Version bump
This commit is contained in:
commit
f83eaad496
@ -1,3 +1,4 @@
|
||||
app/assets/javascripts/discourse-loader.js
|
||||
app/assets/javascripts/env.js
|
||||
app/assets/javascripts/main_include_admin.js
|
||||
app/assets/javascripts/vendor.js
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
{
|
||||
"extends": "eslint-config-discourse",
|
||||
"rules": {
|
||||
"discourse-ember/global-ember": 2,
|
||||
"no-duplicate-imports": 2,
|
||||
"sort-imports": 2
|
||||
"discourse-ember/global-ember": 2
|
||||
},
|
||||
"globals": {
|
||||
"moduleFor": "off",
|
||||
@ -14,6 +12,6 @@
|
||||
"currentURL": "off",
|
||||
"invisible": "off",
|
||||
"visible": "off",
|
||||
"count": "off",
|
||||
"count": "off"
|
||||
}
|
||||
}
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -65,7 +65,7 @@ jobs:
|
||||
if: env.BUILD_TYPE != 'LINT'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -yqq install postgresql-client libpq-dev jpegoptim optipng jhead
|
||||
sudo apt-get -yqq install postgresql-client libpq-dev jpegoptim optipng jhead pngcrush pngquant
|
||||
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/master/image/base/install-pngquant | sudo sh
|
||||
|
||||
- name: Update imagemagick
|
||||
|
||||
@ -6,6 +6,7 @@ config/locales/**/*.yml
|
||||
!config/locales/**/*.en*.yml
|
||||
script/import_scripts/**/*.yml
|
||||
|
||||
app/assets/javascripts/discourse-loader.js
|
||||
app/assets/javascripts/env.js
|
||||
app/assets/javascripts/main_include_admin.js
|
||||
app/assets/javascripts/vendor.js
|
||||
|
||||
1
Gemfile
1
Gemfile
@ -167,6 +167,7 @@ group :test, :development do
|
||||
gem 'parallel_tests'
|
||||
|
||||
gem 'rswag-specs'
|
||||
gem 'json_schemer'
|
||||
end
|
||||
|
||||
group :development do
|
||||
|
||||
42
Gemfile.lock
42
Gemfile.lock
@ -43,7 +43,7 @@ GEM
|
||||
annotate (3.1.1)
|
||||
activerecord (>= 3.2, < 7.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.1)
|
||||
ast (2.4.2)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.390.0)
|
||||
aws-sdk-core (3.109.2)
|
||||
@ -72,10 +72,10 @@ GEM
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (1.0.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.5.1)
|
||||
bootsnap (1.6.0)
|
||||
msgpack (~> 1.0)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.2)
|
||||
bullet (6.1.3)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (11.1.3)
|
||||
@ -93,7 +93,7 @@ GEM
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
css_parser (1.7.1)
|
||||
css_parser (1.8.0)
|
||||
addressable
|
||||
debug_inspector (1.0.0)
|
||||
diff-lcs (1.4.4)
|
||||
@ -114,6 +114,8 @@ GEM
|
||||
in_threads (~> 1.3)
|
||||
progress (~> 3.0, >= 3.0.1)
|
||||
docile (1.3.5)
|
||||
ecma-re-validator (0.3.0)
|
||||
regexp_parser (~> 2.0)
|
||||
email_reply_trimmer (0.1.13)
|
||||
ember-data-source (3.0.2)
|
||||
ember-source (>= 2, < 3.0)
|
||||
@ -141,6 +143,7 @@ GEM
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
guess_html_encoding (0.0.11)
|
||||
hana (1.3.7)
|
||||
hashdiff (1.0.1)
|
||||
hashie (4.1.0)
|
||||
highline (2.0.3)
|
||||
@ -159,9 +162,15 @@ GEM
|
||||
json (2.5.1)
|
||||
json-schema (2.8.1)
|
||||
addressable (>= 2.4)
|
||||
json_schemer (0.2.17)
|
||||
ecma-re-validator (~> 0.3)
|
||||
hana (~> 1.3)
|
||||
regexp_parser (~> 2.0)
|
||||
uri_template (~> 0.7)
|
||||
jwt (2.2.2)
|
||||
kgio (2.11.3)
|
||||
libv8 (8.4.255.0)
|
||||
libv8 (8.4.255.0-universal-darwin-20)
|
||||
libv8 (8.4.255.0-x86_64-darwin-18)
|
||||
libv8 (8.4.255.0-x86_64-darwin-19)
|
||||
libv8 (8.4.255.0-x86_64-darwin-20)
|
||||
@ -177,7 +186,7 @@ GEM
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.26.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (2.9.4)
|
||||
logster (2.9.5)
|
||||
loofah (2.9.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
@ -197,13 +206,13 @@ GEM
|
||||
mini_scheduler (0.13.0)
|
||||
sidekiq (>= 4.2.3)
|
||||
mini_sql (1.0.1)
|
||||
mini_suffix (0.3.0)
|
||||
mini_suffix (0.3.2)
|
||||
ffi (~> 1.9)
|
||||
minitest (5.14.3)
|
||||
mocha (1.12.0)
|
||||
mock_redis (0.27.3)
|
||||
ruby2_keywords
|
||||
msgpack (1.3.3)
|
||||
msgpack (1.4.1)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
@ -212,6 +221,8 @@ GEM
|
||||
nokogiri (1.11.1)
|
||||
mini_portile2 (~> 2.5.0)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.11.1-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.11.1-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.11.1-x86_64-linux)
|
||||
@ -225,7 +236,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.11.0)
|
||||
oj (3.11.1)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
@ -273,7 +284,7 @@ GEM
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.6)
|
||||
puma (5.1.1)
|
||||
puma (5.2.0)
|
||||
nio4r (~> 2.0)
|
||||
r2 (0.2.7)
|
||||
racc (1.5.2)
|
||||
@ -364,7 +375,7 @@ GEM
|
||||
rubocop-ast (>= 1.2.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.4.0)
|
||||
rubocop-ast (1.4.1)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-discourse (2.4.1)
|
||||
rubocop (>= 1.1.0)
|
||||
@ -395,9 +406,9 @@ GEM
|
||||
seed-fu (2.3.9)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
shoulda-matchers (4.5.0)
|
||||
shoulda-matchers (4.5.1)
|
||||
activesupport (>= 4.2.0)
|
||||
sidekiq (6.1.2)
|
||||
sidekiq (6.1.3)
|
||||
connection_pool (>= 2.2.2)
|
||||
rack (~> 2.0)
|
||||
redis (>= 4.2.0)
|
||||
@ -416,7 +427,7 @@ GEM
|
||||
sprockets (>= 3.0.0)
|
||||
sshkey (2.0.0)
|
||||
stackprof (0.2.16)
|
||||
test-prof (0.12.2)
|
||||
test-prof (1.0.0)
|
||||
thor (1.1.0)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
@ -432,6 +443,7 @@ GEM
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.13.2)
|
||||
uri_template (0.7.0)
|
||||
webmock (3.11.1)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
@ -444,6 +456,7 @@ GEM
|
||||
zeitwerk (2.4.2)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin-20
|
||||
ruby
|
||||
x86_64-darwin-18
|
||||
x86_64-darwin-19
|
||||
@ -494,6 +507,7 @@ DEPENDENCIES
|
||||
htmlentities
|
||||
http_accept_language
|
||||
json
|
||||
json_schemer
|
||||
listen
|
||||
lograge
|
||||
logstash-event
|
||||
@ -575,4 +589,4 @@ DEPENDENCIES
|
||||
yaml-lint
|
||||
|
||||
BUNDLED WITH
|
||||
2.2.3
|
||||
2.2.6
|
||||
|
||||
@ -10,6 +10,7 @@ export default Component.extend({
|
||||
_editor: null,
|
||||
_skipContentChangeEvent: null,
|
||||
disabled: false,
|
||||
htmlPlaceholder: false,
|
||||
|
||||
@observes("editorId")
|
||||
editorIdChanged() {
|
||||
@ -86,6 +87,10 @@ export default Component.extend({
|
||||
loadedAce.config.set("loadWorkerFromBlob", false);
|
||||
loadedAce.config.set("workerPath", getURL("/javascripts/ace")); // Do not use CDN for workers
|
||||
|
||||
if (this.htmlPlaceholder) {
|
||||
this._overridePlaceholder(loadedAce);
|
||||
}
|
||||
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -131,4 +136,32 @@ export default Component.extend({
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
_overridePlaceholder(loadedAce) {
|
||||
const originalPlaceholderSetter =
|
||||
loadedAce.config.$defaultOptions.editor.placeholder.set;
|
||||
|
||||
loadedAce.config.$defaultOptions.editor.placeholder.set = function () {
|
||||
if (!this.$updatePlaceholder) {
|
||||
const originalRendererOn = this.renderer.on;
|
||||
this.renderer.on = function () {};
|
||||
originalPlaceholderSetter.call(this, ...arguments);
|
||||
this.renderer.on = originalRendererOn;
|
||||
|
||||
const originalUpdatePlaceholder = this.$updatePlaceholder;
|
||||
|
||||
this.$updatePlaceholder = function () {
|
||||
originalUpdatePlaceholder.call(this, ...arguments);
|
||||
|
||||
if (this.renderer.placeholderNode) {
|
||||
this.renderer.placeholderNode.innerHTML = this.$placeholder || "";
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.on("input", this.$updatePlaceholder);
|
||||
}
|
||||
|
||||
this.$updatePlaceholder();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -10,7 +10,7 @@ export default Component.extend({
|
||||
const model = this.model;
|
||||
const rawData = this.get("model.data");
|
||||
|
||||
var data = {
|
||||
let data = {
|
||||
labels: rawData.map((r) => r.x),
|
||||
datasets: [
|
||||
{
|
||||
|
||||
@ -2,6 +2,7 @@ import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { fmt } from "discourse/lib/computed";
|
||||
import { isDocumentRTL } from "discourse/lib/text-direction";
|
||||
import { next } from "@ember/runloop";
|
||||
|
||||
export default Component.extend({
|
||||
@ -43,9 +44,17 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("currentTargetName", "fieldName")
|
||||
placeholder(targetName, fieldName) {
|
||||
return fieldName && fieldName === "color_definitions"
|
||||
? I18n.t("admin.customize.theme.color_definitions.placeholder")
|
||||
: "";
|
||||
if (fieldName && fieldName === "color_definitions") {
|
||||
const example =
|
||||
":root {\n" +
|
||||
" --mytheme-tertiary-or-quaternary: #{dark-light-choose($tertiary, $quaternary)};\n" +
|
||||
"}";
|
||||
|
||||
return I18n.t("admin.customize.theme.color_definitions.placeholder", {
|
||||
example: isDocumentRTL() ? `<div dir="ltr">${example}</div>` : example,
|
||||
});
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
@discourseComputed("fieldName", "currentTargetName", "theme")
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default Component.extend({
|
||||
newFeatures: null,
|
||||
releaseNotesLink: null,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
ajax("/admin/dashboard/new-features.json").then((json) => {
|
||||
this.setProperties({
|
||||
newFeatures: json.new_features,
|
||||
releaseNotesLink: json.release_notes_link,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
dismissNewFeatures() {
|
||||
ajax("/admin/dashboard/mark-new-features-as-seen.json", {
|
||||
type: "PUT",
|
||||
}).then(() => this.set("newFeatures", null));
|
||||
},
|
||||
});
|
||||
@ -94,9 +94,9 @@ export default Component.extend({
|
||||
_splitValues(values, delimiter) {
|
||||
if (values && values.length) {
|
||||
const keys = ["key", "secret"];
|
||||
var res = [];
|
||||
let res = [];
|
||||
values.split(delimiter).forEach(function (str) {
|
||||
var object = {};
|
||||
let object = {};
|
||||
str.split("|").forEach(function (a, i) {
|
||||
object[keys[i]] = a;
|
||||
});
|
||||
|
||||
@ -110,7 +110,7 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
const data = {};
|
||||
const buffered = this.buffered;
|
||||
fields.forEach(function (field) {
|
||||
var d = buffered.get(field);
|
||||
let d = buffered.get(field);
|
||||
if (boolFields.includes(field)) {
|
||||
d = !!d;
|
||||
}
|
||||
|
||||
@ -53,17 +53,18 @@ export default Controller.extend({
|
||||
|
||||
// Only confirm if we already been saved
|
||||
if (f.get("id")) {
|
||||
bootbox.confirm(I18n.t("admin.user_fields.delete_confirm"), function (
|
||||
result
|
||||
) {
|
||||
if (result) {
|
||||
f.destroyRecord()
|
||||
.then(function () {
|
||||
model.removeObject(f);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
bootbox.confirm(
|
||||
I18n.t("admin.user_fields.delete_confirm"),
|
||||
function (result) {
|
||||
if (result) {
|
||||
f.destroyRecord()
|
||||
.then(function () {
|
||||
model.removeObject(f);
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
} else {
|
||||
model.removeObject(f);
|
||||
}
|
||||
|
||||
@ -396,7 +396,6 @@ export default Controller.extend(CanCheckEmails, {
|
||||
destroy() {
|
||||
const postCount = this.get("model.post_count");
|
||||
const maxPostCount = this.siteSettings.delete_all_posts_max;
|
||||
const user = this.model;
|
||||
const message = I18n.t("admin.user.delete_confirm");
|
||||
const location = document.location.pathname;
|
||||
|
||||
@ -422,13 +421,9 @@ export default Controller.extend(CanCheckEmails, {
|
||||
}
|
||||
} else {
|
||||
bootbox.alert(I18n.t("admin.user.delete_failed"));
|
||||
if (data.user) {
|
||||
user.setProperties(data.user);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
AdminUser.find(user.get("id")).then((u) => user.setProperties(u));
|
||||
bootbox.alert(I18n.t("admin.user.delete_failed"));
|
||||
});
|
||||
};
|
||||
@ -601,8 +596,10 @@ export default Controller.extend(CanCheckEmails, {
|
||||
I18n.t("admin.user.sso.confirm_delete"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
() => {
|
||||
return this.model.deleteSSORecord();
|
||||
(confirmed) => {
|
||||
if (confirmed) {
|
||||
return this.model.deleteSSORecord();
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
|
||||
registerUnbound("value-at-tl", function (data, params) {
|
||||
var tl = parseInt(params.level, 10);
|
||||
let tl = parseInt(params.level, 10);
|
||||
if (data) {
|
||||
var item = data.find(function (d) {
|
||||
let item = data.find(function (d) {
|
||||
return parseInt(d.x, 10) === tl;
|
||||
});
|
||||
if (item) {
|
||||
|
||||
@ -14,6 +14,7 @@ AdminDashboard.reopenClass({
|
||||
return ajax("/admin/dashboard.json").then((json) => {
|
||||
const model = AdminDashboard.create();
|
||||
model.set("version_check", json.version_check);
|
||||
|
||||
return model;
|
||||
});
|
||||
},
|
||||
|
||||
@ -264,7 +264,17 @@ const AdminUser = User.extend({
|
||||
return ajax(`/admin/users/${this.id}.json`, {
|
||||
type: "DELETE",
|
||||
data: formData,
|
||||
});
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data.deleted && data.user) {
|
||||
this.setProperties(data.user);
|
||||
}
|
||||
|
||||
return data;
|
||||
})
|
||||
.catch(() => {
|
||||
this.find(this.id).then((u) => this.setProperties(u));
|
||||
});
|
||||
},
|
||||
|
||||
merge(formData) {
|
||||
|
||||
@ -14,7 +14,7 @@ export default DiscourseRoute.extend({
|
||||
Badge.findAll().then(function (badges) {
|
||||
controller.set("badges", badges);
|
||||
if (badges.length > 0) {
|
||||
var grantableBadges = controller.get("grantableBadges");
|
||||
let grantableBadges = controller.get("grantableBadges");
|
||||
if (grantableBadges.length > 0) {
|
||||
controller.set("selectedBadgeId", grantableBadges[0].get("id"));
|
||||
}
|
||||
|
||||
@ -33,8 +33,8 @@ export default Service.extend({
|
||||
return AdminUser.find(userId).then((au) => this.spammerDetails(au));
|
||||
},
|
||||
|
||||
deleteUser(id) {
|
||||
AdminUser.find(id).then((user) => user.destroy({ deletePosts: true }));
|
||||
deleteUser(id, formData) {
|
||||
return AdminUser.find(id).then((user) => user.destroy(formData));
|
||||
},
|
||||
|
||||
spammerDetails(adminUser) {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
{{#if readOnly}}
|
||||
{{input type="text" name="name" value=buffered.name disabled=true}}
|
||||
<p class="help">
|
||||
{{#link-to "adminSiteText.edit" (concat textCustomizationPrefix "name")}}
|
||||
{{#link-to "adminSiteText" (query-params q=(concat textCustomizationPrefix "name"))}}
|
||||
{{i18n "admin.badges.read_only_setting_help"}}
|
||||
{{/link-to}}
|
||||
</p>
|
||||
@ -70,7 +70,7 @@
|
||||
{{#if buffered.system}}
|
||||
{{textarea name="description" value=buffered.description disabled=true}}
|
||||
<p class="help">
|
||||
{{#link-to "adminSiteText.edit" (concat textCustomizationPrefix "description")}}
|
||||
{{#link-to "adminSiteText" (query-params q=(concat textCustomizationPrefix "description"))}}
|
||||
{{i18n "admin.badges.read_only_setting_help"}}
|
||||
{{/link-to}}
|
||||
</p>
|
||||
@ -84,7 +84,7 @@
|
||||
{{#if buffered.system}}
|
||||
{{textarea name="long_description" value=buffered.long_description disabled=true}}
|
||||
<p class="help">
|
||||
{{#link-to "adminSiteText.edit" (concat textCustomizationPrefix "long_description")}}
|
||||
{{#link-to "adminSiteText" (query-params q=(concat textCustomizationPrefix "long_description"))}}
|
||||
{{i18n "admin.badges.read_only_setting_help"}}
|
||||
{{/link-to}}
|
||||
</p>
|
||||
|
||||
@ -87,4 +87,4 @@
|
||||
<pre class="field-error">{{error}}</pre>
|
||||
{{/if}}
|
||||
|
||||
{{ace-editor content=activeSection editorId=editorId mode=activeSectionMode autofocus="true" placeholder=placeholder}}
|
||||
{{ace-editor content=activeSection editorId=editorId mode=activeSectionMode autofocus="true" placeholder=placeholder htmlPlaceholder=true}}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
<div class="admin-new-feature-item">
|
||||
<div class="new-feature-emoji">{{item.emoji}}</div>
|
||||
<div class="new-feature-content">
|
||||
<div class="header">
|
||||
{{#if item.link}}
|
||||
<a href={{item.link}} target="_blank" rel="noopener noreferrer">{{item.title}}</a>
|
||||
{{else}}
|
||||
{{item.title}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="feature-description">{{item.description}}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,21 @@
|
||||
{{#if newFeatures}}
|
||||
<div class="section dashboard-new-features">
|
||||
<div class="section-title">
|
||||
<h2>{{replace-emoji (i18n "admin.dashboard.new_features.title") }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="section-body">
|
||||
{{#each newFeatures as |feature|}}
|
||||
{{dashboard-new-feature-item item=feature}}
|
||||
{{/each}}
|
||||
</div>
|
||||
<div class="section-footer">
|
||||
{{#if releaseNotesLink}}
|
||||
<a rel="noopener noreferrer" target="_blank" href={{releaseNotesLink}} class="btn btn-primary new-features-release-notes">
|
||||
{{i18n "admin.dashboard.new_features.learn_more"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{d-button label="admin.dashboard.new_features.dismiss" class="new-features-dismiss" action=dismissNewFeatures }}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@ -1,3 +1,5 @@
|
||||
{{dashboard-new-features}}
|
||||
|
||||
{{plugin-outlet name="admin-dashboard-top"}}
|
||||
|
||||
{{#if showVersionChecks}}
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
//Copyright (c) 2007-2009, MIT Style License <browser-update.org/LICENSE.txt>
|
||||
|
||||
(function () {
|
||||
var $buo = function () {
|
||||
let $buo = function () {
|
||||
// Sometimes we have to resort to parsing the user agent string. :(
|
||||
if (navigator && navigator.userAgent) {
|
||||
var ua = navigator.userAgent;
|
||||
let ua = navigator.userAgent;
|
||||
|
||||
// we don't ask Googlebot to update their browser
|
||||
if (
|
||||
@ -22,10 +22,10 @@
|
||||
}
|
||||
|
||||
document.getElementsByTagName("body")[0].className += " crawler";
|
||||
var mainElement = document.getElementById("main");
|
||||
var noscriptElements = document.getElementsByTagName("noscript");
|
||||
let mainElement = document.getElementById("main");
|
||||
let noscriptElements = document.getElementsByTagName("noscript");
|
||||
// find the element with the "data-path" attribute set
|
||||
for (var i = 0; i < noscriptElements.length; ++i) {
|
||||
for (let i = 0; i < noscriptElements.length; ++i) {
|
||||
if (noscriptElements[i].getAttribute("data-path")) {
|
||||
// noscriptElements[i].innerHTML contains encoded HTML
|
||||
if (noscriptElements[i].childNodes.length > 0) {
|
||||
@ -36,7 +36,7 @@
|
||||
}
|
||||
|
||||
// retrieve localized browser upgrade text
|
||||
var t = I18n.t("browser_update"); // eslint-disable-line no-undef
|
||||
let t = I18n.t("browser_update"); // eslint-disable-line no-undef
|
||||
if (t.indexOf(".browser_update]") !== -1) {
|
||||
// very old browsers might fail to load even translations
|
||||
t =
|
||||
@ -44,13 +44,13 @@
|
||||
}
|
||||
|
||||
// create the notification div HTML
|
||||
var div = document.createElement("div");
|
||||
let div = document.createElement("div");
|
||||
div.className = "buorg";
|
||||
div.innerHTML = "<div>" + t + "</div>";
|
||||
|
||||
// create the notification div stylesheet
|
||||
var sheet = document.createElement("style");
|
||||
var style =
|
||||
let sheet = document.createElement("style");
|
||||
let style =
|
||||
".buorg {position:absolute; z-index:111111; width:100%; top:0px; left:0px; background:#FDF2AB; text-align:left; font-family: sans-serif; color:#000; font-size: 14px;} .buorg div {padding: 8px;} .buorg a, .buorg a:visited {color:#E25600; text-decoration: underline;} @media print { .buorg { display: none !important; } }";
|
||||
|
||||
// insert the div and stylesheet into the DOM
|
||||
|
||||
@ -14,6 +14,12 @@ export function isTesting() {
|
||||
return Ember.testing || environment === "testing";
|
||||
}
|
||||
|
||||
// Generally means "before we migrated to Ember CLI"
|
||||
let _isLegacy = Ember.VERSION.startsWith("3.12");
|
||||
export function isLegacyEmber() {
|
||||
return _isLegacy;
|
||||
}
|
||||
|
||||
export function isDevelopment() {
|
||||
return environment === "development";
|
||||
}
|
||||
|
||||
@ -32,8 +32,8 @@ AttributeHook.prototype.unhook = function (node, prop, next) {
|
||||
return;
|
||||
}
|
||||
|
||||
var colonPosition = prop.indexOf(":");
|
||||
var localName = colonPosition > -1 ? prop.substr(colonPosition + 1) : prop;
|
||||
let colonPosition = prop.indexOf(":");
|
||||
let localName = colonPosition > -1 ? prop.substr(colonPosition + 1) : prop;
|
||||
node.removeAttributeNS(this.namespace, localName);
|
||||
};
|
||||
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
import { debounce, run } from "@ember/runloop";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
import { debounce, next, run } from "@ember/runloop";
|
||||
import { isLegacyEmber, isTesting } from "discourse-common/config/environment";
|
||||
|
||||
/**
|
||||
Debounce a Javascript function. This means if it's called many times in a time limit it
|
||||
should only be executed once (at the end of the limit counted from the last call made).
|
||||
Original function will be called with the context and arguments from the last call made.
|
||||
**/
|
||||
|
||||
let testingFunc = isLegacyEmber() ? run : next;
|
||||
|
||||
export default function () {
|
||||
if (isTesting()) {
|
||||
return run(...arguments);
|
||||
return testingFunc(...arguments);
|
||||
} else {
|
||||
return debounce(...arguments);
|
||||
}
|
||||
|
||||
@ -15,9 +15,9 @@ export default function getURL(url) {
|
||||
return url;
|
||||
}
|
||||
|
||||
const found = url.indexOf(baseUri);
|
||||
const found = url.startsWith(baseUri);
|
||||
|
||||
if (found >= 0 && found < 3) {
|
||||
if (found) {
|
||||
return url;
|
||||
}
|
||||
if (url[0] !== "/") {
|
||||
|
||||
@ -22,7 +22,7 @@ const _helpers = {};
|
||||
|
||||
function rawGet(ctx, property, options) {
|
||||
if (options.types && options.data.view) {
|
||||
var view = options.data.view;
|
||||
let view = options.data.view;
|
||||
return view.getStream
|
||||
? view.getStream(property).value()
|
||||
: view.getAttr(property);
|
||||
|
||||
@ -47,7 +47,7 @@ export function deepEqual(obj1, obj2) {
|
||||
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
|
||||
return false;
|
||||
}
|
||||
for (var prop in obj1) {
|
||||
for (let prop in obj1) {
|
||||
if (!deepEqual(obj1[prop], obj2[prop])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -29,24 +29,22 @@ export function registerRawHelpers(hbs, handlebarsClass) {
|
||||
};
|
||||
|
||||
// #each .. in support (as format is transformed to this)
|
||||
hbs.registerHelper("each", function (
|
||||
localName,
|
||||
inKeyword,
|
||||
contextName,
|
||||
options
|
||||
) {
|
||||
if (typeof contextName === "undefined") {
|
||||
return;
|
||||
hbs.registerHelper(
|
||||
"each",
|
||||
function (localName, inKeyword, contextName, options) {
|
||||
if (typeof contextName === "undefined") {
|
||||
return;
|
||||
}
|
||||
let list = get(this, contextName);
|
||||
let output = [];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let innerContext = {};
|
||||
innerContext[localName] = list[i];
|
||||
output.push(options.fn(innerContext));
|
||||
}
|
||||
return output.join("");
|
||||
}
|
||||
var list = get(this, contextName);
|
||||
var output = [];
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
let innerContext = {};
|
||||
innerContext[localName] = list[i];
|
||||
output.push(options.fn(innerContext));
|
||||
}
|
||||
return output.join("");
|
||||
});
|
||||
);
|
||||
|
||||
function stringCompatHelper(fn) {
|
||||
const old = hbs.helpers[fn];
|
||||
|
||||
@ -6,7 +6,7 @@ import Handlebars from "handlebars";
|
||||
const RawHandlebars = Handlebars.create();
|
||||
|
||||
function buildPath(blk, args) {
|
||||
var result = {
|
||||
let result = {
|
||||
type: "PathExpression",
|
||||
data: false,
|
||||
depth: blk.path.depth,
|
||||
@ -22,7 +22,7 @@ function buildPath(blk, args) {
|
||||
}
|
||||
|
||||
function replaceGet(ast) {
|
||||
var visitor = new Handlebars.Visitor();
|
||||
let visitor = new Handlebars.Visitor();
|
||||
visitor.mutating = true;
|
||||
|
||||
visitor.MustacheStatement = function (mustache) {
|
||||
@ -42,7 +42,7 @@ function replaceGet(ast) {
|
||||
// This allows us to use the same syntax in all templates
|
||||
visitor.BlockStatement = function (block) {
|
||||
if (block.path.original === "each" && block.params.length === 1) {
|
||||
var paramName = block.program.blockParams[0];
|
||||
let paramName = block.program.blockParams[0];
|
||||
block.params = [
|
||||
buildPath(block, { original: paramName }),
|
||||
{ type: "CommentStatement", value: "in" },
|
||||
@ -74,10 +74,10 @@ if (Handlebars.Compiler) {
|
||||
RawHandlebars.JavaScriptCompiler.prototype.namespace = "RawHandlebars";
|
||||
|
||||
RawHandlebars.precompile = function (value, asObject) {
|
||||
var ast = Handlebars.parse(value);
|
||||
let ast = Handlebars.parse(value);
|
||||
replaceGet(ast);
|
||||
|
||||
var options = {
|
||||
let options = {
|
||||
knownHelpers: {
|
||||
get: true,
|
||||
},
|
||||
@ -87,7 +87,7 @@ if (Handlebars.Compiler) {
|
||||
|
||||
asObject = asObject === undefined ? true : asObject;
|
||||
|
||||
var environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
let environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
return new RawHandlebars.JavaScriptCompiler().compile(
|
||||
environment,
|
||||
options,
|
||||
@ -97,20 +97,20 @@ if (Handlebars.Compiler) {
|
||||
};
|
||||
|
||||
RawHandlebars.compile = function (string) {
|
||||
var ast = Handlebars.parse(string);
|
||||
let ast = Handlebars.parse(string);
|
||||
replaceGet(ast);
|
||||
|
||||
// this forces us to rewrite helpers
|
||||
var options = { data: true, stringParams: true };
|
||||
var environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
var templateSpec = new RawHandlebars.JavaScriptCompiler().compile(
|
||||
let options = { data: true, stringParams: true };
|
||||
let environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
let templateSpec = new RawHandlebars.JavaScriptCompiler().compile(
|
||||
environment,
|
||||
options,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
var t = RawHandlebars.template(templateSpec);
|
||||
let t = RawHandlebars.template(templateSpec);
|
||||
t.isMethod = false;
|
||||
|
||||
return t;
|
||||
|
||||
@ -111,7 +111,7 @@ export function buildResolver(baseName) {
|
||||
);
|
||||
});
|
||||
|
||||
var module;
|
||||
let module;
|
||||
if (moduleName) {
|
||||
module = requirejs(moduleName, null, null, true /* force sync */);
|
||||
if (module && module["default"]) {
|
||||
@ -200,7 +200,7 @@ export function buildResolver(baseName) {
|
||||
|
||||
findPluginMobileTemplate(parsedName) {
|
||||
if (_options.mobileView) {
|
||||
var pluginParsedName = this.parseName(
|
||||
let pluginParsedName = this.parseName(
|
||||
parsedName.fullName.replace(
|
||||
"template:",
|
||||
"template:javascripts/mobile/"
|
||||
@ -212,7 +212,7 @@ export function buildResolver(baseName) {
|
||||
|
||||
findMobileTemplate(parsedName) {
|
||||
if (_options.mobileView) {
|
||||
var mobileParsedName = this.parseName(
|
||||
let mobileParsedName = this.parseName(
|
||||
parsedName.fullName.replace("template:", "template:mobile/")
|
||||
);
|
||||
return this.findTemplate(mobileParsedName);
|
||||
@ -241,15 +241,15 @@ export function buildResolver(baseName) {
|
||||
},
|
||||
|
||||
findUnderscoredTemplate(parsedName) {
|
||||
var decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
var underscored = decamelized.replace(/\-/g, "_");
|
||||
let decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
let underscored = decamelized.replace(/\-/g, "_");
|
||||
return Ember.TEMPLATES[underscored];
|
||||
},
|
||||
|
||||
// Try to find a template within a special admin namespace, e.g. adminEmail => admin/templates/email
|
||||
// (similar to how discourse lays out templates)
|
||||
findAdminTemplate(parsedName) {
|
||||
var decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
let decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
if (decamelized.indexOf("components") === 0) {
|
||||
let comPath = `admin/templates/${decamelized}`;
|
||||
const compTemplate =
|
||||
|
||||
@ -12,7 +12,7 @@ export default function decoratorAlias(fn, errorMessage) {
|
||||
configurable: desc.configurable,
|
||||
writable: desc.writable,
|
||||
initializer: function () {
|
||||
var value = extractValue(desc);
|
||||
let value = extractValue(desc);
|
||||
return fn.apply(null, params.concat(value));
|
||||
},
|
||||
};
|
||||
|
||||
@ -51,7 +51,7 @@ export function readOnly(target, name, desc) {
|
||||
enumerable: desc.enumerable,
|
||||
configurable: desc.configurable,
|
||||
initializer: function () {
|
||||
var value = extractValue(desc);
|
||||
let value = extractValue(desc);
|
||||
return value.readOnly();
|
||||
},
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ export default function handleDescriptor(target, key, desc, params = []) {
|
||||
let computedDescriptor;
|
||||
|
||||
if (desc.writable) {
|
||||
var val = extractValue(desc);
|
||||
let val = extractValue(desc);
|
||||
if (typeof val === "object") {
|
||||
let value = {};
|
||||
if (val.get) {
|
||||
|
||||
@ -6,7 +6,7 @@ const Handlebars = require("handlebars");
|
||||
const RawHandlebars = Handlebars.create();
|
||||
|
||||
function buildPath(blk, args) {
|
||||
var result = {
|
||||
let result = {
|
||||
type: "PathExpression",
|
||||
data: false,
|
||||
depth: blk.path.depth,
|
||||
@ -22,7 +22,7 @@ function buildPath(blk, args) {
|
||||
}
|
||||
|
||||
function replaceGet(ast) {
|
||||
var visitor = new Handlebars.Visitor();
|
||||
let visitor = new Handlebars.Visitor();
|
||||
visitor.mutating = true;
|
||||
|
||||
visitor.MustacheStatement = function (mustache) {
|
||||
@ -42,7 +42,7 @@ function replaceGet(ast) {
|
||||
// This allows us to use the same syntax in all templates
|
||||
visitor.BlockStatement = function (block) {
|
||||
if (block.path.original === "each" && block.params.length === 1) {
|
||||
var paramName = block.program.blockParams[0];
|
||||
let paramName = block.program.blockParams[0];
|
||||
block.params = [
|
||||
buildPath(block, { original: paramName }),
|
||||
{ type: "CommentStatement", value: "in" },
|
||||
@ -71,10 +71,10 @@ RawHandlebars.JavaScriptCompiler.prototype.compiler =
|
||||
RawHandlebars.JavaScriptCompiler.prototype.namespace = "RawHandlebars";
|
||||
|
||||
RawHandlebars.precompile = function (value, asObject) {
|
||||
var ast = Handlebars.parse(value);
|
||||
let ast = Handlebars.parse(value);
|
||||
replaceGet(ast);
|
||||
|
||||
var options = {
|
||||
let options = {
|
||||
knownHelpers: {
|
||||
get: true,
|
||||
},
|
||||
@ -84,7 +84,7 @@ RawHandlebars.precompile = function (value, asObject) {
|
||||
|
||||
asObject = asObject === undefined ? true : asObject;
|
||||
|
||||
var environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
let environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
return new RawHandlebars.JavaScriptCompiler().compile(
|
||||
environment,
|
||||
options,
|
||||
@ -94,20 +94,20 @@ RawHandlebars.precompile = function (value, asObject) {
|
||||
};
|
||||
|
||||
RawHandlebars.compile = function (string) {
|
||||
var ast = Handlebars.parse(string);
|
||||
let ast = Handlebars.parse(string);
|
||||
replaceGet(ast);
|
||||
|
||||
// this forces us to rewrite helpers
|
||||
var options = { data: true, stringParams: true };
|
||||
var environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
var templateSpec = new RawHandlebars.JavaScriptCompiler().compile(
|
||||
let options = { data: true, stringParams: true };
|
||||
let environment = new RawHandlebars.Compiler().compile(ast, options);
|
||||
let templateSpec = new RawHandlebars.JavaScriptCompiler().compile(
|
||||
environment,
|
||||
options,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
var t = RawHandlebars.template(templateSpec);
|
||||
let t = RawHandlebars.template(templateSpec);
|
||||
t.isMethod = false;
|
||||
|
||||
return t;
|
||||
|
||||
@ -26,7 +26,8 @@ const Discourse = Application.extend({
|
||||
|
||||
const init = module.default;
|
||||
const oldInitialize = init.initialize;
|
||||
init.initialize = () => oldInitialize.call(init, this.__container__, this);
|
||||
init.initialize = (app) => oldInitialize.call(init, app.__container__, app);
|
||||
|
||||
return init;
|
||||
},
|
||||
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import Component from "@ember/component";
|
||||
import { or } from "@ember/object/computed";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: "activation-controls",
|
||||
canEditEmail: or(
|
||||
"siteSettings.enable_local_logins",
|
||||
"siteSettings.email_editable"
|
||||
),
|
||||
});
|
||||
|
||||
@ -5,12 +5,12 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
|
||||
function b64EncodeUnicode(str) {
|
||||
return btoa(
|
||||
encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function toSolidBytes(
|
||||
match,
|
||||
p1
|
||||
) {
|
||||
return String.fromCharCode("0x" + p1);
|
||||
})
|
||||
encodeURIComponent(str).replace(
|
||||
/%([0-9A-F]{2})/g,
|
||||
function toSolidBytes(match, p1) {
|
||||
return String.fromCharCode("0x" + p1);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ export default Component.extend({
|
||||
|
||||
@discourseComputed("topicList.loaded")
|
||||
loaded() {
|
||||
var topicList = this.topicList;
|
||||
let topicList = this.topicList;
|
||||
if (topicList) {
|
||||
return topicList.get("loaded");
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { action } from "@ember/object";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import { or } from "@ember/object/computed";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.loadLocalDates();
|
||||
},
|
||||
|
||||
get postLocalDateFormatted() {
|
||||
return this.postLocalDate().format(I18n.t("dates.long_no_year"));
|
||||
},
|
||||
|
||||
showPostLocalDate: or("postDetectedLocalDate", "postDetectedLocalTime"),
|
||||
|
||||
loadLocalDates() {
|
||||
let postEl = document.querySelector(`[data-post-id="${this.postId}"]`);
|
||||
let localDateEl = null;
|
||||
if (postEl) {
|
||||
localDateEl = postEl.querySelector(".discourse-local-date");
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
postDetectedLocalDate: localDateEl ? localDateEl.dataset.date : null,
|
||||
postDetectedLocalTime: localDateEl ? localDateEl.dataset.time : null,
|
||||
postDetectedLocalTimezone: localDateEl
|
||||
? localDateEl.dataset.timezone
|
||||
: null,
|
||||
});
|
||||
},
|
||||
|
||||
postLocalDate() {
|
||||
const bookmarkController = getOwner(this).lookup("controller:bookmark");
|
||||
let parsedPostLocalDate = bookmarkController._parseCustomDateTime(
|
||||
this.postDetectedLocalDate,
|
||||
this.postDetectedLocalTime,
|
||||
this.postDetectedLocalTimezone
|
||||
);
|
||||
|
||||
if (!this.postDetectedLocalTime) {
|
||||
return bookmarkController.startOfDay(parsedPostLocalDate);
|
||||
}
|
||||
|
||||
return parsedPostLocalDate;
|
||||
},
|
||||
|
||||
@action
|
||||
setReminder() {
|
||||
return this.onChange(this.postLocalDate());
|
||||
},
|
||||
});
|
||||
@ -536,10 +536,10 @@ export default Component.extend({
|
||||
|
||||
_warnMentionedGroups($preview) {
|
||||
schedule("afterRender", () => {
|
||||
var found = this.warnedGroupMentions || [];
|
||||
let found = this.warnedGroupMentions || [];
|
||||
$preview.find(".mention-group.notify").each((idx, e) => {
|
||||
const $e = $(e);
|
||||
var name = $e.data("name");
|
||||
let name = $e.data("name");
|
||||
if (found.indexOf(name) === -1) {
|
||||
this.groupsMentioned([
|
||||
{
|
||||
|
||||
@ -184,7 +184,7 @@ class Toolbar {
|
||||
if (button.shortcut) {
|
||||
const mac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
||||
const mod = mac ? "Meta" : "Ctrl";
|
||||
var shortcutTitle = `${mod}+${button.shortcut}`;
|
||||
let shortcutTitle = `${mod}+${button.shortcut}`;
|
||||
|
||||
// Mac users are used to glyphs for shortcut keys
|
||||
if (mac) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { computed } from "@ember/object";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import afterTransition from "discourse/lib/after-transition";
|
||||
@ -12,10 +13,16 @@ export default Component.extend({
|
||||
"modalStyle",
|
||||
"hasPanels",
|
||||
],
|
||||
attributeBindings: ["data-keyboard", "aria-modal"],
|
||||
attributeBindings: [
|
||||
"data-keyboard",
|
||||
"aria-modal",
|
||||
"role",
|
||||
"ariaLabelledby:aria-labelledby",
|
||||
],
|
||||
dismissable: true,
|
||||
title: null,
|
||||
subtitle: null,
|
||||
role: "dialog",
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
@ -33,6 +40,10 @@ export default Component.extend({
|
||||
// Inform screenreaders of the modal
|
||||
"aria-modal": "true",
|
||||
|
||||
ariaLabelledby: computed("title", function () {
|
||||
return this.title ? "discourse-modal-title" : null;
|
||||
}),
|
||||
|
||||
@on("didInsertElement")
|
||||
setUp() {
|
||||
$("html").on("keyup.discourse-modal", (e) => {
|
||||
|
||||
@ -28,7 +28,7 @@ export default Component.extend({
|
||||
@observes("lastShownAt")
|
||||
bounce() {
|
||||
if (this.lastShownAt) {
|
||||
var $elem = $(this.element);
|
||||
let $elem = $(this.element);
|
||||
if (!this.animateAttribute) {
|
||||
this.animateAttribute = $elem.css("left") === "auto" ? "right" : "left";
|
||||
}
|
||||
@ -51,7 +51,7 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
bounceLeft($elem) {
|
||||
for (var i = 0; i < 5; i++) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
$elem
|
||||
.animate({ left: "+=" + this.bouncePixels }, this.bounceDelay)
|
||||
.animate({ left: "-=" + this.bouncePixels }, this.bounceDelay);
|
||||
@ -59,7 +59,7 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
bounceRight($elem) {
|
||||
for (var i = 0; i < 5; i++) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
$elem
|
||||
.animate({ right: "-=" + this.bouncePixels }, this.bounceDelay)
|
||||
.animate({ right: "+=" + this.bouncePixels }, this.bounceDelay);
|
||||
|
||||
@ -56,7 +56,7 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
_showUrl($target, url) {
|
||||
const $currentTargetOffset = $target.offset();
|
||||
const currentTargetOffset = $target.offset();
|
||||
const $this = $(this.element);
|
||||
|
||||
if (isEmpty(url)) {
|
||||
@ -69,7 +69,7 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
const shareLinkWidth = $this.width();
|
||||
let x = $currentTargetOffset.left - shareLinkWidth / 2;
|
||||
let x = currentTargetOffset.left - shareLinkWidth / 2;
|
||||
if (x < 25) {
|
||||
x = 25;
|
||||
}
|
||||
@ -78,15 +78,18 @@ export default Component.extend({
|
||||
}
|
||||
|
||||
const header = $(".d-header");
|
||||
let y = $currentTargetOffset.top - ($this.height() + 20);
|
||||
let y = currentTargetOffset.top - ($this.height() + 20);
|
||||
if (y < header.offset().top + header.height()) {
|
||||
y = $currentTargetOffset.top + 10;
|
||||
y = currentTargetOffset.top + 10;
|
||||
}
|
||||
|
||||
$this.css({ top: "" + y + "px" });
|
||||
this.element.style.top = `${y}px`;
|
||||
|
||||
if (!this.site.mobileView) {
|
||||
$this.css({ left: "" + x + "px" });
|
||||
this.element.style.left = `${x}px`;
|
||||
if (document.documentElement.classList.contains("rtl")) {
|
||||
this.element.style.right = "unset";
|
||||
}
|
||||
}
|
||||
this.set("link", url);
|
||||
this.set("visible", true);
|
||||
|
||||
@ -107,6 +107,8 @@ export default Component.extend(bufferedProperty("model"), {
|
||||
this.allGroups.forEach((group) => {
|
||||
if (groupIds.includes(group.id)) {
|
||||
updatedPermissions[group.name] = PermissionType.FULL;
|
||||
} else {
|
||||
delete updatedPermissions[group.name];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,13 +1,26 @@
|
||||
import { reads } from "@ember/object/computed";
|
||||
import Component from "@ember/component";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
|
||||
export default Component.extend({
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.set("elementId", `tap_tile_${this.tileId}`);
|
||||
},
|
||||
|
||||
classNames: ["tap-tile"],
|
||||
|
||||
classNameBindings: ["active"],
|
||||
|
||||
attributeBindings: ["role", "ariaPressed", "tabIndex"],
|
||||
|
||||
role: "button",
|
||||
|
||||
tabIndex: 0,
|
||||
|
||||
ariaPressed: reads("active"),
|
||||
|
||||
click() {
|
||||
this.onChange(this.tileId);
|
||||
},
|
||||
|
||||
@ -226,12 +226,6 @@ export default Component.extend({
|
||||
return this.unhandledRowClick(e, topic);
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleBookmark() {
|
||||
this.topic.toggleBookmark().finally(() => this.renderTopicListItem());
|
||||
},
|
||||
},
|
||||
|
||||
unhandledRowClick() {},
|
||||
|
||||
navigateToTopic,
|
||||
|
||||
@ -163,9 +163,9 @@ export default Component.extend(LoadMore, {
|
||||
},
|
||||
|
||||
click(e) {
|
||||
var self = this;
|
||||
var onClick = function (sel, callback) {
|
||||
var target = $(e.target).closest(sel);
|
||||
let self = this;
|
||||
let onClick = function (sel, callback) {
|
||||
let target = $(e.target).closest(sel);
|
||||
|
||||
if (target.length === 1) {
|
||||
callback.apply(self, [target]);
|
||||
|
||||
@ -12,7 +12,7 @@ export default Component.extend({
|
||||
@discourseComputed("badge", "user")
|
||||
badgeUrl() {
|
||||
// NOTE: I tried using a link-to helper here but the queryParams mean it fails
|
||||
var username = this.get("user.username_lower") || "";
|
||||
let username = this.get("user.username_lower") || "";
|
||||
username = username !== "" ? "?username=" + username : "";
|
||||
return this.get("badge.url") + username;
|
||||
},
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { REMINDER_TYPES, formattedReminderTime } from "discourse/lib/bookmark";
|
||||
import { and, or } from "@ember/object/computed";
|
||||
import { isEmpty, isPresent } from "@ember/utils";
|
||||
import { next, schedule } from "@ember/runloop";
|
||||
import { AUTO_DELETE_PREFERENCES } from "discourse/models/bookmark";
|
||||
@ -10,6 +9,7 @@ import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { Promise } from "rsvp";
|
||||
import { action } from "@ember/object";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { and } from "@ember/object/computed";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
@ -62,9 +62,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
customReminderTime: null,
|
||||
lastCustomReminderDate: null,
|
||||
lastCustomReminderTime: null,
|
||||
postDetectedLocalDate: null,
|
||||
postDetectedLocalTime: null,
|
||||
postDetectedLocalTimezone: null,
|
||||
postLocalDate: null,
|
||||
mouseTrap: null,
|
||||
userTimezone: null,
|
||||
showOptions: false,
|
||||
@ -95,6 +93,8 @@ export default Controller.extend(ModalFunctionality, {
|
||||
this._initializeExistingBookmarkData();
|
||||
}
|
||||
|
||||
this.loadLocalDates();
|
||||
|
||||
schedule("afterRender", () => {
|
||||
if (this.site.isMobileDevice) {
|
||||
document.getElementById("bookmark-name").blur();
|
||||
@ -240,11 +240,6 @@ export default Controller.extend(ModalFunctionality, {
|
||||
|
||||
showLastCustom: and("lastCustomReminderTime", "lastCustomReminderDate"),
|
||||
|
||||
showPostLocalDate: or(
|
||||
"model.postDetectedLocalDate",
|
||||
"model.postDetectedLocalTime"
|
||||
),
|
||||
|
||||
get showLaterToday() {
|
||||
let later = this.laterToday();
|
||||
return (
|
||||
@ -302,8 +297,22 @@ export default Controller.extend(ModalFunctionality, {
|
||||
return this.nextMonth().format(I18n.t("dates.long_no_year"));
|
||||
},
|
||||
|
||||
get postLocalDateFormatted() {
|
||||
return this.postLocalDate().format(I18n.t("dates.long_no_year"));
|
||||
loadLocalDates() {
|
||||
let postEl = document.querySelector(
|
||||
`[data-post-id="${this.model.postId}"]`
|
||||
);
|
||||
let localDateEl = null;
|
||||
if (postEl) {
|
||||
localDateEl = postEl.querySelector(".discourse-local-date");
|
||||
}
|
||||
|
||||
if (localDateEl) {
|
||||
this.setProperties({
|
||||
postDetectedLocalDate: localDateEl.dataset.date,
|
||||
postDetectedLocalTime: localDateEl.dataset.time,
|
||||
postDetectedLocalTimezone: localDateEl.dataset.timezone,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@discourseComputed("userTimezone")
|
||||
@ -442,7 +451,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
case REMINDER_TYPES.LAST_CUSTOM:
|
||||
return this.parsedLastCustomReminderDatetime;
|
||||
case REMINDER_TYPES.POST_LOCAL_DATE:
|
||||
return this.postLocalDate();
|
||||
return this.postLocalDate;
|
||||
}
|
||||
},
|
||||
|
||||
@ -454,20 +463,6 @@ export default Controller.extend(ModalFunctionality, {
|
||||
return this.startOfDay(this.now().add(1, "month"));
|
||||
},
|
||||
|
||||
postLocalDate() {
|
||||
let parsedPostLocalDate = this._parseCustomDateTime(
|
||||
this.model.postDetectedLocalDate,
|
||||
this.model.postDetectedLocalTime,
|
||||
this.model.postDetectedLocalTimezone
|
||||
);
|
||||
|
||||
if (!this.model.postDetectedLocalTime) {
|
||||
return this.startOfDay(parsedPostLocalDate);
|
||||
}
|
||||
|
||||
return parsedPostLocalDate;
|
||||
},
|
||||
|
||||
tomorrow() {
|
||||
return this.startOfDay(this.now().add(1, "day"));
|
||||
},
|
||||
@ -572,4 +567,13 @@ export default Controller.extend(ModalFunctionality, {
|
||||
return this.saveAndClose();
|
||||
}
|
||||
},
|
||||
|
||||
@action
|
||||
selectPostLocalDate(date) {
|
||||
this.setProperties({
|
||||
selectedReminderType: this.reminderTypes.POST_LOCAL_DATE,
|
||||
postLocalDate: date,
|
||||
});
|
||||
return this.saveAndClose();
|
||||
},
|
||||
});
|
||||
|
||||
@ -727,7 +727,7 @@ export default Controller.extend({
|
||||
}
|
||||
}
|
||||
|
||||
var staged = false;
|
||||
let staged = false;
|
||||
|
||||
// TODO: This should not happen in model
|
||||
const imageSizes = {};
|
||||
|
||||
@ -19,15 +19,6 @@ export default DiscoveryController.extend({
|
||||
|
||||
canEdit: reads("currentUser.staff"),
|
||||
|
||||
@discourseComputed("model.categories.[].featuredTopics.length")
|
||||
latestTopicOnly() {
|
||||
return (
|
||||
this.get("model.categories").find(
|
||||
(c) => c.get("featuredTopics.length") > 1
|
||||
) === undefined
|
||||
);
|
||||
},
|
||||
|
||||
@discourseComputed("model.parentCategory")
|
||||
categoryPageStyle(parentCategory) {
|
||||
let style = this.site.mobileView
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { and, readOnly } from "@ember/object/computed";
|
||||
import discourseComputed, { on } from "discourse-common/utils/decorators";
|
||||
import Category from "discourse/models/category";
|
||||
import Controller from "@ember/controller";
|
||||
@ -7,7 +8,6 @@ import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import PermissionType from "discourse/models/permission-type";
|
||||
import bootbox from "bootbox";
|
||||
import { extractError } from "discourse/lib/ajax-error";
|
||||
import { readOnly } from "@ember/object/computed";
|
||||
import { underscore } from "@ember/string";
|
||||
|
||||
export default Controller.extend({
|
||||
@ -15,11 +15,12 @@ export default Controller.extend({
|
||||
saving: false,
|
||||
deleting: false,
|
||||
panels: null,
|
||||
hiddenTooltip: true,
|
||||
showTooltip: false,
|
||||
createdCategory: false,
|
||||
expandedMenu: false,
|
||||
mobileView: readOnly("site.mobileView"),
|
||||
parentParams: null,
|
||||
showDeleteReason: and("showTooltip", "model.cannot_delete_reason"),
|
||||
|
||||
@on("init")
|
||||
_initPanels() {
|
||||
@ -143,7 +144,7 @@ export default Controller.extend({
|
||||
},
|
||||
|
||||
toggleDeleteTooltip() {
|
||||
this.toggleProperty("hiddenTooltip");
|
||||
this.toggleProperty("showTooltip");
|
||||
},
|
||||
|
||||
goBack() {
|
||||
|
||||
@ -77,9 +77,9 @@ export default Controller.extend({
|
||||
|
||||
@discourseComputed("context", "context_id")
|
||||
searchContextDescription(context, id) {
|
||||
var name = id;
|
||||
let name = id;
|
||||
if (context === "category") {
|
||||
var category = Category.findById(id);
|
||||
let category = Category.findById(id);
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
@ -322,7 +322,7 @@ export default Controller.extend({
|
||||
},
|
||||
|
||||
loadMore() {
|
||||
var page = this.page;
|
||||
let page = this.page;
|
||||
if (
|
||||
this.get("model.grouped_search_result.more_full_page_results") &&
|
||||
!this.loading &&
|
||||
|
||||
@ -142,13 +142,22 @@ export default Controller.extend({
|
||||
destroyGroup() {
|
||||
this.set("destroying", true);
|
||||
|
||||
const model = this.model;
|
||||
let message = I18n.t("admin.groups.delete_confirm");
|
||||
|
||||
if (model.has_messages && model.message_count > 0) {
|
||||
message = I18n.t("admin.groups.delete_with_messages_confirm", {
|
||||
count: model.message_count,
|
||||
});
|
||||
}
|
||||
|
||||
bootbox.confirm(
|
||||
I18n.t("admin.groups.delete_confirm"),
|
||||
message,
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(confirmed) => {
|
||||
if (confirmed) {
|
||||
this.model
|
||||
model
|
||||
.destroy()
|
||||
.then(() => this.transitionToRoute("groups.index"))
|
||||
.catch((error) => {
|
||||
|
||||
@ -17,7 +17,7 @@ import { sanitizeAsync } from "discourse/lib/text";
|
||||
|
||||
function customTagArray(fieldName) {
|
||||
return computed(fieldName, function () {
|
||||
var val = this.get(fieldName);
|
||||
let val = this.get(fieldName);
|
||||
if (!val) {
|
||||
return val;
|
||||
}
|
||||
@ -194,7 +194,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
if (displayingInline) {
|
||||
return this.isEitherRevisionHidden ? "hidden-revision-either" : null;
|
||||
} else {
|
||||
var result = [];
|
||||
let result = [];
|
||||
if (prevHidden) {
|
||||
result.push("hidden-revision-previous");
|
||||
}
|
||||
@ -227,7 +227,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
@discourseComputed("model.category_id_changes")
|
||||
previousCategory(changes) {
|
||||
if (changes) {
|
||||
var category = Category.findById(changes["previous"]);
|
||||
let category = Category.findById(changes["previous"]);
|
||||
return categoryBadgeHTML(category, { allowUncategorized: true });
|
||||
}
|
||||
},
|
||||
@ -235,7 +235,7 @@ export default Controller.extend(ModalFunctionality, {
|
||||
@discourseComputed("model.category_id_changes")
|
||||
currentCategory(changes) {
|
||||
if (changes) {
|
||||
var category = Category.findById(changes["current"]);
|
||||
let category = Category.findById(changes["current"]);
|
||||
return categoryBadgeHTML(category, { allowUncategorized: true });
|
||||
}
|
||||
},
|
||||
|
||||
@ -403,6 +403,8 @@ export default Controller.extend(ModalFunctionality, {
|
||||
skipConfirmation,
|
||||
});
|
||||
|
||||
showModal("createAccount", { modalClass: "create-account" });
|
||||
next(() => {
|
||||
showModal("createAccount", { modalClass: "create-account" });
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@ -62,7 +62,7 @@ export default Controller.extend({
|
||||
|
||||
@discourseComputed()
|
||||
frequencyEstimate() {
|
||||
var estimate = this.get("model.mailing_list_posts_per_day");
|
||||
let estimate = this.get("model.mailing_list_posts_per_day");
|
||||
if (!estimate || estimate < 2) {
|
||||
return I18n.t("user.mailing_list_mode.few_per_day");
|
||||
} else {
|
||||
|
||||
@ -153,7 +153,7 @@ export default Controller.extend({
|
||||
"themeId"
|
||||
)
|
||||
currentSchemeCanBeSelected(userThemes, userColorSchemes, themeId) {
|
||||
if (!userThemes) {
|
||||
if (!userThemes || !themeId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ export default Controller.extend(ModalFunctionality, Evented, {
|
||||
this.categoriesSorting = ["position"];
|
||||
},
|
||||
|
||||
@discourseComputed("site.categories")
|
||||
@discourseComputed("site.categories.[]")
|
||||
categoriesBuffered(categories) {
|
||||
const bufProxy = EmberObjectProxy.extend(BufferedProxy);
|
||||
return categories.map((c) => bufProxy.create({ content: c }));
|
||||
|
||||
@ -72,7 +72,7 @@ export default Controller.extend({
|
||||
}
|
||||
|
||||
const joinedTags = tags.slice(0, displayN).join(", ");
|
||||
var more = Math.max(0, tags.length - displayN);
|
||||
let more = Math.max(0, tags.length - displayN);
|
||||
|
||||
const tagsString =
|
||||
more === 0
|
||||
|
||||
@ -702,9 +702,9 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
if (!this.currentUser) {
|
||||
return bootbox.alert(I18n.t("bookmarks.not_bookmarked"));
|
||||
} else if (post) {
|
||||
return post.toggleBookmark();
|
||||
return this._togglePostBookmark(post);
|
||||
} else {
|
||||
return this.model.toggleBookmark().then((changedIds) => {
|
||||
return this._toggleTopicBookmark(this.model).then((changedIds) => {
|
||||
if (!changedIds) {
|
||||
return;
|
||||
}
|
||||
@ -1167,6 +1167,107 @@ export default Controller.extend(bufferedProperty("model"), {
|
||||
}
|
||||
},
|
||||
|
||||
_togglePostBookmark(post) {
|
||||
return new Promise((resolve) => {
|
||||
let modalController = showModal("bookmark", {
|
||||
model: {
|
||||
postId: post.id,
|
||||
id: post.bookmark_id,
|
||||
reminderAt: post.bookmark_reminder_at,
|
||||
autoDeletePreference: post.bookmark_auto_delete_preference,
|
||||
name: post.bookmark_name,
|
||||
},
|
||||
title: post.bookmark_id
|
||||
? "post.bookmarks.edit"
|
||||
: "post.bookmarks.create",
|
||||
modalClass: "bookmark-with-reminder",
|
||||
});
|
||||
modalController.setProperties({
|
||||
onCloseWithoutSaving: () => {
|
||||
resolve({ closedWithoutSaving: true });
|
||||
post.appEvents.trigger("post-stream:refresh", { id: post.id });
|
||||
},
|
||||
afterSave: (savedData) => {
|
||||
post.createBookmark(savedData);
|
||||
resolve({ closedWithoutSaving: false });
|
||||
},
|
||||
afterDelete: (topicBookmarked) => {
|
||||
post.deleteBookmark(topicBookmarked);
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_toggleTopicBookmark() {
|
||||
if (this.model.bookmarking) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
this.model.set("bookmarking", true);
|
||||
const bookmark = !this.model.bookmarked;
|
||||
let posts = this.model.postStream.posts;
|
||||
|
||||
return this.model.firstPost().then((firstPost) => {
|
||||
const toggleBookmarkOnServer = () => {
|
||||
if (bookmark) {
|
||||
return this._togglePostBookmark(firstPost).then((opts) => {
|
||||
this.model.set("bookmarking", false);
|
||||
if (opts && opts.closedWithoutSaving) {
|
||||
return;
|
||||
}
|
||||
return this.model.afterTopicBookmarked(firstPost);
|
||||
});
|
||||
} else {
|
||||
return this.model
|
||||
.deleteBookmark()
|
||||
.then(() => {
|
||||
this.model.toggleProperty("bookmarked");
|
||||
this.model.set("bookmark_reminder_at", null);
|
||||
let clearedBookmarkProps = {
|
||||
bookmarked: false,
|
||||
bookmark_id: null,
|
||||
bookmark_name: null,
|
||||
bookmark_reminder_at: null,
|
||||
};
|
||||
if (posts) {
|
||||
const updated = [];
|
||||
posts.forEach((post) => {
|
||||
if (post.bookmarked) {
|
||||
post.setProperties(clearedBookmarkProps);
|
||||
updated.push(post.id);
|
||||
}
|
||||
});
|
||||
firstPost.setProperties(clearedBookmarkProps);
|
||||
return updated;
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => this.model.set("bookmarking", false));
|
||||
}
|
||||
};
|
||||
|
||||
const unbookmarkedPosts = [];
|
||||
if (!bookmark && posts) {
|
||||
posts.forEach(
|
||||
(post) => post.bookmarked && unbookmarkedPosts.push(post)
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
if (unbookmarkedPosts.length > 1) {
|
||||
bootbox.confirm(
|
||||
I18n.t("bookmarks.confirm_clear"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(confirmed) =>
|
||||
confirmed ? toggleBookmarkOnServer().then(resolve) : resolve()
|
||||
);
|
||||
} else {
|
||||
toggleBookmarkOnServer().then(resolve);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
togglePinnedState() {
|
||||
this.send("togglePinnedForUser");
|
||||
},
|
||||
|
||||
@ -16,7 +16,7 @@ export default Controller.extend({
|
||||
|
||||
@observes("userActionType", "model.stream.itemsLoaded")
|
||||
_showFooter: function () {
|
||||
var showFooter;
|
||||
let showFooter;
|
||||
if (this.userActionType) {
|
||||
const stat = (this.get("model.stats") || []).find(
|
||||
(s) => s.action_type === this.userActionType
|
||||
|
||||
@ -40,7 +40,7 @@ export default Controller.extend({
|
||||
|
||||
bulkOperation(operation) {
|
||||
const selected = this.selected;
|
||||
var params = { type: operation };
|
||||
let params = { type: operation };
|
||||
if (this.isGroup) {
|
||||
params.group = this.groupFilter;
|
||||
}
|
||||
|
||||
@ -3,7 +3,11 @@ import EmberObject, { computed, set } from "@ember/object";
|
||||
import { alias, and, gt, not, or } from "@ember/object/computed";
|
||||
import CanCheckEmails from "discourse/mixins/can-check-emails";
|
||||
import User from "discourse/models/user";
|
||||
import I18n from "I18n";
|
||||
import bootbox from "bootbox";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import getURL from "discourse-common/lib/get-url";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import optionalService from "discourse/lib/optional-service";
|
||||
import { prioritizeNameInUx } from "discourse/lib/settings";
|
||||
@ -168,7 +172,57 @@ export default Controller.extend(CanCheckEmails, {
|
||||
},
|
||||
|
||||
adminDelete() {
|
||||
this.adminTools.deleteUser(this.get("model.id"));
|
||||
const userId = this.get("model.id");
|
||||
const message = I18n.t("admin.user.delete_confirm");
|
||||
const location = document.location.pathname;
|
||||
|
||||
const performDestroy = (block) => {
|
||||
bootbox.dialog(I18n.t("admin.user.deleting_user"));
|
||||
let formData = { context: location };
|
||||
if (block) {
|
||||
formData["block_email"] = true;
|
||||
formData["block_urls"] = true;
|
||||
formData["block_ip"] = true;
|
||||
}
|
||||
formData["delete_posts"] = true;
|
||||
|
||||
this.adminTools
|
||||
.deleteUser(userId, formData)
|
||||
.then((data) => {
|
||||
if (data.deleted) {
|
||||
document.location = getURL("/admin/users/list/active");
|
||||
} else {
|
||||
bootbox.alert(I18n.t("admin.user.delete_failed"));
|
||||
}
|
||||
})
|
||||
.catch(() => bootbox.alert(I18n.t("admin.user.delete_failed")));
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: I18n.t("composer.cancel"),
|
||||
class: "btn",
|
||||
link: true,
|
||||
},
|
||||
{
|
||||
label:
|
||||
`${iconHTML("exclamation-triangle")} ` +
|
||||
I18n.t("admin.user.delete_and_block"),
|
||||
class: "btn btn-danger",
|
||||
callback: function () {
|
||||
performDestroy(true);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: I18n.t("admin.user.delete_dont_block"),
|
||||
class: "btn btn-primary",
|
||||
callback: function () {
|
||||
performDestroy(false);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
bootbox.dialog(message, buttons, { classes: "delete-user-modal" });
|
||||
},
|
||||
|
||||
updateNotificationLevel(level) {
|
||||
|
||||
@ -16,7 +16,7 @@ export function replaceCategoryLinkRenderer(fn) {
|
||||
}
|
||||
|
||||
function categoryStripe(color, classes) {
|
||||
var style = color ? "style='background-color: #" + color + ";'" : "";
|
||||
let style = color ? "style='background-color: #" + color + ";'" : "";
|
||||
return "<span class='" + classes + "' " + style + "></span>";
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ export function categoryBadgeHTML(category, opts) {
|
||||
}
|
||||
|
||||
export function categoryLinkHTML(category, options) {
|
||||
var categoryOptions = {};
|
||||
let categoryOptions = {};
|
||||
|
||||
// TODO: This is a compatibility layer with the old helper structure.
|
||||
// Can be removed once we migrate to `registerUnbound` fully
|
||||
|
||||
@ -7,7 +7,7 @@ import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
update the dates on a regular interval.
|
||||
**/
|
||||
registerUnbound("format-date", function (val, params) {
|
||||
var leaveAgo,
|
||||
let leaveAgo,
|
||||
format = "medium",
|
||||
title = true;
|
||||
|
||||
@ -22,7 +22,7 @@ registerUnbound("format-date", function (val, params) {
|
||||
}
|
||||
|
||||
if (val) {
|
||||
var date = new Date(val);
|
||||
let date = new Date(val);
|
||||
return htmlSafe(
|
||||
autoUpdatingRelativeAge(date, {
|
||||
format: format,
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { htmlHelper } from "discourse-common/lib/helpers";
|
||||
|
||||
function renderSpinner(cssClass) {
|
||||
var html = "<div class='spinner";
|
||||
let html = "<div class='spinner";
|
||||
if (cssClass) {
|
||||
html += " " + cssClass;
|
||||
}
|
||||
return html + "'></div>";
|
||||
}
|
||||
var spinnerHTML = renderSpinner();
|
||||
let spinnerHTML = renderSpinner();
|
||||
|
||||
export default htmlHelper((params) => {
|
||||
const hash = params.hash;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||
|
||||
registerUnbound("shorten-url", function (url) {
|
||||
var matches = url.match(/\//g);
|
||||
let matches = url.match(/\//g);
|
||||
|
||||
if (matches && matches.length === 3) {
|
||||
url = url.replace(/\/$/, "");
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
// backwards compatibility for plugins that depend on this initializer
|
||||
import { setDefaultOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
export default {
|
||||
name: "inject-objects",
|
||||
initialize() {},
|
||||
initialize(container, app) {
|
||||
// This is required for Ember CLI tests to work
|
||||
setDefaultOwner(app.__container__);
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
SO: http://stackoverflow.com/questions/9943435/css3-animation-end-techniques
|
||||
**/
|
||||
var dummy = document.createElement("div"),
|
||||
let dummy = document.createElement("div"),
|
||||
eventNameHash = {
|
||||
webkit: "webkitTransitionEnd",
|
||||
Moz: "transitionend",
|
||||
@ -12,8 +12,8 @@ var dummy = document.createElement("div"),
|
||||
ms: "MSTransitionEnd",
|
||||
};
|
||||
|
||||
var transitionEnd = (function () {
|
||||
var retValue;
|
||||
let transitionEnd = (function () {
|
||||
let retValue;
|
||||
retValue = "transitionend";
|
||||
Object.keys(eventNameHash).some(function (vendor) {
|
||||
if (vendor + "TransitionProperty" in dummy.style) {
|
||||
|
||||
@ -15,8 +15,8 @@ export function replaceSpan($elem, categorySlug, categoryLink, type) {
|
||||
export function categoryHashtagTriggerRule(textarea, opts) {
|
||||
const result = caretRowCol(textarea);
|
||||
const row = result.rowNum;
|
||||
var col = result.colNum;
|
||||
var line = textarea.value.split("\n")[row - 1];
|
||||
let col = result.colNum;
|
||||
let line = textarea.value.split("\n")[row - 1];
|
||||
|
||||
if (opts && opts.backSpace) {
|
||||
col = col - 1;
|
||||
|
||||
@ -37,7 +37,7 @@ function searchTags(term, categories, limit) {
|
||||
data: { limit: limit, q },
|
||||
});
|
||||
|
||||
var returnVal = CANCELLED_STATUS;
|
||||
let returnVal = CANCELLED_STATUS;
|
||||
|
||||
oldSearch
|
||||
.then((r) => {
|
||||
@ -91,8 +91,8 @@ export function search(term, siteSettings) {
|
||||
}
|
||||
|
||||
const limit = 5;
|
||||
var categories = Category.search(term, { limit });
|
||||
var numOfCategories = categories.length;
|
||||
let categories = Category.search(term, { limit });
|
||||
let numOfCategories = categories.length;
|
||||
|
||||
categories = categories.map((category) => {
|
||||
return { model: category, text: Category.slugFor(category, SEPARATOR, 2) };
|
||||
|
||||
@ -27,7 +27,7 @@ const Mobile = {
|
||||
localStorage.removeItem("mobileView");
|
||||
}
|
||||
if (localStorage.mobileView) {
|
||||
var savedValue = localStorage.mobileView === "true";
|
||||
let savedValue = localStorage.mobileView === "true";
|
||||
if (savedValue !== this.mobileView) {
|
||||
this.reloadPage(savedValue);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// for android we test webkit
|
||||
var hiddenProperty =
|
||||
let hiddenProperty =
|
||||
document.hidden !== undefined
|
||||
? "hidden"
|
||||
: document.webkitHidden !== undefined
|
||||
|
||||
@ -737,10 +737,10 @@ class PluginApi {
|
||||
* example:
|
||||
*
|
||||
* api.addUserMenuGlyph({
|
||||
* label: 'awesome.label',
|
||||
* title: 'awesome.label',
|
||||
* className: 'my-class',
|
||||
* icon: 'my-icon',
|
||||
* href: `/some/path`
|
||||
* data: { url: `/some/path` },
|
||||
* });
|
||||
*
|
||||
*/
|
||||
@ -1227,11 +1227,11 @@ let _pluginv01;
|
||||
|
||||
// from http://stackoverflow.com/questions/6832596/how-to-compare-software-version-number-using-js-only-number
|
||||
function cmpVersions(a, b) {
|
||||
var i, diff;
|
||||
var regExStrip0 = /(\.0+)+$/;
|
||||
var segmentsA = a.replace(regExStrip0, "").split(".");
|
||||
var segmentsB = b.replace(regExStrip0, "").split(".");
|
||||
var l = Math.min(segmentsA.length, segmentsB.length);
|
||||
let i, diff;
|
||||
let regExStrip0 = /(\.0+)+$/;
|
||||
let segmentsA = a.replace(regExStrip0, "").split(".");
|
||||
let segmentsB = b.replace(regExStrip0, "").split(".");
|
||||
let l = Math.min(segmentsA.length, segmentsB.length);
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
|
||||
|
||||
@ -93,7 +93,7 @@ function positioningWorkaround($fixedElement) {
|
||||
const fixedElement = $fixedElement[0];
|
||||
const oldHeight = fixedElement.style.height;
|
||||
|
||||
var originalScrollTop = 0;
|
||||
let originalScrollTop = 0;
|
||||
let lastTouchedElement = null;
|
||||
|
||||
positioningWorkaround.blur = function (evt) {
|
||||
@ -114,7 +114,7 @@ function positioningWorkaround($fixedElement) {
|
||||
}
|
||||
};
|
||||
|
||||
var blurredNow = function (evt) {
|
||||
let blurredNow = function (evt) {
|
||||
// we cannot use evt.relatedTarget to get the last focused element in safari iOS
|
||||
// document.activeElement is also unreliable (iOS does not mark buttons as focused)
|
||||
// so instead, we store the last touched element and check against it
|
||||
@ -145,11 +145,11 @@ function positioningWorkaround($fixedElement) {
|
||||
positioningWorkaround.blur(evt);
|
||||
};
|
||||
|
||||
var blurred = function (evt) {
|
||||
let blurred = function (evt) {
|
||||
discourseDebounce(this, blurredNow, evt, INPUT_DELAY);
|
||||
};
|
||||
|
||||
var positioningHack = function (evt) {
|
||||
let positioningHack = function (evt) {
|
||||
let _this = this;
|
||||
|
||||
if (evt === undefined) {
|
||||
@ -203,7 +203,7 @@ function positioningWorkaround($fixedElement) {
|
||||
}, delay);
|
||||
};
|
||||
|
||||
var lastTouched = function (evt) {
|
||||
let lastTouched = function (evt) {
|
||||
if (evt && evt.target) {
|
||||
lastTouchedElement = evt.target;
|
||||
}
|
||||
@ -231,7 +231,7 @@ function positioningWorkaround($fixedElement) {
|
||||
};
|
||||
|
||||
positioningWorkaround.touchstartEvent = function (element) {
|
||||
var triggerHack = positioningHack.bind(element);
|
||||
let triggerHack = positioningHack.bind(element);
|
||||
triggerHack();
|
||||
};
|
||||
|
||||
|
||||
@ -29,3 +29,7 @@ export function siteDir() {
|
||||
}
|
||||
return _siteDir;
|
||||
}
|
||||
|
||||
export function isDocumentRTL() {
|
||||
return siteDir() === "rtl";
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { emailValid } from "discourse/lib/utilities";
|
||||
import { isTesting } from "discourse-common/config/environment";
|
||||
import { userPath } from "discourse/lib/url";
|
||||
|
||||
var cache = {},
|
||||
let cache = {},
|
||||
cacheKey,
|
||||
cacheTime,
|
||||
currentTerm,
|
||||
@ -23,7 +23,7 @@ function performSearch(
|
||||
groupMembersOf,
|
||||
resultsFn
|
||||
) {
|
||||
var cached = cache[term];
|
||||
let cached = cache[term];
|
||||
if (cached) {
|
||||
resultsFn(cached);
|
||||
return;
|
||||
@ -52,7 +52,7 @@ function performSearch(
|
||||
},
|
||||
});
|
||||
|
||||
var returnVal = CANCELLED_STATUS;
|
||||
let returnVal = CANCELLED_STATUS;
|
||||
|
||||
oldSearch
|
||||
.then(function (r) {
|
||||
@ -81,7 +81,7 @@ function performSearch(
|
||||
});
|
||||
}
|
||||
|
||||
var debouncedSearch = function (
|
||||
let debouncedSearch = function (
|
||||
term,
|
||||
topicId,
|
||||
categoryId,
|
||||
@ -113,7 +113,7 @@ function organizeResults(r, options) {
|
||||
return r;
|
||||
}
|
||||
|
||||
var exclude = options.exclude || [],
|
||||
let exclude = options.exclude || [],
|
||||
limit = options.limit || 5,
|
||||
users = [],
|
||||
emails = [],
|
||||
@ -182,7 +182,7 @@ export default function userSearch(options) {
|
||||
options.term = options.term.substring(1);
|
||||
}
|
||||
|
||||
var term = options.term || "",
|
||||
let term = options.term || "",
|
||||
includeGroups = options.includeGroups,
|
||||
includeMentionableGroups = options.includeMentionableGroups,
|
||||
includeMessageableGroups = options.includeMessageableGroups,
|
||||
|
||||
@ -97,7 +97,7 @@ export function tinyAvatar(avatarTemplate, options) {
|
||||
}
|
||||
|
||||
export function postUrl(slug, topicId, postNumber) {
|
||||
var url = getURL("/t/");
|
||||
let url = getURL("/t/");
|
||||
if (slug) {
|
||||
url += slug + "/";
|
||||
} else {
|
||||
@ -190,11 +190,11 @@ export function selectedElement() {
|
||||
|
||||
// Determine the row and col of the caret in an element
|
||||
export function caretRowCol(el) {
|
||||
var cp = caretPosition(el);
|
||||
var rows = el.value.slice(0, cp).split("\n");
|
||||
var rowNum = rows.length;
|
||||
let cp = caretPosition(el);
|
||||
let rows = el.value.slice(0, cp).split("\n");
|
||||
let rowNum = rows.length;
|
||||
|
||||
var colNum =
|
||||
let colNum =
|
||||
cp -
|
||||
rows.splice(0, rowNum - 1).reduce(function (sum, row) {
|
||||
return sum + row.length + 1;
|
||||
@ -205,7 +205,7 @@ export function caretRowCol(el) {
|
||||
|
||||
// Determine the position of the caret in an element
|
||||
export function caretPosition(el) {
|
||||
var r, rc, re;
|
||||
let r, rc, re;
|
||||
if (el.selectionStart) {
|
||||
return el.selectionStart;
|
||||
}
|
||||
@ -227,7 +227,7 @@ export function caretPosition(el) {
|
||||
|
||||
// Set the caret's position
|
||||
export function setCaretPosition(ctrl, pos) {
|
||||
var range;
|
||||
let range;
|
||||
if (ctrl.setSelectionRange) {
|
||||
ctrl.focus();
|
||||
ctrl.setSelectionRange(pos, pos);
|
||||
@ -421,7 +421,7 @@ export function areCookiesEnabled() {
|
||||
// see: https://github.com/Modernizr/Modernizr/blob/400db4043c22af98d46e1d2b9cbc5cb062791192/feature-detects/cookies.js
|
||||
try {
|
||||
document.cookie = "cookietest=1";
|
||||
var ret = document.cookie.indexOf("cookietest=") !== -1;
|
||||
let ret = document.cookie.indexOf("cookietest=") !== -1;
|
||||
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
|
||||
return ret;
|
||||
} catch (e) {
|
||||
|
||||
@ -113,7 +113,7 @@ export function mapRoutes() {
|
||||
// can define admin routes.
|
||||
Object.keys(requirejs._eak_seen).forEach(function (key) {
|
||||
if (/route-map$/.test(key)) {
|
||||
var module = requirejs(key, null, null, true);
|
||||
let module = requirejs(key, null, null, true);
|
||||
if (!module || !module.default) {
|
||||
throw new Error(key + " must export a route map.");
|
||||
}
|
||||
|
||||
@ -3,8 +3,11 @@ import { NotificationLevels } from "discourse/lib/notification-levels";
|
||||
import Topic from "discourse/models/topic";
|
||||
import { alias } from "@ember/object/computed";
|
||||
import { on } from "discourse-common/utils/decorators";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Mixin.create({
|
||||
router: service(),
|
||||
|
||||
bulkSelectEnabled: false,
|
||||
selected: null,
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ const Singleton = Mixin.create({
|
||||
|
||||
// Returns OR sets a property on the singleton instance.
|
||||
currentProp(property, value) {
|
||||
var instance = this.current();
|
||||
let instance = this.current();
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -312,7 +312,7 @@ const Category = RestModel.extend({
|
||||
},
|
||||
});
|
||||
|
||||
var _uncategorized;
|
||||
let _uncategorized;
|
||||
|
||||
Category.reopenClass({
|
||||
slugEncoded() {
|
||||
@ -508,7 +508,7 @@ Category.reopenClass({
|
||||
},
|
||||
|
||||
search(term, opts) {
|
||||
var limit = 5;
|
||||
let limit = 5;
|
||||
|
||||
if (opts) {
|
||||
if (opts.limit === 0) {
|
||||
@ -529,8 +529,8 @@ Category.reopenClass({
|
||||
|
||||
const categories = Category.listByActivity();
|
||||
const length = categories.length;
|
||||
var i;
|
||||
var data = [];
|
||||
let i;
|
||||
let data = [];
|
||||
|
||||
const done = () => {
|
||||
return data.length === limit;
|
||||
|
||||
@ -177,7 +177,7 @@ NavItem.reopenClass({
|
||||
return null;
|
||||
}
|
||||
|
||||
var args = { name: filterType, hasIcon: filterType === "unread" };
|
||||
let args = { name: filterType, hasIcon: filterType === "unread" };
|
||||
if (opts.category) {
|
||||
args.category = opts.category;
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { postUrl } from "discourse/lib/utilities";
|
||||
import { propertyEqual } from "discourse/lib/computed";
|
||||
import { resolveShareUrl } from "discourse/helpers/share-url";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { userPath } from "discourse/lib/url";
|
||||
|
||||
const Post = RestModel.extend({
|
||||
@ -304,58 +303,24 @@ const Post = RestModel.extend({
|
||||
return ajax(`/posts/${this.id}/unhide`, { type: "PUT" });
|
||||
},
|
||||
|
||||
toggleBookmark() {
|
||||
let postEl = document.querySelector(`[data-post-id="${this.id}"]`);
|
||||
let localDateEl = null;
|
||||
if (postEl) {
|
||||
localDateEl = postEl.querySelector(".discourse-local-date");
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let controller = showModal("bookmark", {
|
||||
model: {
|
||||
postId: this.id,
|
||||
id: this.bookmark_id,
|
||||
reminderAt: this.bookmark_reminder_at,
|
||||
autoDeletePreference: this.bookmark_auto_delete_preference,
|
||||
name: this.bookmark_name,
|
||||
postDetectedLocalDate: localDateEl ? localDateEl.dataset.date : null,
|
||||
postDetectedLocalTime: localDateEl ? localDateEl.dataset.time : null,
|
||||
postDetectedLocalTimezone: localDateEl
|
||||
? localDateEl.dataset.timezone
|
||||
: null,
|
||||
},
|
||||
title: this.bookmark_id
|
||||
? "post.bookmarks.edit"
|
||||
: "post.bookmarks.create",
|
||||
modalClass: "bookmark-with-reminder",
|
||||
});
|
||||
controller.setProperties({
|
||||
onCloseWithoutSaving: () => {
|
||||
resolve({ closedWithoutSaving: true });
|
||||
this.appEvents.trigger("post-stream:refresh", { id: this.id });
|
||||
},
|
||||
afterSave: (savedData) => {
|
||||
this.setProperties({
|
||||
"topic.bookmarked": true,
|
||||
bookmarked: true,
|
||||
bookmark_reminder_at: savedData.reminderAt,
|
||||
bookmark_reminder_type: savedData.reminderType,
|
||||
bookmark_auto_delete_preference: savedData.autoDeletePreference,
|
||||
bookmark_name: savedData.name,
|
||||
bookmark_id: savedData.id,
|
||||
});
|
||||
resolve({ closedWithoutSaving: false });
|
||||
this.appEvents.trigger("page:bookmark-post-toggled", this);
|
||||
this.appEvents.trigger("post-stream:refresh", { id: this.id });
|
||||
},
|
||||
afterDelete: (topicBookmarked) => {
|
||||
this.set("topic.bookmarked", topicBookmarked);
|
||||
this.clearBookmark();
|
||||
this.appEvents.trigger("page:bookmark-post-toggled", this);
|
||||
},
|
||||
});
|
||||
createBookmark(data) {
|
||||
this.setProperties({
|
||||
"topic.bookmarked": true,
|
||||
bookmarked: true,
|
||||
bookmark_reminder_at: data.reminderAt,
|
||||
bookmark_reminder_type: data.reminderType,
|
||||
bookmark_auto_delete_preference: data.autoDeletePreference,
|
||||
bookmark_name: data.name,
|
||||
bookmark_id: data.id,
|
||||
});
|
||||
this.appEvents.trigger("page:bookmark-post-toggled", this);
|
||||
this.appEvents.trigger("post-stream:refresh", { id: this.id });
|
||||
},
|
||||
|
||||
deleteBookmark(bookmarked) {
|
||||
this.set("topic.bookmarked", bookmarked);
|
||||
this.clearBookmark();
|
||||
this.appEvents.trigger("page:bookmark-post-toggled", this);
|
||||
},
|
||||
|
||||
clearBookmark() {
|
||||
|
||||
@ -114,9 +114,9 @@ export default EmberObject.extend({
|
||||
},
|
||||
|
||||
find(type, findArgs, opts) {
|
||||
var adapter = this.adapterFor(type);
|
||||
let adapter = this.adapterFor(type);
|
||||
return adapter.find(this, type, findArgs, opts).then((result) => {
|
||||
var hydrated = this._hydrateFindResults(result, type, findArgs, opts);
|
||||
let hydrated = this._hydrateFindResults(result, type, findArgs, opts);
|
||||
|
||||
if (result.extras) {
|
||||
hydrated.set("extras", result.extras);
|
||||
@ -139,7 +139,7 @@ export default EmberObject.extend({
|
||||
hydrated.set(
|
||||
"content",
|
||||
hydrated.get("content").map((item) => {
|
||||
var staleItem = stale.content.findBy(primaryKey, item.get(primaryKey));
|
||||
let staleItem = stale.content.findBy(primaryKey, item.get(primaryKey));
|
||||
if (staleItem) {
|
||||
staleItem.setProperties(item);
|
||||
} else {
|
||||
|
||||
@ -291,7 +291,7 @@ const TopicTrackingState = EmberObject.extend({
|
||||
if (split.length >= 4) {
|
||||
filter = split[split.length - 1];
|
||||
// c/cat/subcat/6/l/latest
|
||||
var category = Category.findSingleBySlug(
|
||||
let category = Category.findSingleBySlug(
|
||||
split.splice(1, split.length - 4).join("/")
|
||||
);
|
||||
this.set("filterCategory", category);
|
||||
|
||||
@ -11,7 +11,6 @@ import Session from "discourse/models/session";
|
||||
import Site from "discourse/models/site";
|
||||
import User from "discourse/models/user";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import bootbox from "bootbox";
|
||||
import { deepMerge } from "discourse-common/lib/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
@ -404,73 +403,8 @@ const Topic = RestModel.extend({
|
||||
}
|
||||
},
|
||||
|
||||
toggleBookmark() {
|
||||
if (this.bookmarking) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
this.set("bookmarking", true);
|
||||
const bookmark = !this.bookmarked;
|
||||
let posts = this.postStream.posts;
|
||||
|
||||
return this.firstPost().then((firstPost) => {
|
||||
const toggleBookmarkOnServer = () => {
|
||||
if (bookmark) {
|
||||
return firstPost.toggleBookmark().then((opts) => {
|
||||
this.set("bookmarking", false);
|
||||
if (opts.closedWithoutSaving) {
|
||||
return;
|
||||
}
|
||||
return this.afterTopicBookmarked(firstPost);
|
||||
});
|
||||
} else {
|
||||
return ajax(`/t/${this.id}/remove_bookmarks`, { type: "PUT" })
|
||||
.then(() => {
|
||||
this.toggleProperty("bookmarked");
|
||||
this.set("bookmark_reminder_at", null);
|
||||
let clearedBookmarkProps = {
|
||||
bookmarked: false,
|
||||
bookmark_id: null,
|
||||
bookmark_name: null,
|
||||
bookmark_reminder_at: null,
|
||||
};
|
||||
if (posts) {
|
||||
const updated = [];
|
||||
posts.forEach((post) => {
|
||||
if (post.bookmarked) {
|
||||
post.setProperties(clearedBookmarkProps);
|
||||
updated.push(post.id);
|
||||
}
|
||||
});
|
||||
firstPost.setProperties(clearedBookmarkProps);
|
||||
return updated;
|
||||
}
|
||||
})
|
||||
.catch(popupAjaxError)
|
||||
.finally(() => this.set("bookmarking", false));
|
||||
}
|
||||
};
|
||||
|
||||
const unbookmarkedPosts = [];
|
||||
if (!bookmark && posts) {
|
||||
posts.forEach(
|
||||
(post) => post.bookmarked && unbookmarkedPosts.push(post)
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
if (unbookmarkedPosts.length > 1) {
|
||||
bootbox.confirm(
|
||||
I18n.t("bookmarks.confirm_clear"),
|
||||
I18n.t("no_value"),
|
||||
I18n.t("yes_value"),
|
||||
(confirmed) =>
|
||||
confirmed ? toggleBookmarkOnServer().then(resolve) : resolve()
|
||||
);
|
||||
} else {
|
||||
toggleBookmarkOnServer().then(resolve);
|
||||
}
|
||||
});
|
||||
});
|
||||
deleteBookmark() {
|
||||
return ajax(`/t/${this.id}/remove_bookmarks`, { type: "PUT" });
|
||||
},
|
||||
|
||||
createGroupInvite(group) {
|
||||
|
||||
@ -27,7 +27,7 @@ UserBadge.reopenClass({
|
||||
if (json.users === undefined) {
|
||||
json.users = [];
|
||||
}
|
||||
var users = {};
|
||||
let users = {};
|
||||
json.users.forEach(function (userJson) {
|
||||
users[userJson.id] = User.create(userJson);
|
||||
});
|
||||
@ -36,7 +36,7 @@ UserBadge.reopenClass({
|
||||
if (json.topics === undefined) {
|
||||
json.topics = [];
|
||||
}
|
||||
var topics = {};
|
||||
let topics = {};
|
||||
json.topics.forEach(function (topicJson) {
|
||||
topics[topicJson.id] = Topic.create(topicJson);
|
||||
});
|
||||
@ -45,13 +45,13 @@ UserBadge.reopenClass({
|
||||
if (json.badges === undefined) {
|
||||
json.badges = [];
|
||||
}
|
||||
var badges = {};
|
||||
let badges = {};
|
||||
Badge.createFromJson(json).forEach(function (badge) {
|
||||
badges[badge.get("id")] = badge;
|
||||
});
|
||||
|
||||
// Create UserBadge object(s).
|
||||
var userBadges = [];
|
||||
let userBadges = [];
|
||||
if ("user_badge" in json) {
|
||||
userBadges = [json.user_badge];
|
||||
} else {
|
||||
@ -61,9 +61,9 @@ UserBadge.reopenClass({
|
||||
}
|
||||
|
||||
userBadges = userBadges.map(function (userBadgeJson) {
|
||||
var userBadge = UserBadge.create(userBadgeJson);
|
||||
let userBadge = UserBadge.create(userBadgeJson);
|
||||
|
||||
var grantedAtDate = Date.parse(userBadge.get("granted_at"));
|
||||
let grantedAtDate = Date.parse(userBadge.get("granted_at"));
|
||||
userBadge.set("grantedAt", grantedAtDate);
|
||||
|
||||
userBadge.set("badge", badges[userBadge.get("badge_id")]);
|
||||
@ -102,7 +102,7 @@ UserBadge.reopenClass({
|
||||
if (!username) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
var url = "/user-badges/" + username + ".json";
|
||||
let url = "/user-badges/" + username + ".json";
|
||||
if (options && options.grouped) {
|
||||
url += "?grouped=true";
|
||||
}
|
||||
|
||||
@ -342,7 +342,7 @@ const User = RestModel.extend({
|
||||
data[s] = this.get(`user_option.${s}`);
|
||||
});
|
||||
|
||||
var updatedState = {};
|
||||
let updatedState = {};
|
||||
|
||||
["muted", "regular", "watched", "tracked", "watched_first_post"].forEach(
|
||||
(s) => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Application from "@ember/application";
|
||||
import Ember from "ember";
|
||||
import { isLegacyEmber } from "discourse-common/config/environment";
|
||||
import { registerRouter } from "discourse/mapping-router";
|
||||
|
||||
let originalBuildInstance;
|
||||
@ -12,8 +12,7 @@ export default {
|
||||
let router = registerRouter(app);
|
||||
container.registry.register("router:main", router);
|
||||
|
||||
// TODO: Remove this once we've upgraded Ember everywhere
|
||||
if (Ember.VERSION.startsWith("3.12")) {
|
||||
if (isLegacyEmber()) {
|
||||
// HACK to fix: https://github.com/emberjs/ember.js/issues/10310
|
||||
originalBuildInstance =
|
||||
originalBuildInstance || Application.prototype.buildInstance;
|
||||
|
||||
@ -3,8 +3,8 @@ export default {
|
||||
|
||||
initialize: function () {
|
||||
$('script[type="text/x-handlebars"]').each(function () {
|
||||
var $this = $(this);
|
||||
var name = $this.attr("name") || $this.data("template-name");
|
||||
let $this = $(this);
|
||||
let name = $this.attr("name") || $this.data("template-name");
|
||||
|
||||
if (window.console) {
|
||||
window.console.log(
|
||||
|
||||
@ -157,7 +157,7 @@ export default (filterArg, params) => {
|
||||
canCreateTopic: canCreateTopic,
|
||||
});
|
||||
|
||||
var topicOpts = {
|
||||
let topicOpts = {
|
||||
model: topics,
|
||||
category,
|
||||
period:
|
||||
|
||||
@ -13,6 +13,7 @@ export default DiscourseRoute.extend({
|
||||
controller.setProperties({
|
||||
parentParams,
|
||||
selectedTab: transition.to.params.tab,
|
||||
showTooltip: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@ -30,7 +30,7 @@ export default DiscourseRoute.extend({
|
||||
|
||||
model(params) {
|
||||
const cached = getTransient("lastSearch");
|
||||
var args = { q: params.q };
|
||||
let args = { q: params.q };
|
||||
if (params.context_id && !args.skip_context) {
|
||||
args.search_context = {
|
||||
type: params.context,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user