diff --git a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 index ee2fd2f95d6..40bad8ae00b 100644 --- a/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-backups-logs.js.es6 @@ -1,5 +1,10 @@ export default Ember.Controller.extend({ - logs: [], adminBackups: Ember.inject.controller(), - status: Ember.computed.alias("adminBackups.model") + status: Ember.computed.alias("adminBackups.model"), + + init() { + this._super(...arguments); + + this.logs = []; + } }); diff --git a/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 index 6fe215c9c3e..7bf7659f657 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-email-templates.js.es6 @@ -1,6 +1,10 @@ export default Ember.Controller.extend({ - titleSorting: ["title"], emailTemplates: null, + sortedTemplates: Ember.computed.sort("emailTemplates", "titleSorting"), - sortedTemplates: Ember.computed.sort("emailTemplates", "titleSorting") + init() { + this._super(...arguments); + + this.titleSorting = ["title"]; + } }); diff --git a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 index 4d7d8d232c6..d1109043382 100644 --- a/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-emojis.js.es6 @@ -1,7 +1,12 @@ import { ajax } from "discourse/lib/ajax"; export default Ember.Controller.extend({ sortedEmojis: Ember.computed.sort("model", "emojiSorting"), - emojiSorting: ["name"], + + init() { + this._super(...arguments); + + this.emojiSorting = ["name"]; + }, actions: { emojiUploaded(emoji) { diff --git a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 index f13ac514628..b17b5a2345b 100644 --- a/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-logs-staff-action-logs.js.es6 @@ -6,10 +6,14 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend({ loading: false, filters: null, - userHistoryActions: [], - filtersExists: Ember.computed.gt("filterCount", 0), + init() { + this._super(...arguments); + + this.userHistoryActions = []; + }, + filterActionIdChanged: function() { const filterActionId = this.filterActionId; if (filterActionId) { diff --git a/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 index ccc44c5424e..5c26cb0e9f2 100644 --- a/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-search-logs-index.js.es6 @@ -5,12 +5,19 @@ export default Ember.Controller.extend({ period: DEFAULT_PERIOD, searchType: "all", - searchTypeOptions: [ - { - id: "all", - name: I18n.t("admin.logs.search_logs.types.all_search_types") - }, - { id: "header", name: I18n.t("admin.logs.search_logs.types.header") }, - { id: "full_page", name: I18n.t("admin.logs.search_logs.types.full_page") } - ] + init() { + this._super(...arguments); + + this.searchTypeOptions = [ + { + id: "all", + name: I18n.t("admin.logs.search_logs.types.all_search_types") + }, + { id: "header", name: I18n.t("admin.logs.search_logs.types.header") }, + { + id: "full_page", + name: I18n.t("admin.logs.search_logs.types.full_page") + } + ]; + } }); diff --git a/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 b/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 index 9b8a5f7e732..229aa67db87 100644 --- a/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-search-logs-term.js.es6 @@ -6,16 +6,23 @@ export default Ember.Controller.extend({ period: DEFAULT_PERIOD, searchType: "all", - searchTypeOptions: [ - { - id: "all", - name: I18n.t("admin.logs.search_logs.types.all_search_types") - }, - { id: "header", name: I18n.t("admin.logs.search_logs.types.header") }, - { id: "full_page", name: I18n.t("admin.logs.search_logs.types.full_page") }, - { - id: "click_through_only", - name: I18n.t("admin.logs.search_logs.types.click_through_only") - } - ] + init() { + this._super(...arguments); + + this.searchTypeOptions = [ + { + id: "all", + name: I18n.t("admin.logs.search_logs.types.all_search_types") + }, + { id: "header", name: I18n.t("admin.logs.search_logs.types.header") }, + { + id: "full_page", + name: I18n.t("admin.logs.search_logs.types.full_page") + }, + { + id: "click_through_only", + name: I18n.t("admin.logs.search_logs.types.click_through_only") + } + ]; + } }); diff --git a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 index 6b44749f3bc..d419cf9e345 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 @@ -7,9 +7,13 @@ export default Ember.Controller.extend(GrantBadgeController, { user: Ember.computed.alias("adminUser.model"), userBadges: Ember.computed.alias("model"), allBadges: Ember.computed.alias("badges"), - sortedBadges: Ember.computed.sort("model", "badgeSortOrder"), - badgeSortOrder: ["granted_at:desc"], + + init() { + this._super(...arguments); + + this.badgeSortOrder = ["granted_at:desc"]; + }, @computed("model", "model.[]", "model.expandedBadges.[]") groupedBadges() { diff --git a/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 index 012b91c9dad..7d2a6b3d567 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-fields.js.es6 @@ -5,10 +5,14 @@ const MAX_FIELDS = 20; export default Ember.Controller.extend({ fieldTypes: null, createDisabled: Ember.computed.gte("model.length", MAX_FIELDS), - - fieldSortOrder: ["position"], sortedFields: Ember.computed.sort("model", "fieldSortOrder"), + init() { + this._super(...arguments); + + this.fieldSortOrder = ["position"]; + }, + actions: { createField() { const f = this.store.createRecord("user-field", { diff --git a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 index d8c233d88ad..388fab304fa 100644 --- a/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-web-hooks-show-events.js.es6 @@ -4,9 +4,14 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend({ pingDisabled: false, - incomingEventIds: [], incomingCount: Ember.computed.alias("incomingEventIds.length"), + init() { + this._super(...arguments); + + this.incomingEventIds = []; + }, + @computed("incomingCount") hasIncoming(incomingCount) { return incomingCount > 0; diff --git a/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 index 562bf406904..15688a166aa 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-install-theme.js.es6 @@ -121,13 +121,18 @@ export default Ember.Controller.extend(ModalFunctionality, { urlPlaceholder: "https://github.com/discourse/sample_theme", advancedVisible: false, themesController: Ember.inject.controller("adminCustomizeThemes"), - createTypes: [ - { name: I18n.t("admin.customize.theme.theme"), value: THEMES }, - { name: I18n.t("admin.customize.theme.component"), value: COMPONENTS } - ], selectedType: Ember.computed.alias("themesController.currentTab"), component: Ember.computed.equal("selectedType", COMPONENTS), + init() { + this._super(...arguments); + + this.createTypes = [ + { name: I18n.t("admin.customize.theme.theme"), value: THEMES }, + { name: I18n.t("admin.customize.theme.component"), value: COMPONENTS } + ]; + }, + @computed("themesController.installedThemes") themes(installedThemes) { return POPULAR_THEMES.map(t => { diff --git a/app/assets/javascripts/admin/mixins/period-computation.js.es6 b/app/assets/javascripts/admin/mixins/period-computation.js.es6 index 6cad0c6dee0..4323532e845 100644 --- a/app/assets/javascripts/admin/mixins/period-computation.js.es6 +++ b/app/assets/javascripts/admin/mixins/period-computation.js.es6 @@ -3,10 +3,13 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Mixin.create({ queryParams: ["period"], - period: "monthly", - availablePeriods: ["yearly", "quarterly", "monthly", "weekly"], + init() { + this._super(...arguments); + + this.availablePeriods = ["yearly", "quarterly", "monthly", "weekly"]; + }, @computed("period") startDate(period) { diff --git a/app/assets/javascripts/admin/models/theme.js.es6 b/app/assets/javascripts/admin/models/theme.js.es6 index 3fae52ccc48..7e49ff9b9e8 100644 --- a/app/assets/javascripts/admin/models/theme.js.es6 +++ b/app/assets/javascripts/admin/models/theme.js.es6 @@ -6,13 +6,13 @@ import { escapeExpression } from "discourse/lib/utilities"; import highlightSyntax from "discourse/lib/highlight-syntax"; const THEME_UPLOAD_VAR = 2; +const FIELDS_IDS = [0, 1, 5]; export const THEMES = "themes"; export const COMPONENTS = "components"; const SETTINGS_TYPE_ID = 5; const Theme = RestModel.extend({ - FIELDS_IDS: [0, 1, 5], isActive: Ember.computed.or("default", "user_selectable"), isPendingUpdates: Ember.computed.gt("remote_theme.commits_behind", 0), hasEditedFields: Ember.computed.gt("editedFields.length", 0), @@ -118,7 +118,7 @@ const Theme = RestModel.extend({ let hash = {}; fields.forEach(field => { - if (!field.type_id || this.FIELDS_IDS.includes(field.type_id)) { + if (!field.type_id || FIELDS_IDS.includes(field.type_id)) { hash[this.getKey(field)] = field; } }); diff --git a/app/assets/javascripts/discourse/components/edit-category-general.js.es6 b/app/assets/javascripts/discourse/components/edit-category-general.js.es6 index 05b136ce7d4..9988120e59b 100644 --- a/app/assets/javascripts/discourse/components/edit-category-general.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-general.js.es6 @@ -4,7 +4,12 @@ import Category from "discourse/models/category"; import computed from "ember-addons/ember-computed-decorators"; export default buildCategoryPanel("general", { - foregroundColors: ["FFFFFF", "000000"], + init() { + this._super(...arguments); + + this.foregroundColors = ["FFFFFF", "000000"]; + }, + canSelectParentCategory: Ember.computed.not( "category.isUncategorizedCategory" ), diff --git a/app/assets/javascripts/discourse/components/group-member-dropdown.js.es6 b/app/assets/javascripts/discourse/components/group-member-dropdown.js.es6 index 6cd50f87a75..5cb7099058a 100644 --- a/app/assets/javascripts/discourse/components/group-member-dropdown.js.es6 +++ b/app/assets/javascripts/discourse/components/group-member-dropdown.js.es6 @@ -7,7 +7,12 @@ export default DropdownSelectBoxComponent.extend({ showFullTitle: false, allowInitialValueMutation: false, allowAutoSelectFirst: false, - headerIcon: ["wrench"], + + init() { + this._super(...arguments); + + this.headerIcon = ["wrench"]; + }, autoHighlight() {}, diff --git a/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 b/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 index dc81aa4474c..6ccc23df737 100644 --- a/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 +++ b/app/assets/javascripts/discourse/components/groups-form-interaction-fields.js.es6 @@ -1,32 +1,42 @@ import { default as computed } from "ember-addons/ember-computed-decorators"; export default Ember.Component.extend({ - visibilityLevelOptions: [ - { - name: I18n.t("admin.groups.manage.interaction.visibility_levels.public"), - value: 0 - }, - { - name: I18n.t("admin.groups.manage.interaction.visibility_levels.members"), - value: 1 - }, - { - name: I18n.t("admin.groups.manage.interaction.visibility_levels.staff"), - value: 2 - }, - { - name: I18n.t("admin.groups.manage.interaction.visibility_levels.owners"), - value: 3 - } - ], + init() { + this._super(...arguments); - aliasLevelOptions: [ - { name: I18n.t("groups.alias_levels.nobody"), value: 0 }, - { name: I18n.t("groups.alias_levels.only_admins"), value: 1 }, - { name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 }, - { name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 }, - { name: I18n.t("groups.alias_levels.everyone"), value: 99 } - ], + this.visibilityLevelOptions = [ + { + name: I18n.t( + "admin.groups.manage.interaction.visibility_levels.public" + ), + value: 0 + }, + { + name: I18n.t( + "admin.groups.manage.interaction.visibility_levels.members" + ), + value: 1 + }, + { + name: I18n.t("admin.groups.manage.interaction.visibility_levels.staff"), + value: 2 + }, + { + name: I18n.t( + "admin.groups.manage.interaction.visibility_levels.owners" + ), + value: 3 + } + ]; + + this.aliasLevelOptions = [ + { name: I18n.t("groups.alias_levels.nobody"), value: 0 }, + { name: I18n.t("groups.alias_levels.only_admins"), value: 1 }, + { name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 }, + { name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 }, + { name: I18n.t("groups.alias_levels.everyone"), value: 99 } + ]; + }, @computed("siteSettings.email_in", "model.automatic", "currentUser.admin") showEmailSettings(emailIn, automatic, isAdmin) { diff --git a/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 b/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 index 500d61ce285..306f9a0f30a 100644 --- a/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 +++ b/app/assets/javascripts/discourse/components/groups-form-membership-fields.js.es6 @@ -1,16 +1,20 @@ import computed from "ember-addons/ember-computed-decorators"; export default Ember.Component.extend({ - trustLevelOptions: [ - { - name: I18n.t("admin.groups.manage.membership.trust_levels_none"), - value: 0 - }, - { name: 1, value: 1 }, - { name: 2, value: 2 }, - { name: 3, value: 3 }, - { name: 4, value: 4 } - ], + init() { + this._super(...arguments); + + this.trustLevelOptions = [ + { + name: I18n.t("admin.groups.manage.membership.trust_levels_none"), + value: 0 + }, + { name: 1, value: 1 }, + { name: 2, value: 2 }, + { name: 3, value: 3 }, + { name: 4, value: 4 } + ]; + }, @computed("model.visibility_level", "model.public_admission") disableMembershipRequestSetting(visibility_level, publicAdmission) { diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index f8bbabc122d..75b2e5460a0 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -31,44 +31,47 @@ const IN_OPTIONS_MAPPING = { images: "with" }; export default Ember.Component.extend({ classNames: ["search-advanced-options"], - inOptionsForUsers: [ - { name: I18n.t("search.advanced.filters.unseen"), value: "unseen" }, - { name: I18n.t("search.advanced.filters.posted"), value: "posted" }, - { name: I18n.t("search.advanced.filters.watching"), value: "watching" }, - { name: I18n.t("search.advanced.filters.tracking"), value: "tracking" }, - { name: I18n.t("search.advanced.filters.bookmarks"), value: "bookmarks" } - ], - - inOptionsForAll: [ - { name: I18n.t("search.advanced.filters.first"), value: "first" }, - { name: I18n.t("search.advanced.filters.pinned"), value: "pinned" }, - { name: I18n.t("search.advanced.filters.unpinned"), value: "unpinned" }, - { name: I18n.t("search.advanced.filters.wiki"), value: "wiki" }, - { name: I18n.t("search.advanced.filters.images"), value: "images" } - ], - - statusOptions: [ - { name: I18n.t("search.advanced.statuses.open"), value: "open" }, - { name: I18n.t("search.advanced.statuses.closed"), value: "closed" }, - { name: I18n.t("search.advanced.statuses.archived"), value: "archived" }, - { name: I18n.t("search.advanced.statuses.noreplies"), value: "noreplies" }, - { - name: I18n.t("search.advanced.statuses.single_user"), - value: "single_user" - } - ], - - postTimeOptions: [ - { name: I18n.t("search.advanced.post.time.before"), value: "before" }, - { name: I18n.t("search.advanced.post.time.after"), value: "after" } - ], - init() { this._super(...arguments); + + this.inOptionsForUsers = [ + { name: I18n.t("search.advanced.filters.unseen"), value: "unseen" }, + { name: I18n.t("search.advanced.filters.posted"), value: "posted" }, + { name: I18n.t("search.advanced.filters.watching"), value: "watching" }, + { name: I18n.t("search.advanced.filters.tracking"), value: "tracking" }, + { name: I18n.t("search.advanced.filters.bookmarks"), value: "bookmarks" } + ]; + + this.inOptionsForAll = [ + { name: I18n.t("search.advanced.filters.first"), value: "first" }, + { name: I18n.t("search.advanced.filters.pinned"), value: "pinned" }, + { name: I18n.t("search.advanced.filters.unpinned"), value: "unpinned" }, + { name: I18n.t("search.advanced.filters.wiki"), value: "wiki" }, + { name: I18n.t("search.advanced.filters.images"), value: "images" } + ]; + + this.statusOptions = [ + { name: I18n.t("search.advanced.statuses.open"), value: "open" }, + { name: I18n.t("search.advanced.statuses.closed"), value: "closed" }, + { name: I18n.t("search.advanced.statuses.archived"), value: "archived" }, + { + name: I18n.t("search.advanced.statuses.noreplies"), + value: "noreplies" + }, + { + name: I18n.t("search.advanced.statuses.single_user"), + value: "single_user" + } + ]; + + this.postTimeOptions = [ + { name: I18n.t("search.advanced.post.time.before"), value: "before" }, + { name: I18n.t("search.advanced.post.time.after"), value: "after" } + ]; + this._init(); - Ember.run.scheduleOnce("afterRender", () => { - this._update(); - }); + + Ember.run.scheduleOnce("afterRender", () => this._update()); }, @observes("searchTerm") diff --git a/app/assets/javascripts/discourse/components/share-popup.js.es6 b/app/assets/javascripts/discourse/components/share-popup.js.es6 index fe9bd26af33..669f0c95974 100644 --- a/app/assets/javascripts/discourse/components/share-popup.js.es6 +++ b/app/assets/javascripts/discourse/components/share-popup.js.es6 @@ -88,69 +88,92 @@ export default Ember.Component.extend({ Ember.run.scheduleOnce("afterRender", this, this._focusUrl); }, + _mouseDownHandler(event) { + if (!this.element || this.isDestroying || this.isDestroyed) { + return; + } + + // Use mousedown instead of click so this event is handled before routing occurs when a + // link is clicked (which is a click event) while the share dialog is showing. + if ($(this.element).has(event.target).length !== 0) { + return; + } + + this.send("close"); + + return true; + }, + + _clickHandler(event) { + if (!this.element || this.isDestroying || this.isDestroyed) { + return; + } + + // if they want to open in a new tab, let it so + if (wantsNewWindow(event)) { + return true; + } + + event.preventDefault(); + + const $currentTarget = $(event.currentTarget); + const url = $currentTarget.data("share-url"); + const postNumber = $currentTarget.data("post-number"); + const postId = $currentTarget.closest("article").data("post-id"); + const date = $currentTarget.children().data("time"); + + this.setProperties({ postNumber, date, postId }); + + // use native webshare only when the user clicks on the "chain" icon + if (!$currentTarget.hasClass("post-date")) { + nativeShare({ url }).then(null, () => this._showUrl($currentTarget, url)); + } else { + this._showUrl($currentTarget, url); + } + + return false; + }, + + _keydownHandler(event) { + if (!this.element || this.isDestroying || this.isDestroyed) { + return; + } + + if (event.keyCode === 27) { + this.send("close"); + } + }, + + _shareUrlHandler(url, $target) { + this._showUrl($target, url); + }, + didInsertElement() { this._super(...arguments); const $html = $("html"); - $html.on("mousedown.outside-share-link", e => { - // Use mousedown instead of click so this event is handled before routing occurs when a - // link is clicked (which is a click event) while the share dialog is showing. - if (this.$().has(e.target).length !== 0) { - return; - } - this.send("close"); - return true; - }); + $html.on("mousedown.outside-share-link", this._mouseDownHandler.bind(this)); $html.on( "click.discourse-share-link", "button[data-share-url], .post-info .post-date[data-share-url]", - e => { - // if they want to open in a new tab, let it so - if (wantsNewWindow(e)) { - return true; - } - - e.preventDefault(); - - const $currentTarget = $(e.currentTarget); - const url = $currentTarget.data("share-url"); - const postNumber = $currentTarget.data("post-number"); - const postId = $currentTarget.closest("article").data("post-id"); - const date = $currentTarget.children().data("time"); - - this.setProperties({ postNumber, date, postId }); - - // use native webshare only when the user clicks on the "chain" icon - if (!$currentTarget.hasClass("post-date")) { - nativeShare({ url }).then(null, () => - this._showUrl($currentTarget, url) - ); - } else { - this._showUrl($currentTarget, url); - } - - return false; - } + this._clickHandler.bind(this) ); - $html.on("keydown.share-view", e => { - if (e.keyCode === 27) { - this.send("close"); - } - }); + $html.on("keydown.share-view", this._keydownHandler); - this.appEvents.on("share:url", (url, $target) => - this._showUrl($target, url) - ); + this.appEvents.on("share:url", this._shareUrlHandler); }, willDestroyElement() { this._super(...arguments); + $("html") - .off("click.discourse-share-link") - .off("mousedown.outside-share-link") - .off("keydown.share-view"); + .off("click.discourse-share-link", this._clickHandler) + .off("mousedown.outside-share-link", this._mouseDownHandler) + .off("keydown.share-view", this._keydownHandler); + + this.appEvents.off("share:url", this._shareUrlHandler); }, actions: { diff --git a/app/assets/javascripts/discourse/components/tags-admin-dropdown.js.es6 b/app/assets/javascripts/discourse/components/tags-admin-dropdown.js.es6 index 2a65b6705f3..85e8caf0250 100644 --- a/app/assets/javascripts/discourse/components/tags-admin-dropdown.js.es6 +++ b/app/assets/javascripts/discourse/components/tags-admin-dropdown.js.es6 @@ -5,9 +5,14 @@ export default DropdownSelectBoxComponent.extend({ classNames: "tags-admin-dropdown", showFullTitle: false, allowInitialValueMutation: false, - headerIcon: ["bars", "caret-down"], actionsMapping: null, + init() { + this._super(...arguments); + + this.headerIcon = ["bars", "caret-down"]; + }, + autoHighlight() {}, computeContent() { diff --git a/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 b/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 index a3089dfc8a8..13757e678e0 100644 --- a/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 +++ b/app/assets/javascripts/discourse/controllers/grant-badge.js.es6 @@ -13,8 +13,13 @@ export default Ember.Controller.extend( loading: true, saving: false, selectedBadgeId: null, - allBadges: [], - userBadges: [], + + init() { + this._super(...arguments); + + this.allBadges = []; + this.userBadges = []; + }, @computed("topicController.selectedPosts") post() { diff --git a/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 b/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 index 3652ca1c038..77929ebfc89 100644 --- a/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/move-to-topic.js.es6 @@ -16,9 +16,19 @@ export default Ember.Controller.extend(ModalFunctionality, { existingTopic: Ember.computed.equal("selection", "existing_topic"), newMessage: Ember.computed.equal("selection", "new_message"), existingMessage: Ember.computed.equal("selection", "existing_message"), - moveTypes: ["newTopic", "existingTopic", "newMessage", "existingMessage"], participants: null, + init() { + this._super(...arguments); + + this.saveAttrNames = [ + "newTopic", + "existingTopic", + "newMessage", + "existingMessage" + ]; + }, + topicController: Ember.inject.controller("topic"), selectedPostsCount: Ember.computed.alias( "topicController.selectedPostsCount" diff --git a/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 index 7c10170df61..c0a7fc4feb0 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/account.js.es6 @@ -16,7 +16,11 @@ export default Ember.Controller.extend( CanCheckEmails, PreferencesTabController, { - saveAttrNames: ["name", "title"], + init() { + this._super(...arguments); + + this.saveAttrNames = ["name", "title"]; + }, canEditName: setting("enable_names"), canSaveUser: true, diff --git a/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 index 76ee9b22f5a..0be1508dae6 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/categories.js.es6 @@ -3,12 +3,16 @@ import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend(PreferencesTabController, { - saveAttrNames: [ - "muted_category_ids", - "watched_category_ids", - "tracked_category_ids", - "watched_first_post_category_ids" - ], + init() { + this._super(...arguments); + + this.saveAttrNames = [ + "muted_category_ids", + "watched_category_ids", + "tracked_category_ids", + "watched_first_post_category_ids" + ]; + }, @computed( "model.watchedCategories", diff --git a/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 index 57a81e56af3..2db23b6f4da 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/emails.js.es6 @@ -18,17 +18,45 @@ export default Ember.Controller.extend(PreferencesTabController, { EMAIL_LEVELS.ONLY_WHEN_AWAY ), - saveAttrNames: [ - "email_level", - "email_messages_level", - "mailing_list_mode", - "mailing_list_mode_frequency", - "email_digests", - "email_in_reply_to", - "email_previous_replies", - "digest_after_minutes", - "include_tl0_in_digests" - ], + init() { + this._super(...arguments); + + this.saveAttrNames = [ + "email_level", + "email_messages_level", + "mailing_list_mode", + "mailing_list_mode_frequency", + "email_digests", + "email_in_reply_to", + "email_previous_replies", + "digest_after_minutes", + "include_tl0_in_digests" + ]; + + this.previousRepliesOptions = [ + { name: I18n.t("user.email_previous_replies.always"), value: 0 }, + { name: I18n.t("user.email_previous_replies.unless_emailed"), value: 1 }, + { name: I18n.t("user.email_previous_replies.never"), value: 2 } + ]; + + this.emailLevelOptions = [ + { name: I18n.t("user.email_level.always"), value: EMAIL_LEVELS.ALWAYS }, + { + name: I18n.t("user.email_level.only_when_away"), + value: EMAIL_LEVELS.ONLY_WHEN_AWAY + }, + { name: I18n.t("user.email_level.never"), value: EMAIL_LEVELS.NEVER } + ]; + + this.digestFrequencies = [ + { name: I18n.t("user.email_digests.every_30_minutes"), value: 30 }, + { name: I18n.t("user.email_digests.every_hour"), value: 60 }, + { name: I18n.t("user.email_digests.daily"), value: 1440 }, + { name: I18n.t("user.email_digests.weekly"), value: 10080 }, + { name: I18n.t("user.email_digests.every_month"), value: 43200 }, + { name: I18n.t("user.email_digests.every_six_months"), value: 259200 } + ]; + }, @computed() frequencyEstimate() { @@ -50,30 +78,6 @@ export default Ember.Controller.extend(PreferencesTabController, { ]; }, - previousRepliesOptions: [ - { name: I18n.t("user.email_previous_replies.always"), value: 0 }, - { name: I18n.t("user.email_previous_replies.unless_emailed"), value: 1 }, - { name: I18n.t("user.email_previous_replies.never"), value: 2 } - ], - - emailLevelOptions: [ - { name: I18n.t("user.email_level.always"), value: EMAIL_LEVELS.ALWAYS }, - { - name: I18n.t("user.email_level.only_when_away"), - value: EMAIL_LEVELS.ONLY_WHEN_AWAY - }, - { name: I18n.t("user.email_level.never"), value: EMAIL_LEVELS.NEVER } - ], - - digestFrequencies: [ - { name: I18n.t("user.email_digests.every_30_minutes"), value: 30 }, - { name: I18n.t("user.email_digests.every_hour"), value: 60 }, - { name: I18n.t("user.email_digests.daily"), value: 1440 }, - { name: I18n.t("user.email_digests.weekly"), value: 10080 }, - { name: I18n.t("user.email_digests.every_month"), value: 43200 }, - { name: I18n.t("user.email_digests.every_six_months"), value: 259200 } - ], - @computed() emailFrequencyInstructions() { if (this.siteSettings.email_time_window_mins) { diff --git a/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 index 108011c977a..77690846d5b 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/notifications.js.es6 @@ -3,67 +3,89 @@ import { NotificationLevels } from "discourse/lib/notification-levels"; import { popupAjaxError } from "discourse/lib/ajax-error"; export default Ember.Controller.extend(PreferencesTabController, { - saveAttrNames: [ - "muted_usernames", - "ignored_usernames", - "new_topic_duration_minutes", - "auto_track_topics_after_msecs", - "notification_level_when_replying", - "like_notification_frequency", - "allow_private_messages" - ], + init() { + this._super(...arguments); - likeNotificationFrequencies: [ - { name: I18n.t("user.like_notification_frequency.always"), value: 0 }, - { - name: I18n.t("user.like_notification_frequency.first_time_and_daily"), - value: 1 - }, - { name: I18n.t("user.like_notification_frequency.first_time"), value: 2 }, - { name: I18n.t("user.like_notification_frequency.never"), value: 3 } - ], + this.saveAttrNames = [ + "muted_usernames", + "ignored_usernames", + "new_topic_duration_minutes", + "auto_track_topics_after_msecs", + "notification_level_when_replying", + "like_notification_frequency", + "allow_private_messages" + ]; - autoTrackDurations: [ - { name: I18n.t("user.auto_track_options.never"), value: -1 }, - { name: I18n.t("user.auto_track_options.immediately"), value: 0 }, - { name: I18n.t("user.auto_track_options.after_30_seconds"), value: 30000 }, - { name: I18n.t("user.auto_track_options.after_1_minute"), value: 60000 }, - { name: I18n.t("user.auto_track_options.after_2_minutes"), value: 120000 }, - { name: I18n.t("user.auto_track_options.after_3_minutes"), value: 180000 }, - { name: I18n.t("user.auto_track_options.after_4_minutes"), value: 240000 }, - { name: I18n.t("user.auto_track_options.after_5_minutes"), value: 300000 }, - { name: I18n.t("user.auto_track_options.after_10_minutes"), value: 600000 } - ], + this.likeNotificationFrequencies = [ + { name: I18n.t("user.like_notification_frequency.always"), value: 0 }, + { + name: I18n.t("user.like_notification_frequency.first_time_and_daily"), + value: 1 + }, + { name: I18n.t("user.like_notification_frequency.first_time"), value: 2 }, + { name: I18n.t("user.like_notification_frequency.never"), value: 3 } + ]; - notificationLevelsForReplying: [ - { - name: I18n.t("topic.notifications.watching.title"), - value: NotificationLevels.WATCHING - }, - { - name: I18n.t("topic.notifications.tracking.title"), - value: NotificationLevels.TRACKING - }, - { - name: I18n.t("topic.notifications.regular.title"), - value: NotificationLevels.REGULAR - } - ], + this.autoTrackDurations = [ + { name: I18n.t("user.auto_track_options.never"), value: -1 }, + { name: I18n.t("user.auto_track_options.immediately"), value: 0 }, + { + name: I18n.t("user.auto_track_options.after_30_seconds"), + value: 30000 + }, + { name: I18n.t("user.auto_track_options.after_1_minute"), value: 60000 }, + { + name: I18n.t("user.auto_track_options.after_2_minutes"), + value: 120000 + }, + { + name: I18n.t("user.auto_track_options.after_3_minutes"), + value: 180000 + }, + { + name: I18n.t("user.auto_track_options.after_4_minutes"), + value: 240000 + }, + { + name: I18n.t("user.auto_track_options.after_5_minutes"), + value: 300000 + }, + { + name: I18n.t("user.auto_track_options.after_10_minutes"), + value: 600000 + } + ]; - considerNewTopicOptions: [ - { name: I18n.t("user.new_topic_duration.not_viewed"), value: -1 }, - { name: I18n.t("user.new_topic_duration.after_1_day"), value: 60 * 24 }, - { name: I18n.t("user.new_topic_duration.after_2_days"), value: 60 * 48 }, - { - name: I18n.t("user.new_topic_duration.after_1_week"), - value: 7 * 60 * 24 - }, - { - name: I18n.t("user.new_topic_duration.after_2_weeks"), - value: 2 * 7 * 60 * 24 - }, - { name: I18n.t("user.new_topic_duration.last_here"), value: -2 } - ], + this.notificationLevelsForReplying = [ + { + name: I18n.t("topic.notifications.watching.title"), + value: NotificationLevels.WATCHING + }, + { + name: I18n.t("topic.notifications.tracking.title"), + value: NotificationLevels.TRACKING + }, + { + name: I18n.t("topic.notifications.regular.title"), + value: NotificationLevels.REGULAR + } + ]; + + this.considerNewTopicOptions = [ + { name: I18n.t("user.new_topic_duration.not_viewed"), value: -1 }, + { name: I18n.t("user.new_topic_duration.after_1_day"), value: 60 * 24 }, + { name: I18n.t("user.new_topic_duration.after_2_days"), value: 60 * 48 }, + { + name: I18n.t("user.new_topic_duration.after_1_week"), + value: 7 * 60 * 24 + }, + { + name: I18n.t("user.new_topic_duration.after_2_weeks"), + value: 2 * 7 * 60 * 24 + }, + { name: I18n.t("user.new_topic_duration.last_here"), value: -2 } + ]; + }, actions: { save() { diff --git a/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 index c806d4a169f..5d1dde4b760 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/profile.js.es6 @@ -4,16 +4,20 @@ import { popupAjaxError } from "discourse/lib/ajax-error"; import { cookAsync } from "discourse/lib/text"; export default Ember.Controller.extend(PreferencesTabController, { - saveAttrNames: [ - "bio_raw", - "website", - "location", - "custom_fields", - "user_fields", - "profile_background_upload_url", - "card_background_upload_url", - "date_of_birth" - ], + init() { + this._super(...arguments); + + this.saveAttrNames = [ + "bio_raw", + "website", + "location", + "custom_fields", + "user_fields", + "profile_background_upload_url", + "card_background_upload_url", + "date_of_birth" + ]; + }, @computed("model.user_fields.@each.value") userFields() { diff --git a/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 index 5f970fa9f6d..e149711bd3d 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/tags.js.es6 @@ -3,12 +3,16 @@ import { popupAjaxError } from "discourse/lib/ajax-error"; import computed from "ember-addons/ember-computed-decorators"; export default Ember.Controller.extend(PreferencesTabController, { - saveAttrNames: [ - "muted_tags", - "tracked_tags", - "watched_tags", - "watching_first_post_tags" - ], + init() { + this._super(...arguments); + + this.saveAttrNames = [ + "muted_tags", + "tracked_tags", + "watched_tags", + "watching_first_post_tags" + ]; + }, @computed( "model.watched_tags.[]", diff --git a/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 index b1174ccba47..16c7630429a 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/users.js.es6 @@ -4,10 +4,16 @@ import showModal from "discourse/lib/show-modal"; import User from "discourse/models/user"; export default Ember.Controller.extend(PreferencesTabController, { - saveAttrNames: ["muted_usernames", "ignored_usernames"], ignoredUsernames: Ember.computed.alias("model.ignored_usernames"), userIsMemberOrAbove: Ember.computed.gte("model.trust_level", 2), ignoredEnabled: Ember.computed.or("userIsMemberOrAbove", "model.staff"), + + init() { + this._super(...arguments); + + this.saveAttrNames = ["muted_usernames", "ignored_usernames"]; + }, + actions: { ignoredUsernamesChanged(previous, current) { if (current.length > previous.length) { diff --git a/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 b/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 index f8e10c2391c..d893fa5b0db 100644 --- a/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 +++ b/app/assets/javascripts/discourse/controllers/reorder-categories.js.es6 @@ -9,6 +9,12 @@ import { import Ember from "ember"; export default Ember.Controller.extend(ModalFunctionality, Ember.Evented, { + init() { + this._super(...arguments); + + this.categoriesSorting = ["position"]; + }, + @on("init") _fixOrder() { this.fixIndices(); @@ -20,7 +26,6 @@ export default Ember.Controller.extend(ModalFunctionality, Ember.Evented, { return categories.map(c => bufProxy.create({ content: c })); }, - categoriesSorting: ["position"], categoriesOrdered: Ember.computed.sort( "categoriesBuffered", "categoriesSorting" diff --git a/app/assets/javascripts/discourse/controllers/tags-index.js.es6 b/app/assets/javascripts/discourse/controllers/tags-index.js.es6 index 07bd964daf6..fa20f97f2f3 100644 --- a/app/assets/javascripts/discourse/controllers/tags-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tags-index.js.es6 @@ -4,7 +4,6 @@ import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; export default Ember.Controller.extend({ - sortProperties: ["totalCount:desc", "id"], sortedByCount: true, sortedByName: false, @@ -12,6 +11,12 @@ export default Ember.Controller.extend({ groupedByCategory: Ember.computed.notEmpty("model.extras.categories"), groupedByTagGroup: Ember.computed.notEmpty("model.extras.tag_groups"), + init() { + this._super(...arguments); + + this.sortProperties = ["totalCount:desc", "id"]; + }, + @computed("groupedByCategory", "groupedByTagGroup") otherTagsTitleKey(groupedByCategory, groupedByTagGroup) { if (!groupedByCategory && !groupedByTagGroup) { diff --git a/app/assets/javascripts/discourse/controllers/user-badges.js.es6 b/app/assets/javascripts/discourse/controllers/user-badges.js.es6 index b9bf8fedce9..9046c373bdd 100644 --- a/app/assets/javascripts/discourse/controllers/user-badges.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-badges.js.es6 @@ -2,5 +2,10 @@ export default Ember.Controller.extend({ user: Ember.inject.controller(), username: Ember.computed.alias("user.model.username_lower"), sortedBadges: Ember.computed.sort("model", "badgeSortOrder"), - badgeSortOrder: ["badge.badge_type.sort_order", "badge.name"] + + init() { + this._super(...arguments); + + this.badgeSortOrder = ["badge.badge_type.sort_order", "badge.name"]; + } }); diff --git a/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 b/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 index 35f67bc43d1..a4d822a565e 100644 --- a/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-topics-list.js.es6 @@ -6,11 +6,16 @@ export default Ember.Controller.extend({ hideCategory: false, showPosters: false, - newIncoming: [], incomingCount: 0, channel: null, tagsForUser: null, + init() { + this._super(...arguments); + + this.newIncoming = []; + }, + _showFooter: function() { this.set("application.showFooter", !this.get("model.canLoadMore")); }.observes("model.canLoadMore"), diff --git a/app/assets/javascripts/discourse/lib/screen-track.js.es6 b/app/assets/javascripts/discourse/lib/screen-track.js.es6 index 3050de3a1d5..d048c798a91 100644 --- a/app/assets/javascripts/discourse/lib/screen-track.js.es6 +++ b/app/assets/javascripts/discourse/lib/screen-track.js.es6 @@ -1,11 +1,10 @@ import { ajax } from "discourse/lib/ajax"; + // We use this class to track how long posts in a topic are on the screen. const PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3; const MAX_TRACKING_TIME = 1000 * 60 * 6; const ANON_MAX_TOPIC_IDS = 5; -const getTime = () => new Date().getTime(); - export default class { constructor(topicTrackingState, siteSettings, session, currentUser) { this.topicTrackingState = topicTrackingState; @@ -27,7 +26,7 @@ export default class { // Create an interval timer if we don't have one. if (!this._interval) { this._interval = setInterval(() => this.tick(), 1000); - $(window).on("scroll.screentrack", () => this.scrolled()); + $(window).on("scroll.screentrack", this.scrolled.bind(this)); } this._topicId = topicId; @@ -40,7 +39,7 @@ export default class { return; } - $(window).off("scroll.screentrack"); + $(window).off("scroll.screentrack", this.scrolled); this.tick(); this.flush(); this.reset(); @@ -61,7 +60,7 @@ export default class { // Reset our timers reset() { - const now = getTime(); + const now = this._getTime(); this._lastTick = now; this._lastScrolled = now; this._lastFlush = 0; @@ -75,7 +74,7 @@ export default class { } scrolled() { - this._lastScrolled = getTime(); + this._lastScrolled = this._getTime(); } registerAnonCallback(cb) { @@ -225,4 +224,8 @@ export default class { }); } } + + _getTime() { + return (this._time = this._time || new Date().getTime()); + } } diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6 index 8e05d10f94b..c40fd0f6844 100644 --- a/app/assets/javascripts/discourse/models/group.js.es6 +++ b/app/assets/javascripts/discourse/models/group.js.es6 @@ -14,7 +14,12 @@ const Group = RestModel.extend({ limit: 50, offset: 0, user_count: 0, - owners: [], + + init() { + this._super(...arguments); + + this.owners = []; + }, hasOwners: Ember.computed.notEmpty("owners"), diff --git a/app/assets/javascripts/discourse/models/site.js.es6 b/app/assets/javascripts/discourse/models/site.js.es6 index 246aaec63e4..1089956d6c0 100644 --- a/app/assets/javascripts/discourse/models/site.js.es6 +++ b/app/assets/javascripts/discourse/models/site.js.es6 @@ -8,6 +8,12 @@ import PreloadStore from "preload-store"; const Site = RestModel.extend({ isReadOnly: Ember.computed.alias("is_readonly"), + init() { + this._super(...arguments); + + this.topicCountDesc = ["topic_count:desc"]; + }, + @computed("notification_types") notificationLookup(notificationTypes) { const result = []; @@ -24,7 +30,6 @@ const Site = RestModel.extend({ return postActionTypes.filterBy("is_flag", true); }, - topicCountDesc: ["topic_count:desc"], categoriesByCount: Ember.computed.sort("categories", "topicCountDesc"), collectUserFields(fields) { diff --git a/app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 b/app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 index 0b20921ea40..5b1dc108e07 100644 --- a/app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 +++ b/app/assets/javascripts/select-kit/components/categories-admin-dropdown.js.es6 @@ -5,7 +5,12 @@ export default DropdownSelectBoxComponent.extend({ classNames: "categories-admin-dropdown", showFullTitle: false, allowInitialValueMutation: false, - headerIcon: ["bars"], + + init() { + this._super(...arguments); + + this.headerIcon = ["bars"]; + }, autoHighlight() {}, diff --git a/app/assets/javascripts/select-kit/components/group-members-dropdown.js.es6 b/app/assets/javascripts/select-kit/components/group-members-dropdown.js.es6 index 41e54458474..5dc5549c585 100644 --- a/app/assets/javascripts/select-kit/components/group-members-dropdown.js.es6 +++ b/app/assets/javascripts/select-kit/components/group-members-dropdown.js.es6 @@ -2,9 +2,15 @@ import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-bo export default DropdownSelectBoxComponent.extend({ classNames: "group-members-dropdown", - headerIcon: ["bars"], showFullTitle: false, allowInitialValueMutation: false, + + init() { + this._super(...arguments); + + this.headerIcon = ["bars"]; + }, + autoHighlight() {}, computeContent() { diff --git a/app/assets/javascripts/select-kit/mixins/events.js.es6 b/app/assets/javascripts/select-kit/mixins/events.js.es6 index 39d67435489..a838ea38afd 100644 --- a/app/assets/javascripts/select-kit/mixins/events.js.es6 +++ b/app/assets/javascripts/select-kit/mixins/events.js.es6 @@ -18,137 +18,149 @@ export default Ember.Mixin.create({ willDestroyElement() { this._super(...arguments); - $(document).off("mousedown.select-kit"); + $(document).off("mousedown.select-kit", this._mouseDownHandler); if (this.$header().length) { this.$header() - .off("blur.select-kit") - .off("focus.select-kit") - .off("keypress.select-kit") - .off("keydown.select-kit"); + .off("blur.select-kit", this._blurHeaderHandler) + .off("focus.select-kit", this._focusHeaderHandler) + .off("keydown.select-kit", this._keydownHeaderHandler) + .off("keypress.select-kit", this._keypressHeaderHandler); } if (this.$filterInput().length) { this.$filterInput() - .off("change.select-kit") - .off("keydown.select-kit") - .off("keypress.select-kit") - .off("focusout.select-kit"); + .off("change.select-kit", this._changeFilterInputHandler) + .off("keydown.select-kit", this._keydownFilterInputHandler) + .off("keypress.select-kit", this._keypressFilterInputHandler) + .off("focusout.select-kit", this._focusoutFilterInputHandler); } }, + _mouseDownHandler(event) { + if (!this.element || this.isDestroying || this.isDestroyed) { + return true; + } + + if (Ember.$.contains(this.element, event.target)) { + event.stopPropagation(); + if (!this.renderedBodyOnce) return; + if (!this.isFocused) return; + } else { + this.didClickOutside(event); + } + }, + + _blurHeaderHandler() { + if (!this.isExpanded && this.isFocused) { + this.close(); + } + }, + + _focusHeaderHandler(event) { + this.set("isFocused", true); + this._destroyEvent(event); + }, + + _keydownHeaderHandler(event) { + if (document.activeElement !== this.$header()[0]) return event; + + const keyCode = event.keyCode || event.which; + + if (keyCode === this.keys.TAB && event.shiftKey) { + this.unfocus(event); + } + if (keyCode === this.keys.TAB && !event.shiftKey) this.tabFromHeader(event); + if (Ember.isEmpty(this.filter) && keyCode === this.keys.BACKSPACE) + this.backspaceFromHeader(event); + if (keyCode === this.keys.ESC) this.escapeFromHeader(event); + if (keyCode === this.keys.ENTER) this.enterFromHeader(event); + if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) + this.upAndDownFromHeader(event); + if ( + Ember.isEmpty(this.filter) && + [this.keys.LEFT, this.keys.RIGHT].includes(keyCode) + ) { + this.leftAndRightFromHeader(event); + } + return event; + }, + + _keypressHeaderHandler(event) { + const keyCode = event.keyCode || event.which; + + if (keyCode === this.keys.ENTER) return true; + if (keyCode === this.keys.TAB) return true; + + this.expand(event); + + if (this.filterable || this.autoFilterable) { + this.set("renderedFilterOnce", true); + } + + Ember.run.schedule("afterRender", () => { + this.$filterInput() + .focus() + .val(this.$filterInput().val() + String.fromCharCode(keyCode)); + }); + + return false; + }, + + _keydownFilterInputHandler(event) { + const keyCode = event.keyCode || event.which; + + if ( + Ember.isEmpty(this.filter) && + keyCode === this.keys.BACKSPACE && + typeof this.didPressBackspaceFromFilter === "function" + ) { + this.didPressBackspaceFromFilter(event); + } + + if (keyCode === this.keys.TAB && event.shiftKey) { + this.unfocus(event); + } + if (keyCode === this.keys.TAB && !event.shiftKey) this.tabFromFilter(event); + if (keyCode === this.keys.ESC) this.escapeFromFilter(event); + if (keyCode === this.keys.ENTER) this.enterFromFilter(event); + if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) + this.upAndDownFromFilter(event); + + if ( + Ember.isEmpty(this.filter) && + [this.keys.LEFT, this.keys.RIGHT].includes(keyCode) + ) { + this.leftAndRightFromFilter(event); + } + }, + + _changeFilterInputHandler(event) { + this.send("onFilterComputedContent", $(event.target).val()); + }, + _keypressFilterInputHandler(event) { + event.stopPropagation(); + }, + _focusoutFilterInputHandler(event) { + this.onFilterInputFocusout(event); + }, + didInsertElement() { this._super(...arguments); - $(document).on("mousedown.select-kit", event => { - if (!this.element || this.isDestroying || this.isDestroyed) { - return true; - } - - if (Ember.$.contains(this.element, event.target)) { - event.stopPropagation(); - if (!this.renderedBodyOnce) return; - if (!this.isFocused) return; - } else { - this.didClickOutside(event); - } - - return true; - }); + $(document).on("mousedown.select-kit", this._mouseDownHandler); this.$header() - .on("blur.select-kit", () => { - if (!this.isExpanded && this.isFocused) { - this.close(); - } - }) - .on("focus.select-kit", event => { - this.set("isFocused", true); - this._destroyEvent(event); - }) - .on("keydown.select-kit", event => { - if (document.activeElement !== this.$header()[0]) return event; - - const keyCode = event.keyCode || event.which; - - if (keyCode === this.keys.TAB && event.shiftKey) { - this.unfocus(event); - } - if (keyCode === this.keys.TAB && !event.shiftKey) - this.tabFromHeader(event); - if (Ember.isEmpty(this.filter) && keyCode === this.keys.BACKSPACE) - this.backspaceFromHeader(event); - if (keyCode === this.keys.ESC) this.escapeFromHeader(event); - if (keyCode === this.keys.ENTER) this.enterFromHeader(event); - if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) - this.upAndDownFromHeader(event); - if ( - Ember.isEmpty(this.filter) && - [this.keys.LEFT, this.keys.RIGHT].includes(keyCode) - ) { - this.leftAndRightFromHeader(event); - } - return event; - }) - .on("keypress.select-kit", event => { - const keyCode = event.keyCode || event.which; - - if (keyCode === this.keys.ENTER) return true; - if (keyCode === this.keys.TAB) return true; - - this.expand(event); - - if (this.filterable || this.autoFilterable) { - this.set("renderedFilterOnce", true); - } - - Ember.run.schedule("afterRender", () => { - this.$filterInput() - .focus() - .val(this.$filterInput().val() + String.fromCharCode(keyCode)); - }); - - return false; - }); + .on("blur.select-kit", this._blurHeaderHandler.bind(this)) + .on("focus.select-kit", this._focusHeaderHandler.bind(this)) + .on("keydown.select-kit", this._keydownHeaderHandler.bind(this)) + .on("keypress.select-kit", this._keypressHeaderHandler); this.$filterInput() - .on("change.select-kit", event => { - this.send("onFilterComputedContent", $(event.target).val()); - }) - .on("keypress.select-kit", event => { - event.stopPropagation(); - }) - .on("focusout.select-kit", event => { - this.onFilterInputFocusout(event); - }) - .on("keydown.select-kit", event => { - const keyCode = event.keyCode || event.which; - - if ( - Ember.isEmpty(this.filter) && - keyCode === this.keys.BACKSPACE && - typeof this.didPressBackspaceFromFilter === "function" - ) { - this.didPressBackspaceFromFilter(event); - } - - if (keyCode === this.keys.TAB && event.shiftKey) { - this.unfocus(event); - } - if (keyCode === this.keys.TAB && !event.shiftKey) - this.tabFromFilter(event); - if (keyCode === this.keys.ESC) this.escapeFromFilter(event); - if (keyCode === this.keys.ENTER) this.enterFromFilter(event); - if ([this.keys.UP, this.keys.DOWN].includes(keyCode)) - this.upAndDownFromFilter(event); - - if ( - Ember.isEmpty(this.filter) && - [this.keys.LEFT, this.keys.RIGHT].includes(keyCode) - ) { - this.leftAndRightFromFilter(event); - } - }); + .on("change.select-kit", this._changeFilterInputHandler.bind(this)) + .on("keypress.select-kit", this._keypressFilterInputHandler) + .on("focusout.select-kit", this._focusoutFilterInputHandler.bind(this)) + .on("keydown.select-kit", this._keydownFilterInputHandler.bind(this)); }, didPressTab(event) { diff --git a/test/javascripts/components/keyboard-shortcuts-test.js.es6 b/test/javascripts/components/keyboard-shortcuts-test.js.es6 index 3ae296bbed9..d7f60a85c04 100644 --- a/test/javascripts/components/keyboard-shortcuts-test.js.es6 +++ b/test/javascripts/components/keyboard-shortcuts-test.js.es6 @@ -64,6 +64,7 @@ QUnit.module("lib:keyboard-shortcuts", { afterEach() { $("#qunit-scratch").html(""); + testMouseTrap = undefined; } }); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index bbfaac9d90d..14d79bb4072 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -65,8 +65,6 @@ d.write( "" ); -Ember.Test.adapter = window.QUnitAdapter.create(); - Discourse.rootElement = "#ember-testing"; Discourse.setupForTesting(); Discourse.injectTestHelpers(); diff --git a/vendor/assets/javascripts/caret_position.js b/vendor/assets/javascripts/caret_position.js index f811f7c073a..ea84372906b 100644 --- a/vendor/assets/javascripts/caret_position.js +++ b/vendor/assets/javascripts/caret_position.js @@ -2,28 +2,27 @@ // except for the little snippet from StackOverflow // // http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea -var clone, getCaret; -getCaret = function(el) { - var r, rc, re; - if (el.selectionStart) { - return el.selectionStart; - } else if (document.selection) { - el.focus(); - r = document.selection.createRange(); - if (!r) return 0; - re = el.createTextRange(); - rc = re.duplicate(); - re.moveToBookmark(r.getBookmark()); - rc.setEndPoint("EndToStart", re); - return rc.text.length; - } - return 0; -}; +var clone = null; -clone = null; +$.fn.caret = function(elem) { + var getCaret = function(el) { + var r, rc, re; + if (el.selectionStart) { + return el.selectionStart; + } else if (document.selection) { + el.focus(); + r = document.selection.createRange(); + if (!r) return 0; + re = el.createTextRange(); + rc = re.duplicate(); + re.moveToBookmark(r.getBookmark()); + rc.setEndPoint("EndToStart", re); + return rc.text.length; + } + return 0; + }; -$.fn.caret = function() { - return getCaret(this[0]); + return getCaret(elem || this[0]); }; /** @@ -99,7 +98,7 @@ $.fn.caretPosition = function(options) { pos = options && (options.pos || options.pos === 0) ? options.pos - : getCaret(textarea[0]); + : $.caret(textarea[0]); val = textarea.val().replace("\r", ""); if (options && options.key) {