diff --git a/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 b/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 index bccec30932774e..d10280daf7e0f4 100644 --- a/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 +++ b/app/assets/javascripts/admin/components/admin-user-field-item.js.es6 @@ -1,13 +1,14 @@ -import { bufferedProperty } from 'discourse/mixins/buffered-content'; import UserField from 'admin/models/user-field'; +import { bufferedProperty } from 'discourse/mixins/buffered-content'; import { popupAjaxError } from 'discourse/lib/ajax-error'; +import { propertyEqual } from 'discourse/lib/computed'; export default Ember.Component.extend(bufferedProperty('userField'), { editing: Ember.computed.empty('userField.id'), classNameBindings: [':user-field'], - cantMoveUp: Discourse.computed.propertyEqual('userField', 'firstField'), - cantMoveDown: Discourse.computed.propertyEqual('userField', 'lastField'), + cantMoveUp: propertyEqual('userField', 'firstField'), + cantMoveDown: propertyEqual('userField', 'lastField'), userFieldsDescription: function() { return I18n.t('admin.user_fields.description'); diff --git a/app/assets/javascripts/admin/components/site-setting.js.es6 b/app/assets/javascripts/admin/components/site-setting.js.es6 index d56d1f2e8df6b1..10925e8a2e3c5e 100644 --- a/app/assets/javascripts/admin/components/site-setting.js.es6 +++ b/app/assets/javascripts/admin/components/site-setting.js.es6 @@ -1,13 +1,14 @@ import BufferedContent from 'discourse/mixins/buffered-content'; import ScrollTop from 'discourse/mixins/scroll-top'; import SiteSetting from 'admin/models/site-setting'; +import { propertyNotEqual } from 'discourse/lib/computed'; const CustomTypes = ['bool', 'enum', 'list', 'url_list', 'host_list']; export default Ember.Component.extend(BufferedContent, ScrollTop, { classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'], content: Ember.computed.alias('setting'), - dirty: Discourse.computed.propertyNotEqual('buffered.value', 'setting.value'), + dirty: propertyNotEqual('buffered.value', 'setting.value'), validationMessage: null, preview: function() { diff --git a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 index ac648462b263fa..15ba6bc01143c2 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 @@ -1,5 +1,6 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; import BufferedContent from 'discourse/mixins/buffered-content'; +import { propertyNotEqual } from 'discourse/lib/computed'; export default Ember.ObjectController.extend(BufferedContent, { needs: ['admin-badges'], @@ -12,7 +13,7 @@ export default Ember.ObjectController.extend(BufferedContent, { protectedSystemFields: Em.computed.alias('controllers.admin-badges.protectedSystemFields'), readOnly: Ember.computed.alias('buffered.system'), - showDisplayName: Discourse.computed.propertyNotEqual('name', 'displayName'), + showDisplayName: propertyNotEqual('name', 'displayName'), canEditDescription: Em.computed.none('buffered.translatedDescription'), _resetSaving: function() { diff --git a/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 index 59d3245aa13c1e..f4e9853917843a 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-css-html-show.js.es6 @@ -1,3 +1,5 @@ +import { url } from 'discourse/lib/computed'; + const sections = ['css', 'header', 'top', 'footer', 'head-tag', 'body-tag', 'mobile-css', 'mobile-header', 'mobile-top', 'mobile-footer', 'embedded-css']; @@ -12,8 +14,8 @@ export default Ember.Controller.extend(activeSections, { maximized: false, section: null, - previewUrl: Discourse.computed.url("model.key", "/?preview-style=%@"), - downloadUrl: Discourse.computed.url('model.id', '/admin/size_customizations/%@'), + previewUrl: url("model.key", "/?preview-style=%@"), + downloadUrl: url('model.id', '/admin/size_customizations/%@'), mobile: function() { return this.get('section').startsWith('mobile-'); @@ -33,8 +35,8 @@ export default Ember.Controller.extend(activeSections, { needs: ['adminCustomizeCssHtml'], - undoPreviewUrl: Discourse.computed.url('/?preview-style='), - defaultStyleUrl: Discourse.computed.url('/?preview-style=default'), + undoPreviewUrl: url('/?preview-style='), + defaultStyleUrl: url('/?preview-style=default'), actions: { save() { diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 index ad572337e050d8..ab304adc7a8fb9 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 @@ -1,17 +1,12 @@ -/** - This controller supports the default interface when you enter the admin section. - - @class AdminDashboardController - @extends Ember.Controller - @namespace Discourse - @module Discourse -**/ +import { setting } from 'discourse/lib/computed'; + +// This controller supports the default interface when you enter the admin section. export default Ember.Controller.extend({ loading: true, versionCheck: null, problemsCheckMinutes: 1, - showVersionChecks: Discourse.computed.setting('version_checks'), + showVersionChecks: setting('version_checks'), foundProblems: function() { return(Discourse.User.currentProp('admin') && this.get('problems') && this.get('problems').length > 0); diff --git a/app/assets/javascripts/admin/controllers/admin-group.js.es6 b/app/assets/javascripts/admin/controllers/admin-group.js.es6 index 225671408494d9..21ef6139971f1f 100644 --- a/app/assets/javascripts/admin/controllers/admin-group.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-group.js.es6 @@ -1,4 +1,5 @@ import { popupAjaxError } from 'discourse/lib/ajax-error'; +import { propertyEqual } from 'discourse/lib/computed'; export default Em.ObjectController.extend({ needs: ['adminGroupsType'], @@ -15,7 +16,7 @@ export default Em.ObjectController.extend({ }.property("limit", "user_count"), showingFirst: Em.computed.lte("currentPage", 1), - showingLast: Discourse.computed.propertyEqual("currentPage", "totalPages"), + showingLast: propertyEqual("currentPage", "totalPages"), aliasLevelOptions: function() { return [ diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 index b544aafc6379d7..339f34e2471135 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -1,15 +1,16 @@ import ObjectController from 'discourse/controllers/object'; import CanCheckEmails from 'discourse/mixins/can-check-emails'; +import { propertyNotEqual, setting } from 'discourse/lib/computed'; export default ObjectController.extend(CanCheckEmails, { editingTitle: false, originalPrimaryGroupId: null, availableGroups: null, - showApproval: Discourse.computed.setting('must_approve_users'), - showBadges: Discourse.computed.setting('enable_badges'), + showApproval: setting('must_approve_users'), + showBadges: setting('enable_badges'), - primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'model.primary_group_id'), + primaryGroupDirty: propertyNotEqual('originalPrimaryGroupId', 'model.primary_group_id'), automaticGroups: function() { return this.get("model.automaticGroups").map((g) => g.name).join(", "); diff --git a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 index 708207f84ac07f..dcca2e31bab108 100644 --- a/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-users-list-show.js.es6 @@ -1,3 +1,5 @@ +import { i18n } from 'discourse/lib/computed'; + export default Ember.ArrayController.extend({ query: null, showEmails: false, @@ -9,7 +11,7 @@ export default Ember.ArrayController.extend({ queryPending: Em.computed.equal('query', 'pending'), queryHasApproval: Em.computed.or('queryNew', 'queryPending'), showApproval: Em.computed.and('siteSettings.must_approve_users', 'queryHasApproval'), - searchHint: Discourse.computed.i18n('search_hint'), + searchHint: i18n('search_hint'), hasSelection: Em.computed.gt('selectedCount', 0), selectedCount: function() { diff --git a/app/assets/javascripts/admin/models/admin-user.js.es6 b/app/assets/javascripts/admin/models/admin-user.js.es6 index 8416f5358596bd..7cda05c8202372 100644 --- a/app/assets/javascripts/admin/models/admin-user.js.es6 +++ b/app/assets/javascripts/admin/models/admin-user.js.es6 @@ -1,3 +1,4 @@ +import { propertyNotEqual } from 'discourse/lib/computed'; import { popupAjaxError } from 'discourse/lib/ajax-error'; const AdminUser = Discourse.User.extend({ @@ -144,7 +145,7 @@ const AdminUser = Discourse.User.extend({ this.set('originalTrustLevel', this.get('trust_level')); }, - dirty: Discourse.computed.propertyNotEqual('originalTrustLevel', 'trustLevel.id'), + dirty: propertyNotEqual('originalTrustLevel', 'trustLevel.id'), saveTrustLevel() { return Discourse.ajax("/admin/users/" + this.id + "/trust_level", { diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6 index e8f7f394c4db57..a28601d0ce98b1 100644 --- a/app/assets/javascripts/admin/models/report.js.es6 +++ b/app/assets/javascripts/admin/models/report.js.es6 @@ -1,7 +1,8 @@ import round from "discourse/lib/round"; +import { fmt } from 'discourse/lib/computed'; const Report = Discourse.Model.extend({ - reportUrl: Discourse.computed.fmt("type", "/admin/reports/%@"), + reportUrl: fmt("type", "/admin/reports/%@"), valueAt(numDaysAgo) { if (this.data) { diff --git a/app/assets/javascripts/admin/models/user-field.js.es6 b/app/assets/javascripts/admin/models/user-field.js.es6 index c6a1a1f6be451e..9e657f2204112c 100644 --- a/app/assets/javascripts/admin/models/user-field.js.es6 +++ b/app/assets/javascripts/admin/models/user-field.js.es6 @@ -1,9 +1,10 @@ import RestModel from 'discourse/models/rest'; +import { i18n } from 'discourse/lib/computed'; const UserField = RestModel.extend(); const UserFieldType = Ember.Object.extend({ - name: Discourse.computed.i18n('id', 'admin.user_fields.field_types.%@') + name: i18n('id', 'admin.user_fields.field_types.%@') }); UserField.reopenClass({ diff --git a/app/assets/javascripts/discourse/components/actions-summary.js.es6 b/app/assets/javascripts/discourse/components/actions-summary.js.es6 index 31c1459527cd60..21c2076aa92fcc 100644 --- a/app/assets/javascripts/discourse/components/actions-summary.js.es6 +++ b/app/assets/javascripts/discourse/components/actions-summary.js.es6 @@ -1,5 +1,6 @@ import StringBuffer from 'discourse/mixins/string-buffer'; import { iconHTML } from 'discourse/helpers/fa-icon'; +import { autoUpdatingRelativeAge } from 'discourse/lib/formatter'; export default Ember.Component.extend(StringBuffer, { tagName: 'section', @@ -57,7 +58,7 @@ export default Ember.Component.extend(StringBuffer, { buffer.push("
" + iconHTML('fa-trash-o') + ' ' + Discourse.Utilities.tinyAvatar(post.get('postDeletedBy.avatar_template'), {title: post.get('postDeletedBy.username')}) + - Discourse.Formatter.autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) + + autoUpdatingRelativeAge(new Date(post.get('postDeletedAt'))) + "
"); } }, diff --git a/app/assets/javascripts/discourse/components/category-drop.js.es6 b/app/assets/javascripts/discourse/components/category-drop.js.es6 index bb63d0bbf95d77..696991853cdf39 100644 --- a/app/assets/javascripts/discourse/components/category-drop.js.es6 +++ b/app/assets/javascripts/discourse/components/category-drop.js.es6 @@ -1,8 +1,9 @@ +import { setting } from 'discourse/lib/computed'; var get = Ember.get; export default Ember.Component.extend({ classNameBindings: ['category::no-category', 'categories:has-drop','categoryStyle'], - categoryStyle: Discourse.computed.setting('category_style'), + categoryStyle: setting('category_style'), tagName: 'li', diff --git a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 index 3bba6b1b242d4b..049157609e39d6 100644 --- a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 @@ -1,6 +1,7 @@ +import { setting } from 'discourse/lib/computed'; import { buildCategoryPanel } from 'discourse/components/edit-category-panel'; export default buildCategoryPanel('settings', { - emailInEnabled: Discourse.computed.setting('email_in'), - showPositionInput: Discourse.computed.setting('fixed_category_positions'), + emailInEnabled: setting('email_in'), + showPositionInput: setting('fixed_category_positions'), }); diff --git a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 index 72c95192ac315a..9e4706606753ff 100644 --- a/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 +++ b/app/assets/javascripts/discourse/components/edit-category-tab.js.es6 @@ -1,3 +1,5 @@ +import { propertyEqual } from 'discourse/lib/computed'; + export default Em.Component.extend({ tagName: 'li', classNameBindings: ['active', 'tabClassName'], @@ -6,7 +8,7 @@ export default Em.Component.extend({ return 'edit-category-' + this.get('tab'); }.property('tab'), - active: Discourse.computed.propertyEqual('selectedTab', 'tab'), + active: propertyEqual('selectedTab', 'tab'), title: function() { return I18n.t('category.' + this.get('tab').replace('-', '_')); diff --git a/app/assets/javascripts/discourse/components/home-logo.js.es6 b/app/assets/javascripts/discourse/components/home-logo.js.es6 index 83ca9ec8da6947..d4b429ef033e3f 100644 --- a/app/assets/javascripts/discourse/components/home-logo.js.es6 +++ b/app/assets/javascripts/discourse/components/home-logo.js.es6 @@ -1,3 +1,5 @@ +import { setting } from 'discourse/lib/computed'; + export default Ember.Component.extend({ classNames: ["title"], @@ -13,10 +15,10 @@ export default Ember.Component.extend({ return Discourse.Mobile.mobileView && !Ember.isBlank(this.get('mobileBigLogoUrl')); }.property(), - smallLogoUrl: Discourse.computed.setting('logo_small_url'), - bigLogoUrl: Discourse.computed.setting('logo_url'), - mobileBigLogoUrl: Discourse.computed.setting('mobile_logo_url'), - title: Discourse.computed.setting('title'), + smallLogoUrl: setting('logo_small_url'), + bigLogoUrl: setting('logo_url'), + mobileBigLogoUrl: setting('mobile_logo_url'), + title: setting('title'), click: function(e) { // if they want to open in a new tab, let it so diff --git a/app/assets/javascripts/discourse/components/poster-name.js.es6 b/app/assets/javascripts/discourse/components/poster-name.js.es6 index 3c5738cac473ae..5a2a7bd8eabfe8 100644 --- a/app/assets/javascripts/discourse/components/poster-name.js.es6 +++ b/app/assets/javascripts/discourse/components/poster-name.js.es6 @@ -1,6 +1,8 @@ +import { setting } from 'discourse/lib/computed'; + const PosterNameComponent = Em.Component.extend({ classNames: ['names', 'trigger-user-card'], - displayNameOnPosts: Discourse.computed.setting('display_name_on_posts'), + displayNameOnPosts: setting('display_name_on_posts'), // sanitize name for comparison sanitizeName(name){ diff --git a/app/assets/javascripts/discourse/components/small-action.js.es6 b/app/assets/javascripts/discourse/components/small-action.js.es6 index 4457c6fb498637..54ef41b9fa166b 100644 --- a/app/assets/javascripts/discourse/components/small-action.js.es6 +++ b/app/assets/javascripts/discourse/components/small-action.js.es6 @@ -1,3 +1,5 @@ +import { relativeAge } from 'discourse/lib/formatter'; + const icons = { 'closed.enabled': 'lock', 'closed.disabled': 'unlock-alt', @@ -19,7 +21,7 @@ export function actionDescription(actionCode, createdAt) { const ac = this.get(actionCode); if (ac) { const dt = new Date(this.get(createdAt)); - const when = Discourse.Formatter.relativeAge(dt, {format: 'medium-with-ago'}); + const when = relativeAge(dt, {format: 'medium-with-ago'}); return I18n.t(`action_codes.${ac}`, {when}).htmlSafe(); } }.property(actionCode, createdAt); diff --git a/app/assets/javascripts/discourse/components/stream-item.js.es6 b/app/assets/javascripts/discourse/components/stream-item.js.es6 index 9a29d8743845e6..562ac59f03ec9f 100644 --- a/app/assets/javascripts/discourse/components/stream-item.js.es6 +++ b/app/assets/javascripts/discourse/components/stream-item.js.es6 @@ -1,8 +1,9 @@ +import { propertyEqual } from 'discourse/lib/computed'; import { actionDescription } from "discourse/components/small-action"; export default Ember.Component.extend({ classNameBindings: [":item", "item.hidden", "item.deleted", "moderatorAction"], - moderatorAction: Discourse.computed.propertyEqual("item.post_type", "site.post_types.moderator_action"), + moderatorAction: propertyEqual("item.post_type", "site.post_types.moderator_action"), actionDescription: actionDescription("item.action_code", "item.created_at"), actions: { diff --git a/app/assets/javascripts/discourse/components/user-field.js.es6 b/app/assets/javascripts/discourse/components/user-field.js.es6 index 625067622e4158..86caf3b5d6605f 100644 --- a/app/assets/javascripts/discourse/components/user-field.js.es6 +++ b/app/assets/javascripts/discourse/components/user-field.js.es6 @@ -1,6 +1,8 @@ +import { fmt } from 'discourse/lib/computed'; + export default Ember.Component.extend({ classNameBindings: [':user-field', 'field.field_type'], - layoutName: Discourse.computed.fmt('field.field_type', 'components/user-fields/%@'), + layoutName: fmt('field.field_type', 'components/user-fields/%@'), noneLabel: function() { if (!this.get('field.required')) { diff --git a/app/assets/javascripts/discourse/components/user-small.js.es6 b/app/assets/javascripts/discourse/components/user-small.js.es6 index b89c5d01a47b6c..9dc06993815eea 100644 --- a/app/assets/javascripts/discourse/components/user-small.js.es6 +++ b/app/assets/javascripts/discourse/components/user-small.js.es6 @@ -1,7 +1,9 @@ +import { url } from 'discourse/lib/computed'; + export default Ember.Component.extend({ classNames: ['user-small'], - userPath: Discourse.computed.url('user.username', '/users/%@'), + userPath: url('user.username', '/users/%@'), name: function() { const name = this.get('user.name'); diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index c4f1ac21b4cf66..f724a6cbce6663 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -1,3 +1,4 @@ +import { setting } from 'discourse/lib/computed'; import Presence from 'discourse/mixins/presence'; export default Ember.ObjectController.extend(Presence, { @@ -8,7 +9,7 @@ export default Ember.ObjectController.extend(Presence, { showEditReason: false, editReason: null, - maxTitleLength: Discourse.computed.setting('max_topic_title_length'), + maxTitleLength: setting('max_topic_title_length'), scopedCategoryId: null, similarTopics: null, similarTopicsMessage: null, diff --git a/app/assets/javascripts/discourse/controllers/create-account.js.es6 b/app/assets/javascripts/discourse/controllers/create-account.js.es6 index a668d4cc88dd12..d8995ad6fefcfa 100644 --- a/app/assets/javascripts/discourse/controllers/create-account.js.es6 +++ b/app/assets/javascripts/discourse/controllers/create-account.js.es6 @@ -1,5 +1,6 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import DiscourseController from 'discourse/controllers/controller'; +import { setting } from 'discourse/lib/computed'; export default DiscourseController.extend(ModalFunctionality, { needs: ['login'], @@ -16,10 +17,10 @@ export default DiscourseController.extend(ModalFunctionality, { userFields: null, hasAuthOptions: Em.computed.notEmpty('authOptions'), - canCreateLocal: Discourse.computed.setting('enable_local_logins'), + canCreateLocal: setting('enable_local_logins'), showCreateForm: Em.computed.or('hasAuthOptions', 'canCreateLocal'), - maxUsernameLength: Discourse.computed.setting('max_username_length'), - minUsernameLength: Discourse.computed.setting('min_username_length'), + maxUsernameLength: setting('max_username_length'), + minUsernameLength: setting('min_username_length'), resetForm() { // We wrap the fields in a structure so we can assign a value diff --git a/app/assets/javascripts/discourse/controllers/directory-item.js.es6 b/app/assets/javascripts/discourse/controllers/directory-item.js.es6 index 88589824089ec9..2d09b3824f3bbf 100644 --- a/app/assets/javascripts/discourse/controllers/directory-item.js.es6 +++ b/app/assets/javascripts/discourse/controllers/directory-item.js.es6 @@ -1,3 +1,5 @@ +import { propertyEqual } from 'discourse/lib/computed'; + export default Ember.Controller.extend({ - me: Discourse.computed.propertyEqual('model.user.id', 'currentUser.id') + me: propertyEqual('model.user.id', 'currentUser.id') }); diff --git a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 index 71a316ef02ac96..ac534b96183f5c 100644 --- a/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery/topics.js.es6 @@ -1,6 +1,7 @@ import DiscoveryController from 'discourse/controllers/discovery'; import { queryParams } from 'discourse/controllers/discovery-sortable'; import BulkTopicSelection from 'discourse/mixins/bulk-topic-selection'; +import { endWith } from 'discourse/lib/computed'; const controllerOpts = { needs: ['discovery'], @@ -102,8 +103,8 @@ const controllerOpts = { hasTopics: Em.computed.gt('model.topics.length', 0), allLoaded: Em.computed.empty('model.more_topics_url'), - latest: Discourse.computed.endWith('model.filter', 'latest'), - new: Discourse.computed.endWith('model.filter', 'new'), + latest: endWith('model.filter', 'latest'), + new: endWith('model.filter', 'new'), top: Em.computed.notEmpty('period'), yearly: Em.computed.equal('period', 'yearly'), quarterly: Em.computed.equal('period', 'quarterly'), diff --git a/app/assets/javascripts/discourse/controllers/group.js.es6 b/app/assets/javascripts/discourse/controllers/group.js.es6 index b7c7c18a63b45b..dcd408673dc438 100644 --- a/app/assets/javascripts/discourse/controllers/group.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group.js.es6 @@ -1,7 +1,4 @@ -import ObjectController from 'discourse/controllers/object'; - -// The basic controller for a group -export default ObjectController.extend({ +export default Ember.Controller.extend({ counts: null, showing: null, @@ -10,4 +7,3 @@ export default ObjectController.extend({ showingIndex: Em.computed.equal('showing', 'index'), showingMembers: Em.computed.equal('showing', 'members') }); - diff --git a/app/assets/javascripts/discourse/controllers/group/members.js.es6 b/app/assets/javascripts/discourse/controllers/group/members.js.es6 index ca218875fbd6b8..794b5856a775df 100644 --- a/app/assets/javascripts/discourse/controllers/group/members.js.es6 +++ b/app/assets/javascripts/discourse/controllers/group/members.js.es6 @@ -1,11 +1,13 @@ -export default Ember.ObjectController.extend({ +export default Ember.Controller.extend({ loading: false, + limit: null, + offset: null, actions: { loadMore() { if (this.get("loading")) { return; } // we've reached the end - if (this.get("model.members.length") >= this.get("user_count")) { return; } + if (this.get("model.members.length") >= this.get("model.user_count")) { return; } this.set("loading", true); diff --git a/app/assets/javascripts/discourse/controllers/login.js.es6 b/app/assets/javascripts/discourse/controllers/login.js.es6 index 641b6bc8387f8e..6d39640e5b6c62 100644 --- a/app/assets/javascripts/discourse/controllers/login.js.es6 +++ b/app/assets/javascripts/discourse/controllers/login.js.es6 @@ -1,6 +1,7 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import DiscourseController from 'discourse/controllers/controller'; import showModal from 'discourse/lib/show-modal'; +import { setting } from 'discourse/lib/computed'; // This is happening outside of the app via popup const AuthErrors = @@ -13,7 +14,7 @@ export default DiscourseController.extend(ModalFunctionality, { loggingIn: false, loggedIn: false, - canLoginLocal: Discourse.computed.setting('enable_local_logins'), + canLoginLocal: setting('enable_local_logins'), loginRequired: Em.computed.alias('controllers.application.loginRequired'), resetForm: function() { diff --git a/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 b/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 index 4abaf1da27494c..c21ed81341eeeb 100644 --- a/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 +++ b/app/assets/javascripts/discourse/controllers/navigation/category.js.es6 @@ -1,7 +1,8 @@ import NavigationDefaultController from 'discourse/controllers/navigation/default'; +import { setting } from 'discourse/lib/computed'; export default NavigationDefaultController.extend({ - subcategoryListSetting: Discourse.computed.setting('show_subcategory_list'), + subcategoryListSetting: setting('show_subcategory_list'), showingParentCategory: Em.computed.none('category.parentCategory'), showingSubcategoryList: Em.computed.and('subcategoryListSetting', 'showingParentCategory'), diff --git a/app/assets/javascripts/discourse/controllers/notifications.js.es6 b/app/assets/javascripts/discourse/controllers/notifications.js.es6 index f0ae8ad42e74f1..e76d84e968e14e 100644 --- a/app/assets/javascripts/discourse/controllers/notifications.js.es6 +++ b/app/assets/javascripts/discourse/controllers/notifications.js.es6 @@ -1,5 +1,7 @@ +import { url } from 'discourse/lib/computed'; + export default Ember.ArrayController.extend({ needs: ['header'], loadingNotifications: Em.computed.alias('controllers.header.loadingNotifications'), - myNotificationsUrl: Discourse.computed.url('/my/notifications') + myNotificationsUrl: url('/my/notifications') }); diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6 index 0cc11e05e95ec5..cacbd4b9e1650d 100644 --- a/app/assets/javascripts/discourse/controllers/preferences.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6 @@ -1,14 +1,15 @@ +import { setting } from 'discourse/lib/computed'; import ObjectController from 'discourse/controllers/object'; import CanCheckEmails from 'discourse/mixins/can-check-emails'; import { popupAjaxError } from 'discourse/lib/ajax-error'; export default ObjectController.extend(CanCheckEmails, { - allowAvatarUpload: Discourse.computed.setting('allow_uploaded_avatars'), - allowUserLocale: Discourse.computed.setting('allow_user_locale'), - ssoOverridesAvatar: Discourse.computed.setting('sso_overrides_avatar'), - allowBackgrounds: Discourse.computed.setting('allow_profile_backgrounds'), - editHistoryVisible: Discourse.computed.setting('edit_history_visible_to_public'), + allowAvatarUpload: setting('allow_uploaded_avatars'), + allowUserLocale: setting('allow_user_locale'), + ssoOverridesAvatar: setting('sso_overrides_avatar'), + allowBackgrounds: setting('allow_profile_backgrounds'), + editHistoryVisible: setting('edit_history_visible_to_public'), selectedCategories: function(){ return [].concat(this.get("model.watchedCategories"), @@ -40,7 +41,7 @@ export default ObjectController.extend(CanCheckEmails, { cannotDeleteAccount: Em.computed.not('can_delete_account'), deleteDisabled: Em.computed.or('saving', 'deleting', 'cannotDeleteAccount'), - canEditName: Discourse.computed.setting('enable_names'), + canEditName: setting('enable_names'), nameInstructions: function() { return I18n.t(Discourse.SiteSettings.full_name_required ? 'user.name.instructions_required' : 'user.name.instructions'); diff --git a/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 index 50ee7857d2ca37..547a9adbd7ea9f 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/email.js.es6 @@ -1,13 +1,6 @@ +import { propertyEqual } from 'discourse/lib/computed'; import ObjectController from 'discourse/controllers/object'; -/** - This controller supports actions related to updating one's email address - - @class PreferencesEmailController - @extends ObjectController - @namespace Discourse - @module Discourse -**/ export default ObjectController.extend({ taken: false, saving: false, @@ -17,7 +10,7 @@ export default ObjectController.extend({ newEmailEmpty: Em.computed.empty('newEmail'), saveDisabled: Em.computed.or('saving', 'newEmailEmpty', 'taken', 'unchanged'), - unchanged: Discourse.computed.propertyEqual('newEmailLower', 'email'), + unchanged: propertyEqual('newEmailLower', 'email'), newEmailLower: function() { return this.get('newEmail').toLowerCase(); diff --git a/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 b/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 index ed6699ad4a676d..f74250976bd435 100644 --- a/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences/username.js.es6 @@ -1,3 +1,4 @@ +import { setting, propertyEqual } from 'discourse/lib/computed'; import Presence from 'discourse/mixins/presence'; import ObjectController from 'discourse/controllers/object'; @@ -8,11 +9,11 @@ export default ObjectController.extend(Presence, { errorMessage: null, newUsername: null, - maxLength: Discourse.computed.setting('max_username_length'), - minLength: Discourse.computed.setting('min_username_length'), + maxLength: setting('max_username_length'), + minLength: setting('min_username_length'), newUsernameEmpty: Em.computed.empty('newUsername'), saveDisabled: Em.computed.or('saving', 'newUsernameEmpty', 'taken', 'unchanged', 'errorMessage'), - unchanged: Discourse.computed.propertyEqual('newUsername', 'username'), + unchanged: propertyEqual('newUsername', 'username'), checkTaken: function() { if( this.get('newUsername') && this.get('newUsername').length < this.get('minLength') ) { diff --git a/app/assets/javascripts/discourse/controllers/queued-post.js.es6 b/app/assets/javascripts/discourse/controllers/queued-post.js.es6 index 100b0b158664f8..a285537491e4ff 100644 --- a/app/assets/javascripts/discourse/controllers/queued-post.js.es6 +++ b/app/assets/javascripts/discourse/controllers/queued-post.js.es6 @@ -1,3 +1,4 @@ +import { propertyEqual } from 'discourse/lib/computed'; import BufferedContent from 'discourse/mixins/buffered-content'; import { popupAjaxError } from 'discourse/lib/ajax-error'; @@ -21,7 +22,7 @@ export default Ember.Controller.extend(BufferedContent, { post: Ember.computed.alias('model'), currentlyEditing: Ember.computed.alias('controllers.queued-posts.editing'), - editing: Discourse.computed.propertyEqual('model', 'currentlyEditing'), + editing: propertyEqual('model', 'currentlyEditing'), _confirmDelete: updateState('rejected', {deleteUser: true}), diff --git a/app/assets/javascripts/discourse/controllers/share.js.es6 b/app/assets/javascripts/discourse/controllers/share.js.es6 index 2e662dc217a3ff..fa1c3ff390a947 100644 --- a/app/assets/javascripts/discourse/controllers/share.js.es6 +++ b/app/assets/javascripts/discourse/controllers/share.js.es6 @@ -1,11 +1,12 @@ import Sharing from 'discourse/lib/sharing'; +import { longDateNoYear } from 'discourse/lib/formatter'; export default Ember.Controller.extend({ needs: ['topic'], title: Ember.computed.alias('controllers.topic.model.title'), displayDate: function() { - return Discourse.Formatter.longDateNoYear(new Date(this.get('date'))); + return longDateNoYear(new Date(this.get('date'))); }.property('date'), // Close the share controller diff --git a/app/assets/javascripts/discourse/controllers/site-map.js.es6 b/app/assets/javascripts/discourse/controllers/site-map.js.es6 index af9ccd08c4578f..61192eb575da89 100644 --- a/app/assets/javascripts/discourse/controllers/site-map.js.es6 +++ b/app/assets/javascripts/discourse/controllers/site-map.js.es6 @@ -1,3 +1,5 @@ +import { url } from 'discourse/lib/computed'; + export default Ember.ArrayController.extend({ needs: ['application', 'header'], @@ -8,7 +10,7 @@ export default Ember.ArrayController.extend({ return Discourse.SiteSettings.faq_url ? Discourse.SiteSettings.faq_url : Discourse.getURL('/faq'); }.property(), - badgesUrl: Discourse.computed.url('/badges'), + badgesUrl: url('/badges'), showKeyboardShortcuts: function(){ return !Discourse.Mobile.mobileView && !this.capabilities.touch; diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index 7dbce6dbb417b5..dc74e0d08fd79f 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -3,6 +3,7 @@ import BufferedContent from 'discourse/mixins/buffered-content'; import SelectedPostsCount from 'discourse/mixins/selected-posts-count'; import { spinnerHTML } from 'discourse/helpers/loading-spinner'; import Topic from 'discourse/models/topic'; +import { setting } from 'discourse/lib/computed'; export default ObjectController.extend(SelectedPostsCount, BufferedContent, { multiSelect: false, @@ -18,7 +19,7 @@ export default ObjectController.extend(SelectedPostsCount, BufferedContent, { firstPostExpanded: false, retrying: false, - maxTitleLength: Discourse.computed.setting('max_topic_title_length'), + maxTitleLength: setting('max_topic_title_length'), contextChanged: function() { this.set('controllers.search.searchContext', this.get('model.searchContext')); diff --git a/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 b/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 index edd2d569434957..be9d21dafb8662 100644 --- a/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 +++ b/app/assets/javascripts/discourse/controllers/upload-selector.js.es6 @@ -1,5 +1,6 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import DiscourseController from 'discourse/controllers/controller'; +import { setting } from 'discourse/lib/computed'; export default DiscourseController.extend(ModalFunctionality, { remote: Em.computed.not("local"), @@ -13,7 +14,7 @@ export default DiscourseController.extend(ModalFunctionality, { }); }.on('init'), - maxSize: Discourse.computed.setting('max_attachment_size_kb'), + maxSize: setting('max_attachment_size_kb'), allowLocal: Em.computed.gt('maxSize', 0), actions: { diff --git a/app/assets/javascripts/discourse/controllers/user-card.js.es6 b/app/assets/javascripts/discourse/controllers/user-card.js.es6 index 2dc7dde29f3cae..3279137dbfb064 100644 --- a/app/assets/javascripts/discourse/controllers/user-card.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-card.js.es6 @@ -1,3 +1,5 @@ +import { propertyNotEqual, setting } from 'discourse/lib/computed'; + export default Ember.Controller.extend({ needs: ['topic', 'application'], visible: false, @@ -16,10 +18,10 @@ export default Ember.Controller.extend({ viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./), viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./), showFilter: Em.computed.and('viewingTopic', 'postStream.hasNoFilters', 'enoughPostsForFiltering'), - showName: Discourse.computed.propertyNotEqual('user.name', 'user.username'), + showName: propertyNotEqual('user.name', 'user.username'), hasUserFilters: Em.computed.gt('postStream.userFilters.length', 0), isSuspended: Em.computed.notEmpty('user.suspend_reason'), - showBadges: Discourse.computed.setting('enable_badges'), + showBadges: setting('enable_badges'), showMoreBadges: Em.computed.gt('moreBadgesCount', 0), showDelete: Em.computed.and("viewingAdmin", "showName", "user.canBeDeleted"), diff --git a/app/assets/javascripts/discourse/controllers/user-posts.js.es6 b/app/assets/javascripts/discourse/controllers/user-posts.js.es6 index dd2f58f6954dec..e06143db4812db 100644 --- a/app/assets/javascripts/discourse/controllers/user-posts.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-posts.js.es6 @@ -1,7 +1,7 @@ -export default Ember.ObjectController.extend({ +export default Ember.Controller.extend({ needs: ["application"], _showFooter: function() { - this.set("controllers.application.showFooter", !this.get("canLoadMore")); - }.observes("canLoadMore") + this.set("controllers.application.showFooter", !this.get("model.canLoadMore")); + }.observes("model.canLoadMore") }); diff --git a/app/assets/javascripts/discourse/helpers/application_helpers.js b/app/assets/javascripts/discourse/helpers/application.js.es6 similarity index 64% rename from app/assets/javascripts/discourse/helpers/application_helpers.js rename to app/assets/javascripts/discourse/helpers/application.js.es6 index 291e598b14373f..35c4f6493699fd 100644 --- a/app/assets/javascripts/discourse/helpers/application_helpers.js +++ b/app/assets/javascripts/discourse/helpers/application.js.es6 @@ -1,17 +1,17 @@ -var safe = Handlebars.SafeString; +import registerUnbound from 'discourse/helpers/register-unbound'; +import avatarTemplate from 'discourse/lib/avatar-template'; +import { longDate, autoUpdatingRelativeAge, number } from 'discourse/lib/formatter'; -// TODO: Remove me when ES6ified -var registerUnbound = require('discourse/helpers/register-unbound', null, null, true).default; -var avatarTemplate = require('discourse/lib/avatar-template', null, null, true).default; +const safe = Handlebars.SafeString; Em.Handlebars.helper('bound-avatar', function(user, size, uploadId) { if (Em.isEmpty(user)) { return new safe("
"); } - var username = Em.get(user, 'username'); + const username = Em.get(user, 'username'); if (arguments.length < 4) { uploadId = Em.get(user, 'uploaded_avatar_id'); } - var avatar = Em.get(user, 'avatar_template') || avatarTemplate(username, uploadId); + const avatar = Em.get(user, 'avatar_template') || avatarTemplate(username, uploadId); return new safe(Discourse.Utilities.avatarImg({ size: size, avatarTemplate: avatar })); }, 'username', 'uploaded_avatar_id', 'avatar_template'); @@ -24,30 +24,30 @@ Em.Handlebars.helper('bound-avatar-template', function(avatarTemplate, size) { }); registerUnbound('raw-date', function(dt) { - return Discourse.Formatter.longDate(new Date(dt)); + return longDate(new Date(dt)); }); registerUnbound('age-with-tooltip', function(dt) { - return new safe(Discourse.Formatter.autoUpdatingRelativeAge(new Date(dt), {title: true})); + return new safe(autoUpdatingRelativeAge(new Date(dt), {title: true})); }); registerUnbound('number', function(orig, params) { orig = parseInt(orig, 10); if (isNaN(orig)) { orig = 0; } - var title = orig; + let title = orig; if (params.numberKey) { title = I18n.t(params.numberKey, { number: orig }); } - var classNames = 'number'; + let classNames = 'number'; if (params['class']) { classNames += ' ' + params['class']; } - var result = "= docViewTop); } return $elements.each(function(i, elem) { - var $elem = $(elem), - elemTop = $elem.offset().top, - elemBottom = elemTop + $elem.height(), - markSeen = false; + const $elem = $(elem), + elemTop = $elem.offset().top, + elemBottom = elemTop + $elem.height(); + + let markSeen = false; // Make sure the element is visible if (!$elem.is(':visible')) return true; @@ -67,18 +58,15 @@ Discourse.Eyeline.prototype.update = function() { }; -/** - Call this when we know aren't loading any more elements. Mark the rest as seen - - @method flushRest -**/ -Discourse.Eyeline.prototype.flushRest = function() { - var self = this; +// Call this when we know aren't loading any more elements. Mark the rest as seen +Eyeline.prototype.flushRest = function() { + if (Ember.Test) { return; } + const self = this; $(this.selector).each(function(i, elem) { return self.trigger('saw', { detail: $(elem) }); }); }; -RSVP.EventTarget.mixin(Discourse.Eyeline.prototype); - +RSVP.EventTarget.mixin(Eyeline.prototype); +export default Eyeline; diff --git a/app/assets/javascripts/discourse/lib/formatter.js b/app/assets/javascripts/discourse/lib/formatter.js.es6 similarity index 72% rename from app/assets/javascripts/discourse/lib/formatter.js rename to app/assets/javascripts/discourse/lib/formatter.js.es6 index 1b3db5baadcb36..a2cdaefb40542e 100644 --- a/app/assets/javascripts/discourse/lib/formatter.js +++ b/app/assets/javascripts/discourse/lib/formatter.js.es6 @@ -1,9 +1,5 @@ /* global BreakString:true */ -var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny, - relativeAgeMedium, relativeAgeMediumSpan, longDate, longDateNoYear, toTitleCase, - shortDate, shortDateNoYear, tinyDateYear, relativeAgeTinyShowsYear; - /* * memoize.js * by @philogb and @addyosmani @@ -14,15 +10,15 @@ var updateRelativeAge, autoUpdatingRelativeAge, relativeAge, relativeAgeTiny, * * modified with cap by Sam */ -var cappedMemoize = function ( fn, max ) { +function cappedMemoize(fn, max) { fn.maxMemoize = max; fn.memoizeLength = 0; return function () { - var args = Array.prototype.slice.call(arguments), - hash = "", - i = args.length; - var currentArg = null; + const args = Array.prototype.slice.call(arguments); + let hash = ""; + let i = args.length; + let currentArg = null; while (i--) { currentArg = args[i]; hash += (currentArg === new Object(currentArg)) ? @@ -39,44 +35,45 @@ var cappedMemoize = function ( fn, max ) { fn.memoizeLength = 0; fn.memoize = {}; } - var result = fn.apply(this, args); + const result = fn.apply(this, args); fn.memoize[hash] = result; return result; } }; -}; +} -var breakUp = cappedMemoize(function(str, hint){ +const breakUp = cappedMemoize(function(str, hint){ return new BreakString(str).break(hint); }, 100); +export { breakUp }; -shortDate = function(date){ +export function shortDate(date){ return moment(date).format(I18n.t("dates.medium.date_year")); -}; +} -shortDateNoYear = function(date) { +function shortDateNoYear(date) { return moment(date).format(I18n.t("dates.tiny.date_month")); -}; +} -tinyDateYear = function(date) { +function tinyDateYear(date) { return moment(date).format(I18n.t("dates.tiny.date_year")); -}; +} // http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript // TODO: locale support ? -toTitleCase = function toTitleCase(str) { +export function toTitleCase(str) { return str.replace(/\w\S*/g, function(txt){ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); -}; +} -longDate = function(dt) { +export function longDate(dt) { if (!dt) return; return moment(dt).longDate(); -}; +} // suppress year, if current year -longDateNoYear = function(dt) { +export function longDateNoYear(dt) { if (!dt) return; if ((new Date()).getFullYear() !== dt.getFullYear()) { @@ -84,26 +81,25 @@ longDateNoYear = function(dt) { } else { return moment(dt).format(I18n.t("dates.long_date_without_year")); } -}; +} -updateRelativeAge = function(elems) { +export function updateRelativeAge(elems) { // jQuery .each elems.each(function(){ - var $this = $(this); + const $this = $(this); $this.html(relativeAge(new Date($this.data('time')), {format: $this.data('format'), wrapInSpan: false})); }); -}; +} -autoUpdatingRelativeAge = function(date,options) { +export function autoUpdatingRelativeAge(date,options) { if (!date) return ""; if (+date === +new Date(0)) return ""; options = options || {}; - var format = options.format || "tiny"; - - var append = ""; + let format = options.format || "tiny"; - if(format === 'medium') { + let append = ""; + if (format === 'medium') { append = " date"; if(options.leaveAgo) { format = 'medium-with-ago'; @@ -111,7 +107,7 @@ autoUpdatingRelativeAge = function(date,options) { options.wrapInSpan = false; } - var relAge = relativeAge(date, options); + const relAge = relativeAge(date, options); if (format === 'tiny' && relativeAgeTinyShowsYear(relAge)) { append += " with-year"; @@ -122,16 +118,16 @@ autoUpdatingRelativeAge = function(date,options) { } return "" + relAge + ""; -}; +} -relativeAgeTiny = function(date){ - var format = "tiny"; - var distance = Math.round((new Date() - date) / 1000); - var distanceInMinutes = Math.round(distance / 60.0); +function relativeAgeTiny(date){ + const format = "tiny"; + const distance = Math.round((new Date() - date) / 1000); + const distanceInMinutes = Math.round(distance / 60.0); - var formatted; - var t = function(key,opts){ + let formatted; + const t = function(key,opts){ return I18n.t("dates." + format + "." + key, opts); }; @@ -168,22 +164,21 @@ relativeAgeTiny = function(date){ } return formatted; -}; +} /* * Returns true if the given tiny date string includes the year. * Useful for checking if the string isn't so tiny. */ -relativeAgeTinyShowsYear = function(relativeAgeString) { +function relativeAgeTinyShowsYear(relativeAgeString) { return relativeAgeString.match(/'[\d]{2}$/); -}; - -relativeAgeMediumSpan = function(distance, leaveAgo) { - var formatted, distanceInMinutes; +} - distanceInMinutes = Math.round(distance / 60.0); +function relativeAgeMediumSpan(distance, leaveAgo) { + let formatted; + const distanceInMinutes = Math.round(distance / 60.0); - var t = function(key, opts){ + const t = function(key, opts){ return I18n.t("dates.medium" + (leaveAgo?"_with_ago":"") + "." + key, opts); }; @@ -205,24 +200,22 @@ relativeAgeMediumSpan = function(distance, leaveAgo) { break; } return formatted || '&mdash'; -}; +} -relativeAgeMedium = function(date, options){ - var displayDate, fiveDaysAgo, oneMinuteAgo, fullReadable, leaveAgo; - var wrapInSpan = options.wrapInSpan !== false; - - leaveAgo = options.leaveAgo; - var distance = Math.round((new Date() - date) / 1000); +function relativeAgeMedium(date, options) { + const wrapInSpan = options.wrapInSpan !== false; + const leaveAgo = options.leaveAgo; + const distance = Math.round((new Date() - date) / 1000); if (!date) { return "—"; } - fullReadable = longDate(date); - displayDate = ""; - fiveDaysAgo = 432000; - oneMinuteAgo = 60; + const fullReadable = longDate(date); + const fiveDaysAgo = 432000; + const oneMinuteAgo = 60; + let displayDate = ""; if (distance < oneMinuteAgo) { displayDate = I18n.t("now"); } else if (distance > fiveDaysAgo) { @@ -239,12 +232,12 @@ relativeAgeMedium = function(date, options){ } else { return displayDate; } -}; +} // mostly lifted from rails with a few amendments -relativeAge = function(date, options) { +export function relativeAge(date, options) { options = options || {}; - var format = options.format || "tiny"; + const format = options.format || "tiny"; if(format === "tiny") { return relativeAgeTiny(date, options); @@ -255,10 +248,10 @@ relativeAge = function(date, options) { } return "UNKNOWN FORMAT"; -}; +} -var number = function(val) { - var formattedNumber; +export function number(val) { + let formattedNumber; val = parseInt(val, 10); if (isNaN(val)) val = 0; @@ -272,17 +265,5 @@ var number = function(val) { return I18n.t("number.short.thousands", {number: formattedNumber}); } return val.toString(); -}; - -Discourse.Formatter = { - longDate: longDate, - longDateNoYear: longDateNoYear, - relativeAge: relativeAge, - autoUpdatingRelativeAge: autoUpdatingRelativeAge, - updateRelativeAge: updateRelativeAge, - toTitleCase: toTitleCase, - shortDate: shortDate, - breakUp: breakUp, - cappedMemoize: cappedMemoize, - number: number -}; +} + diff --git a/app/assets/javascripts/discourse/lib/page_tracker.js b/app/assets/javascripts/discourse/lib/page-tracker.js.es6 similarity index 77% rename from app/assets/javascripts/discourse/lib/page_tracker.js rename to app/assets/javascripts/discourse/lib/page-tracker.js.es6 index 842f2d9b11dff6..9a7dcc9c9d9658 100644 --- a/app/assets/javascripts/discourse/lib/page_tracker.js +++ b/app/assets/javascripts/discourse/lib/page-tracker.js.es6 @@ -1,3 +1,5 @@ +import Singleton from 'discourse/mixins/singleton'; + /** Called whenever the "page" changes. This allows us to set up analytics and other tracking. @@ -5,12 +7,12 @@ To get notified when the page changes, you can install a hook like so: ```javascript - Discourse.PageTracker.current().on('change', function(url, title) { + PageTracker.current().on('change', function(url, title) { console.log('the page changed to: ' + url + ' and title ' + title); }); ``` **/ -Discourse.PageTracker = Ember.Object.extend(Ember.Evented, { +const PageTracker = Ember.Object.extend(Ember.Evented, { start: function() { if (this.get('started')) { return; } @@ -30,4 +32,6 @@ Discourse.PageTracker = Ember.Object.extend(Ember.Evented, { this.set('started', true); } }); -Discourse.PageTracker.reopenClass(Discourse.Singleton); +PageTracker.reopenClass(Singleton); + +export default PageTracker; diff --git a/app/assets/javascripts/discourse/lib/screen_track.js b/app/assets/javascripts/discourse/lib/screen-track.js.es6 similarity index 72% rename from app/assets/javascripts/discourse/lib/screen_track.js rename to app/assets/javascripts/discourse/lib/screen-track.js.es6 index 595a5321ce751e..3d55418cfbf694 100644 --- a/app/assets/javascripts/discourse/lib/screen_track.js +++ b/app/assets/javascripts/discourse/lib/screen-track.js.es6 @@ -1,23 +1,18 @@ -/** - We use this class to track how long posts in a topic are on the screen. +// We use this class to track how long posts in a topic are on the screen. - @class ScreenTrack - @extends Ember.Object - @namespace Discourse - @module Discourse -**/ +import Singleton from 'discourse/mixins/singleton'; -var PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3, - MAX_TRACKING_TIME = 1000 * 60 * 6; +const PAUSE_UNLESS_SCROLLED = 1000 * 60 * 3, + MAX_TRACKING_TIME = 1000 * 60 * 6; -Discourse.ScreenTrack = Ember.Object.extend({ +const ScreenTrack = Ember.Object.extend({ - init: function() { + init() { this.reset(); }, - start: function(topicId, topicController) { - var currentTopicId = this.get('topicId'); + start(topicId, topicController) { + const currentTopicId = this.get('topicId'); if (currentTopicId && (currentTopicId !== topicId)) { this.tick(); this.flush(); @@ -27,7 +22,7 @@ Discourse.ScreenTrack = Ember.Object.extend({ // Create an interval timer if we don't have one. if (!this.get('interval')) { - var self = this; + const self = this; this.set('interval', setInterval(function () { self.tick(); }, 1000)); @@ -39,7 +34,7 @@ Discourse.ScreenTrack = Ember.Object.extend({ this.set('topicController', topicController); }, - stop: function() { + stop() { if(!this.get('topicId')) { // already stopped no need to "extra stop" return; @@ -56,19 +51,19 @@ Discourse.ScreenTrack = Ember.Object.extend({ } }, - track: function(elementId, postNumber) { + track(elementId, postNumber) { this.get('timings')["#" + elementId] = { time: 0, postNumber: postNumber }; }, - stopTracking: function(elementId) { + stopTracking(elementId) { delete this.get('timings')['#' + elementId]; }, // Reset our timers - reset: function() { + reset() { this.setProperties({ lastTick: new Date().getTime(), lastScrolled: new Date().getTime(), @@ -80,17 +75,17 @@ Discourse.ScreenTrack = Ember.Object.extend({ }); }, - scrolled: function() { + scrolled() { this.set('lastScrolled', new Date().getTime()); }, - flush: function() { + flush() { if (this.get('cancelled')) { return; } // We don't log anything unless we're logged in if (!Discourse.User.current()) return; - var newTimings = {}, + const newTimings = {}, totalTimings = this.get('totalTimings'), self = this; @@ -105,14 +100,14 @@ Discourse.ScreenTrack = Ember.Object.extend({ timing.time = 0; }); - var topicId = parseInt(this.get('topicId'), 10), - highestSeen = 0; + const topicId = parseInt(this.get('topicId'), 10); + let highestSeen = 0; _.each(newTimings, function(time,postNumber) { highestSeen = Math.max(highestSeen, parseInt(postNumber, 10)); }); - var highestSeenByTopic = Discourse.Session.currentProp('highestSeenByTopic'); + const highestSeenByTopic = Discourse.Session.currentProp('highestSeenByTopic'); if ((highestSeenByTopic[topicId] || 0) < highestSeen) { highestSeenByTopic[topicId] = highestSeen; } @@ -132,9 +127,9 @@ Discourse.ScreenTrack = Ember.Object.extend({ 'X-SILENCE-LOGGER': 'true' } }).then(function(){ - var controller = self.get('topicController'); + const controller = self.get('topicController'); if(controller){ - var postNumbers = Object.keys(newTimings).map(function(v){ + const postNumbers = Object.keys(newTimings).map(function(v){ return parseInt(v,10); }); controller.readPosts(topicId, postNumbers); @@ -146,23 +141,23 @@ Discourse.ScreenTrack = Ember.Object.extend({ this.set('lastFlush', 0); }, - tick: function() { + tick() { // If the user hasn't scrolled the browser in a long time, stop tracking time read - var sinceScrolled = new Date().getTime() - this.get('lastScrolled'); + const sinceScrolled = new Date().getTime() - this.get('lastScrolled'); if (sinceScrolled > PAUSE_UNLESS_SCROLLED) { return; } - var diff = new Date().getTime() - this.get('lastTick'); + const diff = new Date().getTime() - this.get('lastTick'); this.set('lastFlush', this.get('lastFlush') + diff); this.set('lastTick', new Date().getTime()); - var totalTimings = this.get('totalTimings'), timings = this.get('timings'); - var nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000; + const totalTimings = this.get('totalTimings'), timings = this.get('timings'); + const nextFlush = Discourse.SiteSettings.flush_timings_secs * 1000; // rush new post numbers - var rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){ + const rush = _.any(_.filter(timings, function(t){return t.time>0;}), function(t){ return !totalTimings[t.postNumber]; }); @@ -174,15 +169,15 @@ Discourse.ScreenTrack = Ember.Object.extend({ if (!Discourse.get("hasFocus")) return; this.set('topicTime', this.get('topicTime') + diff); - var docViewTop = $(window).scrollTop() + $('header').height(), + const docViewTop = $(window).scrollTop() + $('header').height(), docViewBottom = docViewTop + $(window).height(); // TODO: Eyeline has a smarter more accurate function here. It's bad to do jQuery // in a model like component, so we should refactor this out later. _.each(this.get('timings'),function(timing,id) { - var $element = $(id); + const $element = $(id); if ($element.length === 1) { - var elemTop = $element.offset().top, + const elemTop = $element.offset().top, elemBottom = elemTop + $element.height(); // If part of the element is on the screen, increase the counter @@ -195,5 +190,5 @@ Discourse.ScreenTrack = Ember.Object.extend({ }); -Discourse.ScreenTrack.reopenClass(Discourse.Singleton); - +ScreenTrack.reopenClass(Singleton); +export default ScreenTrack; diff --git a/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 b/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 index 22742d7451bbe5..dc802c4d047306 100644 --- a/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 +++ b/app/assets/javascripts/discourse/mixins/can-check-emails.js.es6 @@ -1,6 +1,8 @@ +import { propertyEqual, setting } from 'discourse/lib/computed'; + export default Ember.Mixin.create({ - isOwnEmail: Discourse.computed.propertyEqual("model.id", "currentUser.id"), - showEmailOnProfile: Discourse.computed.setting("show_email_on_profile"), + isOwnEmail: propertyEqual("model.id", "currentUser.id"), + showEmailOnProfile: setting("show_email_on_profile"), canStaffCheckEmails: Em.computed.and("showEmailOnProfile", "currentUser.staff"), canAdminCheckEmails: Em.computed.alias("currentUser.admin"), canCheckEmails: Em.computed.or("isOwnEmail", "canStaffCheckEmails", "canAdminCheckEmails"), diff --git a/app/assets/javascripts/discourse/mixins/load-more.js.es6 b/app/assets/javascripts/discourse/mixins/load-more.js.es6 index 0726b13bd76fcf..19d772a9bd3826 100644 --- a/app/assets/javascripts/discourse/mixins/load-more.js.es6 +++ b/app/assets/javascripts/discourse/mixins/load-more.js.es6 @@ -1,5 +1,8 @@ +import Eyeline from 'discourse/lib/eyeline'; +import Scrolling from 'discourse/mixins/scrolling'; + // Provides the ability to load more items for a view which is scrolled to the bottom. -export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrolling, { +export default Ember.Mixin.create(Ember.ViewTargetActionSupport, Scrolling, { scrolled: function() { const eyeline = this.get('eyeline'); @@ -7,7 +10,7 @@ export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrollin }, _bindEyeline: function() { - const eyeline = new Discourse.Eyeline(this.get('eyelineSelector') + ":last"); + const eyeline = new Eyeline(this.get('eyelineSelector') + ":last"); this.set('eyeline', eyeline); eyeline.on('sawBottom', () => this.send('loadMore')); this.bindScrolling(); diff --git a/app/assets/javascripts/discourse/mixins/scrolling.js b/app/assets/javascripts/discourse/mixins/scrolling.js deleted file mode 100644 index c9473c155e5aeb..00000000000000 --- a/app/assets/javascripts/discourse/mixins/scrolling.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - This mixin adds support for being notified every time the browser window - is scrolled. - - @class Scrolling - @extends Ember.Mixin - @namespace Discourse - @module Discourse -**/ - -Discourse.Scrolling = Em.Mixin.create({ - - /** - Begin watching for scroll events. By default they will be called at max every 100ms. - call with {debounce: N} for a diff time - - @method bindScrolling - */ - bindScrolling: function(opts) { - opts = opts || {debounce: 100}; - - // So we can not call the scrolled event while transitioning - var router = Discourse.__container__.lookup('router:main').router; - - var self = this, - onScrollMethod = function() { - if (router.activeTransition) { return; } - return Em.run.scheduleOnce('afterRender', self, 'scrolled'); - }; - - if (opts.debounce) { - onScrollMethod = Discourse.debounce(onScrollMethod, opts.debounce); - } - - Discourse.ScrollingDOMMethods.bindOnScroll(onScrollMethod, opts.name); - Em.run.scheduleOnce('afterRender', onScrollMethod); - }, - - /** - Stop watching for scroll events. - - @method unbindScrolling - */ - unbindScrolling: function(name) { - Discourse.ScrollingDOMMethods.unbindOnScroll(name); - } - -}); - - -/** - This object provides the DOM methods we need for our Mixin to bind to scrolling - methods in the browser. By removing them from the Mixin we can test them - easier. - - @class ScrollingDOMMethods - @module Discourse -**/ -Discourse.ScrollingDOMMethods = { - - bindOnScroll: function(onScrollMethod, name) { - name = name || 'default'; - $(document).bind('touchmove.discourse-' + name, onScrollMethod); - $(window).bind('scroll.discourse-' + name, onScrollMethod); - }, - - unbindOnScroll: function(name) { - name = name || 'default'; - $(window).unbind('scroll.discourse-' + name); - $(document).unbind('touchmove.discourse-' + name); - } - -}; diff --git a/app/assets/javascripts/discourse/mixins/scrolling.js.es6 b/app/assets/javascripts/discourse/mixins/scrolling.js.es6 new file mode 100644 index 00000000000000..459bbd7119558f --- /dev/null +++ b/app/assets/javascripts/discourse/mixins/scrolling.js.es6 @@ -0,0 +1,50 @@ +/** + This object provides the DOM methods we need for our Mixin to bind to scrolling + methods in the browser. By removing them from the Mixin we can test them + easier. +**/ +const ScrollingDOMMethods = { + bindOnScroll: function(onScrollMethod, name) { + name = name || 'default'; + $(document).bind('touchmove.discourse-' + name, onScrollMethod); + $(window).bind('scroll.discourse-' + name, onScrollMethod); + }, + + unbindOnScroll: function(name) { + name = name || 'default'; + $(window).unbind('scroll.discourse-' + name); + $(document).unbind('touchmove.discourse-' + name); + } +}; + +const Scrolling = Ember.Mixin.create({ + + // Begin watching for scroll events. By default they will be called at max every 100ms. + // call with {debounce: N} for a diff time + bindScrolling: function(opts) { + opts = opts || {debounce: 100}; + + // So we can not call the scrolled event while transitioning + const router = Discourse.__container__.lookup('router:main').router; + + const self = this; + var onScrollMethod = function() { + if (router.activeTransition) { return; } + return Em.run.scheduleOnce('afterRender', self, 'scrolled'); + }; + + if (opts.debounce) { + onScrollMethod = Discourse.debounce(onScrollMethod, opts.debounce); + } + + ScrollingDOMMethods.bindOnScroll(onScrollMethod, opts.name); + Em.run.scheduleOnce('afterRender', onScrollMethod); + }, + + unbindScrolling: function(name) { + ScrollingDOMMethods.unbindOnScroll(name); + } +}); + +export { ScrollingDOMMethods }; +export default Scrolling; diff --git a/app/assets/javascripts/discourse/mixins/singleton.js b/app/assets/javascripts/discourse/mixins/singleton.js.es6 similarity index 61% rename from app/assets/javascripts/discourse/mixins/singleton.js rename to app/assets/javascripts/discourse/mixins/singleton.js.es6 index 73ce7a33e7433c..3bd27813e5d848 100644 --- a/app/assets/javascripts/discourse/mixins/singleton.js +++ b/app/assets/javascripts/discourse/mixins/singleton.js.es6 @@ -9,7 +9,7 @@ // Define your class and apply the Mixin User = Ember.Object.extend({}); - User.reopenClass(Discourse.Singleton); + User.reopenClass(Singleton); // Retrieve the current instance: var instance = User.current(); @@ -35,7 +35,7 @@ // Define your class and apply the Mixin Foot = Ember.Object.extend({}); - Foot.reopenClass(Discourse.Singleton, { + Foot.reopenClass(Singleton, { createCurrent: function() { return Foot.create({toes: 5}); } @@ -44,51 +44,28 @@ console.log(Foot.currentProp('toes')); // 5 ``` - - @class Discourse.Singleton - @extends Ember.Mixin - @namespace Discourse - @module Discourse **/ -Discourse.Singleton = Em.Mixin.create({ - - /** - Returns the current singleton instance of the class. +const Singleton = Ember.Mixin.create({ - @method current - @returns {Ember.Object} the instance of the singleton - **/ - current: function() { + current() { if (!this._current) { this._current = this.createCurrent(); } - return this._current; }, - /** How the singleton instance is created. This can be overridden with logic for creating (or even returning null) your instance. By default it just calls `create` with an empty object. - - @method createCurrent - @returns {Ember.Object} the instance that will be your singleton **/ - createCurrent: function() { + createCurrent() { return this.create({}); }, - /** - Returns or sets a property on the singleton instance. - - @method currentProp - @param {String} property the property we want to get or set - @param {String} value the optional value to set the property to - @returns the value of the property - **/ - currentProp: function(property, value) { + // Returns OR sets a property on the singleton instance. + currentProp(property, value) { var instance = this.current(); if (!instance) { return; } @@ -100,14 +77,9 @@ Discourse.Singleton = Em.Mixin.create({ } }, - /** - Resets the current singleton. Useful in testing. - - @method resetCurrent - **/ - resetCurrent: function(val) { + resetCurrent(val) { this._current = val; } }); - +export default Singleton; diff --git a/app/assets/javascripts/discourse/models/admin_post.js b/app/assets/javascripts/discourse/models/admin-post.js.es6 similarity index 73% rename from app/assets/javascripts/discourse/models/admin_post.js rename to app/assets/javascripts/discourse/models/admin-post.js.es6 index 8db9dfec69abfe..4504fcbe24e988 100644 --- a/app/assets/javascripts/discourse/models/admin_post.js +++ b/app/assets/javascripts/discourse/models/admin-post.js.es6 @@ -1,15 +1,9 @@ -/** - A data model for flagged/deleted posts. +import Post from 'discourse/models/post'; - @class AdminPost - @extends Discourse.Post - @namespace Discourse - @module Discourse -**/ -Discourse.AdminPost = Discourse.Post.extend({ +export default Post.extend({ _attachCategory: function () { - var categoryId = this.get("category_id"); + const categoryId = this.get("category_id"); if (categoryId) { this.set("category", Discourse.Category.findById(categoryId)); } diff --git a/app/assets/javascripts/discourse/models/archetype.js b/app/assets/javascripts/discourse/models/archetype.js deleted file mode 100644 index cfbc88c41823b8..00000000000000 --- a/app/assets/javascripts/discourse/models/archetype.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - A data model for archetypes such as polls, tasks, etc. - - @class Archetype - @extends Discourse.Model - @namespace Discourse - @module Discourse -**/ -Discourse.Archetype = Discourse.Model.extend({ - - hasOptions: Em.computed.gt('options.length', 0), - - site: function() { - return Discourse.Site.current(); - }.property(), - - isDefault: Discourse.computed.propertyEqual('id', 'site.default_archetype'), - notDefault: Em.computed.not('isDefault') - -}); - - diff --git a/app/assets/javascripts/discourse/models/archetype.js.es6 b/app/assets/javascripts/discourse/models/archetype.js.es6 new file mode 100644 index 00000000000000..3931858f75c4e7 --- /dev/null +++ b/app/assets/javascripts/discourse/models/archetype.js.es6 @@ -0,0 +1,8 @@ +import { propertyEqual } from 'discourse/lib/computed'; +import RestModel from 'discourse/models/rest'; + +export default RestModel.extend({ + hasOptions: Em.computed.gt('options.length', 0), + isDefault: propertyEqual('id', 'site.default_archetype'), + notDefault: Em.computed.not('isDefault') +}); diff --git a/app/assets/javascripts/discourse/models/nav-item.js.es6 b/app/assets/javascripts/discourse/models/nav-item.js.es6 index def6a3430a5a67..d4e5ef228b2698 100644 --- a/app/assets/javascripts/discourse/models/nav-item.js.es6 +++ b/app/assets/javascripts/discourse/models/nav-item.js.es6 @@ -1,11 +1,4 @@ -/** - A data model representing a navigation item on the list views - - @class NavItem - @extends Discourse.Model - @namespace Discourse - @module Discourse -**/ +import { toTitleCase } from 'discourse/lib/formatter'; const NavItem = Discourse.Model.extend({ @@ -22,7 +15,7 @@ const NavItem = Discourse.Model.extend({ if (categoryName) { name = 'category'; - extra.categoryName = Discourse.Formatter.toTitleCase(categoryName); + extra.categoryName = toTitleCase(categoryName); } return I18n.t("filters." + name.replace("/", ".") + ".title", extra); }.property('categoryName', 'name', 'count'), diff --git a/app/assets/javascripts/discourse/models/post.js.es6 b/app/assets/javascripts/discourse/models/post.js.es6 index a6785730771a82..7f6ccf38d86793 100644 --- a/app/assets/javascripts/discourse/models/post.js.es6 +++ b/app/assets/javascripts/discourse/models/post.js.es6 @@ -1,6 +1,7 @@ import RestModel from 'discourse/models/rest'; import { popupAjaxError } from 'discourse/lib/ajax-error'; import ActionSummary from 'discourse/models/action-summary'; +import { url, fmt, propertyEqual } from 'discourse/lib/computed'; const Post = RestModel.extend({ @@ -57,7 +58,7 @@ const Post = RestModel.extend({ return (this.get('post_number') === 1) ? url + "/1" : url; }.property('post_number', 'url'), - usernameUrl: Discourse.computed.url('username', '/users/%@'), + usernameUrl: url('username', '/users/%@'), showUserReplyTab: function() { return this.get('reply_to_user') && ( @@ -66,9 +67,9 @@ const Post = RestModel.extend({ ); }.property('reply_to_user', 'reply_to_post_number', 'post_number'), - topicOwner: Discourse.computed.propertyEqual('topic.details.created_by.id', 'user_id'), + topicOwner: propertyEqual('topic.details.created_by.id', 'user_id'), hasHistory: Em.computed.gt('version', 1), - postElementId: Discourse.computed.fmt('post_number', 'post_%@'), + postElementId: fmt('post_number', 'post_%@'), canViewRawEmail: function() { return this.get("user_id") === Discourse.User.currentProp("id") || Discourse.User.currentProp('staff'); diff --git a/app/assets/javascripts/discourse/models/session.js.es6 b/app/assets/javascripts/discourse/models/session.js.es6 index 894dc6b2fdfadb..f87549339392b7 100644 --- a/app/assets/javascripts/discourse/models/session.js.es6 +++ b/app/assets/javascripts/discourse/models/session.js.es6 @@ -1,11 +1,13 @@ +import RestModel from 'discourse/models/rest'; +import Singleton from 'discourse/mixins/singleton'; + // A data model representing current session data. You can put transient // data here you might want later. It is not stored or serialized anywhere. -var Session = Discourse.Model.extend({ +const Session = RestModel.extend({ init: function() { this.set('highestSeenByTopic', {}); } }); -Session.reopenClass(Discourse.Singleton); - +Session.reopenClass(Singleton); export default Session; diff --git a/app/assets/javascripts/discourse/models/site.js.es6 b/app/assets/javascripts/discourse/models/site.js.es6 index e3466eada0fc99..226e1ed811d9a5 100644 --- a/app/assets/javascripts/discourse/models/site.js.es6 +++ b/app/assets/javascripts/discourse/models/site.js.es6 @@ -1,4 +1,6 @@ +import Archetype from 'discourse/models/archetype'; import PostActionType from 'discourse/models/post-action-type'; +import Singleton from 'discourse/mixins/singleton'; const Site = Discourse.Model.extend({ @@ -85,11 +87,11 @@ const Site = Discourse.Model.extend({ } }); -Site.reopenClass(Discourse.Singleton, { +Site.reopenClass(Singleton, { // The current singleton will retrieve its attributes from the `PreloadStore`. createCurrent() { - return Discourse.Site.create(PreloadStore.get('site')); + return Site.create(PreloadStore.get('site')); }, create() { @@ -137,7 +139,8 @@ Site.reopenClass(Discourse.Singleton, { if (result.archetypes) { result.archetypes = _.map(result.archetypes,function(a) { - return Discourse.Archetype.create(a); + a.site = result; + return Archetype.create(a); }); } diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index 245508741123de..0fab68fa1088a6 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -1,5 +1,7 @@ import { flushMap } from 'discourse/models/store'; import RestModel from 'discourse/models/rest'; +import { propertyEqual } from 'discourse/lib/computed'; +import { longDate } from 'discourse/lib/formatter'; const Topic = RestModel.extend({ message: null, @@ -20,8 +22,8 @@ const Topic = RestModel.extend({ }.property('bumped_at', 'createdAt'), bumpedAtTitle: function() { - return I18n.t('first_post') + ": " + Discourse.Formatter.longDate(this.get('createdAt')) + "\n" + - I18n.t('last_post') + ": " + Discourse.Formatter.longDate(this.get('bumpedAt')); + return I18n.t('first_post') + ": " + longDate(this.get('createdAt')) + "\n" + + I18n.t('last_post') + ": " + longDate(this.get('bumpedAt')); }.property('bumpedAt'), createdAt: function() { @@ -364,7 +366,7 @@ const Topic = RestModel.extend({ return( e && e.substr(e.length - 8,8) === '…' ); }.property('excerpt'), - readLastPost: Discourse.computed.propertyEqual('last_read_post_number', 'highest_post_number'), + readLastPost: propertyEqual('last_read_post_number', 'highest_post_number'), canClearPin: Em.computed.and('pinned', 'readLastPost') }); diff --git a/app/assets/javascripts/discourse/models/trust-level.js.es6 b/app/assets/javascripts/discourse/models/trust-level.js.es6 new file mode 100644 index 00000000000000..f51eda37e355a0 --- /dev/null +++ b/app/assets/javascripts/discourse/models/trust-level.js.es6 @@ -0,0 +1,6 @@ +import RestModel from 'discourse/models/rest'; +import { fmt } from 'discourse/lib/computed'; + +export default RestModel.extend({ + detailedName: fmt('id', 'name', '%@ - %@') +}); diff --git a/app/assets/javascripts/discourse/models/trust_level.js b/app/assets/javascripts/discourse/models/trust_level.js deleted file mode 100644 index 869401011993a6..00000000000000 --- a/app/assets/javascripts/discourse/models/trust_level.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - Represents a user's trust level in the system - - @class TrustLevel - @extends Discourse.Model - @namespace Discourse - @module Discourse -**/ -Discourse.TrustLevel = Discourse.Model.extend({ - detailedName: Discourse.computed.fmt('id', 'name', '%@ - %@') -}); diff --git a/app/assets/javascripts/discourse/models/user-action-stat.js.es6 b/app/assets/javascripts/discourse/models/user-action-stat.js.es6 new file mode 100644 index 00000000000000..073c3032478adc --- /dev/null +++ b/app/assets/javascripts/discourse/models/user-action-stat.js.es6 @@ -0,0 +1,21 @@ +import RestModel from 'discourse/models/rest'; +import UserAction from 'discourse/models/user-action'; +import { i18n } from 'discourse/lib/computed'; + +export default RestModel.extend({ + + isPM: function() { + const actionType = this.get('action_type'); + return actionType === UserAction.TYPES.messages_sent || + actionType === UserAction.TYPES.messages_received; + }.property('action_type'), + + description: i18n('action_type', 'user_action_groups.%@'), + + isResponse: function() { + const actionType = this.get('action_type'); + return actionType === UserAction.TYPES.replies || + actionType === UserAction.TYPES.quotes; + }.property('action_type') + +}); diff --git a/app/assets/javascripts/discourse/models/user_action.js b/app/assets/javascripts/discourse/models/user-action.js.es6 similarity index 81% rename from app/assets/javascripts/discourse/models/user_action.js rename to app/assets/javascripts/discourse/models/user-action.js.es6 index 2c5060258d5c56..2d273c43e16b75 100644 --- a/app/assets/javascripts/discourse/models/user_action.js +++ b/app/assets/javascripts/discourse/models/user-action.js.es6 @@ -1,39 +1,37 @@ -var UserActionTypes = { - likes_given: 1, - likes_received: 2, - bookmarks: 3, - topics: 4, - posts: 5, - replies: 6, - mentions: 7, - quotes: 9, - edits: 11, - messages_sent: 12, - messages_received: 13, - pending: 14 - }, - InvertedActionTypes = {}; +import RestModel from 'discourse/models/rest'; +import { url } from 'discourse/lib/computed'; + +const UserActionTypes = { + likes_given: 1, + likes_received: 2, + bookmarks: 3, + topics: 4, + posts: 5, + replies: 6, + mentions: 7, + quotes: 9, + edits: 11, + messages_sent: 12, + messages_received: 13, + pending: 14 +}; +const InvertedActionTypes = {}; _.each(UserActionTypes, function (k, v) { InvertedActionTypes[k] = v; }); -Discourse.UserAction = Discourse.Model.extend({ +const UserAction = RestModel.extend({ _attachCategory: function() { - var categoryId = this.get('category_id'); + const categoryId = this.get('category_id'); if (categoryId) { this.set('category', Discourse.Category.findById(categoryId)); } }.on('init'), - /** - Return an i18n key we will use for the description text of a user action. - - @property descriptionKey - **/ descriptionKey: function() { - var action = this.get('action_type'); + const action = this.get('action_type'); if (action === null || Discourse.UserAction.TO_SHOW.indexOf(action) >= 0) { if (this.get('isPM')) { return this.get('sameUser') ? 'sent_by_you' : 'sent_by_user'; @@ -74,13 +72,13 @@ Discourse.UserAction = Discourse.Model.extend({ presentName: Em.computed.any('name', 'username'), targetDisplayName: Em.computed.any('target_name', 'target_username'), actingDisplayName: Em.computed.any('acting_name', 'acting_username'), - targetUserUrl: Discourse.computed.url('target_username', '/users/%@'), + targetUserUrl: url('target_username', '/users/%@'), usernameLower: function() { return this.get('username').toLowerCase(); }.property('username'), - userUrl: Discourse.computed.url('usernameLower', '/users/%@'), + userUrl: url('usernameLower', '/users/%@'), postUrl: function() { return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number')); @@ -102,7 +100,7 @@ Discourse.UserAction = Discourse.Model.extend({ removableBookmark: Em.computed.and('bookmarkType', 'sameUser'), addChild: function(action) { - var groups = this.get("childGroups"); + let groups = this.get("childGroups"); if (!groups) { groups = { likes: Discourse.UserActionGroup.create({ icon: "fa fa-heart" }), @@ -113,7 +111,7 @@ Discourse.UserAction = Discourse.Model.extend({ } this.set("childGroups", groups); - var bucket = (function() { + const bucket = (function() { switch (action.action_type) { case UserActionTypes.likes_given: case UserActionTypes.likes_received: @@ -124,15 +122,15 @@ Discourse.UserAction = Discourse.Model.extend({ return "bookmarks"; } })(); - var current = groups[bucket]; + const current = groups[bucket]; if (current) { current.push(action); } }, children: function() { - var g = this.get("childGroups"); - var rval = []; + const g = this.get("childGroups"); + let rval = []; if (g) { rval = [g.likes, g.stars, g.edits, g.bookmarks].filter(function(i) { return i.get("items") && i.get("items").length > 0; @@ -154,20 +152,20 @@ Discourse.UserAction = Discourse.Model.extend({ } }); -Discourse.UserAction.reopenClass({ +UserAction.reopenClass({ collapseStream: function(stream) { - var uniq = {}, - collapsed = [], - pos = 0; + const uniq = {}; + const collapsed = []; + let pos = 0; stream.forEach(function(item) { - var key = "" + item.topic_id + "-" + item.post_number; - var found = uniq[key]; + const key = "" + item.topic_id + "-" + item.post_number; + const found = uniq[key]; if (found === void 0) { - var current; + let current; if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) { - current = Discourse.UserAction.create(item); + current = UserAction.create(item); item.switchToActing(); current.addChild(item); } else { @@ -177,7 +175,7 @@ Discourse.UserAction.reopenClass({ collapsed[pos] = current; pos += 1; } else { - if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) { + if (UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) { item.switchToActing(); collapsed[found].addChild(item); } else { @@ -208,3 +206,5 @@ Discourse.UserAction.reopenClass({ ] }); + +export default UserAction; diff --git a/app/assets/javascripts/discourse/models/user_posts_stream.js b/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 similarity index 67% rename from app/assets/javascripts/discourse/models/user_posts_stream.js rename to app/assets/javascripts/discourse/models/user-posts-stream.js.es6 index e00646cc1211cb..8d7a750d8bbd7c 100644 --- a/app/assets/javascripts/discourse/models/user_posts_stream.js +++ b/app/assets/javascripts/discourse/models/user-posts-stream.js.es6 @@ -1,12 +1,7 @@ -/** - Represents a user's stream - - @class UserPostsStream - @extends Discourse.Model - @namespace Discourse - @module Discourse -**/ -Discourse.UserPostsStream = Discourse.Model.extend({ +import { url } from 'discourse/lib/computed'; +import AdminPost from 'discourse/models/admin-post'; + +export default Discourse.Model.extend({ loaded: false, _initialize: function () { @@ -17,9 +12,9 @@ Discourse.UserPostsStream = Discourse.Model.extend({ }); }.on("init"), - url: Discourse.computed.url("user.username_lower", "filter", "itemsLoaded", "/posts/%@/%@?offset=%@"), + url: url("user.username_lower", "filter", "itemsLoaded", "/posts/%@/%@?offset=%@"), - filterBy: function (filter) { + filterBy(filter) { if (this.get("loaded") && this.get("filter") === filter) { return Ember.RSVP.resolve(); } this.setProperties({ @@ -32,15 +27,15 @@ Discourse.UserPostsStream = Discourse.Model.extend({ return this.findItems(); }, - findItems: function () { - var self = this; + findItems() { + const self = this; if (this.get("loading") || !this.get("canLoadMore")) { return Ember.RSVP.reject(); } this.set("loading", true); return Discourse.ajax(this.get("url"), { cache: false }).then(function (result) { if (result) { - var posts = result.map(function (post) { return Discourse.AdminPost.create(post); }); + const posts = result.map(function (post) { return AdminPost.create(post); }); self.get("content").pushObjects(posts); self.setProperties({ loaded: true, diff --git a/app/assets/javascripts/discourse/models/user-stream.js.es6 b/app/assets/javascripts/discourse/models/user-stream.js.es6 index 1870d484d63dc8..71d1bba89c8cd6 100644 --- a/app/assets/javascripts/discourse/models/user-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/user-stream.js.es6 @@ -1,3 +1,4 @@ +import { url } from 'discourse/lib/computed'; import RestModel from 'discourse/models/rest'; export default RestModel.extend({ @@ -22,7 +23,7 @@ export default RestModel.extend({ return filter; }.property('filter'), - baseUrl: Discourse.computed.url('itemsLoaded', 'user.username_lower', '/user_actions.json?offset=%@&username=%@'), + baseUrl: url('itemsLoaded', 'user.username_lower', '/user_actions.json?offset=%@&username=%@'), filterBy(filter) { this.setProperties({ filter, itemsLoaded: 0, content: [], lastLoadedUrl: null }); diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 8e9c8e53507266..bcc84e85e86b88 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -1,5 +1,10 @@ +import { url } from 'discourse/lib/computed'; import RestModel from 'discourse/models/rest'; import avatarTemplate from 'discourse/lib/avatar-template'; +import UserStream from 'discourse/models/user-stream'; +import UserPostsStream from 'discourse/models/user-posts-stream'; +import Singleton from 'discourse/mixins/singleton'; +import { longDate } from 'discourse/lib/formatter'; const User = RestModel.extend({ @@ -10,24 +15,12 @@ const User = RestModel.extend({ hasNotPosted: Em.computed.not("hasPosted"), canBeDeleted: Em.computed.and("can_be_deleted", "hasNotPosted"), - /** - The user's stream - - @property stream - @type {Discourse.UserStream} - **/ stream: function() { - return Discourse.UserStream.create({ user: this }); + return UserStream.create({ user: this }); }.property(), - /** - The user's posts stream - - @property postsStream - @type {Discourse.UserPostsStream} - **/ postsStream: function() { - return Discourse.UserPostsStream.create({ user: this }); + return UserPostsStream.create({ user: this }); }.property(), /** @@ -89,7 +82,7 @@ const User = RestModel.extend({ @property adminPath @type {String} **/ - adminPath: Discourse.computed.url('username_lower', "/admin/users/%@"), + adminPath: url('username_lower', "/admin/users/%@"), /** This user's username in lowercase. @@ -123,7 +116,7 @@ const User = RestModel.extend({ }.property('suspended_till'), suspendedTillDate: function() { - return Discourse.Formatter.longDate(this.get('suspended_till')); + return longDate(this.get('suspended_till')); }.property('suspended_till'), /** @@ -434,15 +427,15 @@ const User = RestModel.extend({ }); -User.reopenClass(Discourse.Singleton, { +User.reopenClass(Singleton, { // Find a `Discourse.User` for a given username. findByUsername: function(username, options) { - const user = Discourse.User.create({username: username}); + const user = User.create({username: username}); return user.findDetails(options); }, - // TODO: Use app.register and junk Discourse.Singleton + // TODO: Use app.register and junk Singleton createCurrent: function() { var userJson = PreloadStore.get('currentUser'); if (userJson) { diff --git a/app/assets/javascripts/discourse/models/user_action_stat.js b/app/assets/javascripts/discourse/models/user_action_stat.js deleted file mode 100644 index 942f22e96072bc..00000000000000 --- a/app/assets/javascripts/discourse/models/user_action_stat.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - A data model representing a statistic on a UserAction - - @class UserActionStat - @extends Discourse.Model - @namespace Discourse - @module Discourse -**/ -Discourse.UserActionStat = Discourse.Model.extend({ - - isPM: function() { - var actionType = this.get('action_type'); - return actionType === Discourse.UserAction.TYPES.messages_sent || - actionType === Discourse.UserAction.TYPES.messages_received; - }.property('action_type'), - - description: Discourse.computed.i18n('action_type', 'user_action_groups.%@'), - - isResponse: function() { - var actionType = this.get('action_type'); - return actionType === Discourse.UserAction.TYPES.replies || - actionType === Discourse.UserAction.TYPES.quotes; - }.property('action_type') - -}); diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 6cff9ca749188a..a923dd17975601 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -1,3 +1,4 @@ +import { setting } from 'discourse/lib/computed'; import showModal from 'discourse/lib/show-modal'; import OpenComposer from "discourse/mixins/open-composer"; @@ -13,7 +14,7 @@ function unlessReadOnly(method) { const ApplicationRoute = Discourse.Route.extend(OpenComposer, { - siteTitle: Discourse.computed.setting('title'), + siteTitle: setting('title'), actions: { _collectTitleTokens(tokens) { diff --git a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 index 1f5dcd7621dc33..69cd2e5c22ed4d 100644 --- a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 @@ -1,3 +1,4 @@ +import ScreenTrack from 'discourse/lib/screen-track'; import { queryParams } from 'discourse/controllers/discovery-sortable'; // A helper to build a topic route for a filter @@ -82,7 +83,7 @@ export default function(filter, extras) { model(data, transition) { // attempt to stop early cause we need this to be called before .sync - Discourse.ScreenTrack.current().stop(); + ScreenTrack.current().stop(); const findOpts = filterQueryParams(transition.queryParams), extras = { cached: this.isPoppedState(transition) }; diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 7d5f2533413f78..6d730f058d6adf 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -1,3 +1,5 @@ +import ScreenTrack from 'discourse/lib/screen-track'; + let isTransitioning = false, scheduledReplace = null, lastScrollPos = null; @@ -185,7 +187,7 @@ const TopicRoute = Discourse.Route.extend({ topicController.set('multiSelect', false); topicController.unsubscribe(); this.controllerFor('composer').set('topic', null); - Discourse.ScreenTrack.current().stop(); + ScreenTrack.current().stop(); const headerController = this.controllerFor('header'); if (headerController) { @@ -226,7 +228,7 @@ const TopicRoute = Discourse.Route.extend({ this.controllerFor('topic-progress').set('model', model); // We reset screen tracking every time a topic is entered - Discourse.ScreenTrack.current().start(model.get('id'), controller); + ScreenTrack.current().start(model.get('id'), controller); } }); diff --git a/app/assets/javascripts/discourse/templates/user/posts.hbs b/app/assets/javascripts/discourse/templates/user/posts.hbs index f3f6e67545feac..285824a59f656d 100644 --- a/app/assets/javascripts/discourse/templates/user/posts.hbs +++ b/app/assets/javascripts/discourse/templates/user/posts.hbs @@ -1,5 +1,5 @@ {{#each p in model.content}} -
+
diff --git a/app/assets/javascripts/discourse/views/embedded-post.js.es6 b/app/assets/javascripts/discourse/views/embedded-post.js.es6 index 4697e439060364..4bccf52199c5a4 100644 --- a/app/assets/javascripts/discourse/views/embedded-post.js.es6 +++ b/app/assets/javascripts/discourse/views/embedded-post.js.es6 @@ -1,13 +1,15 @@ +import ScreenTrack from 'discourse/lib/screen-track'; + export default Discourse.GroupedView.extend({ templateName: 'embedded-post', classNames: ['reply'], _startTracking: function() { const post = this.get('content'); - Discourse.ScreenTrack.current().track(this.get('elementId'), post.get('post_number')); + ScreenTrack.current().track(this.get('elementId'), post.get('post_number')); }.on('didInsertElement'), _stopTracking: function() { - Discourse.ScreenTrack.current().stopTracking(this.get('elementId')); + ScreenTrack.current().stopTracking(this.get('elementId')); }.on('willDestroyElement') }); diff --git a/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 b/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 index 19bed7d0d2c793..d6026366733815 100644 --- a/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 +++ b/app/assets/javascripts/discourse/views/list/posts-count-column.js.es6 @@ -1,3 +1,5 @@ +import { fmt } from 'discourse/lib/computed'; + export default Ember.Object.extend({ tagName: "td", ratio: function() { @@ -26,6 +28,6 @@ export default Ember.Object.extend({ return ''; }.property(), - likesHeat: Discourse.computed.fmt('ratioText', 'heatmap-%@'), + likesHeat: fmt('ratioText', 'heatmap-%@'), }); diff --git a/app/assets/javascripts/discourse/views/post.js.es6 b/app/assets/javascripts/discourse/views/post.js.es6 index 38fb86f0f49a36..1d83deaff0ed5a 100644 --- a/app/assets/javascripts/discourse/views/post.js.es6 +++ b/app/assets/javascripts/discourse/views/post.js.es6 @@ -1,3 +1,6 @@ +import ScreenTrack from 'discourse/lib/screen-track'; +import { number } from 'discourse/lib/formatter'; + const DAY = 60 * 50 * 1000; const PostView = Discourse.GroupedView.extend(Ember.Evented, { @@ -178,7 +181,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, { // don't display badge counts on category badge & oneboxes (unless when explicitely stated) if ($link.hasClass("track-link") || $link.closest('.badge-category,.onebox-result,.onebox-body').length === 0) { - $link.append("" + Discourse.Formatter.number(lc.clicks) + ""); + $link.append("" + number(lc.clicks) + ""); } } }); @@ -263,7 +266,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, { }, _destroyedPostView: function() { - Discourse.ScreenTrack.current().stopTracking(this.get('elementId')); + ScreenTrack.current().stopTracking(this.get('elementId')); }.on('willDestroyElement'), _postViewInserted: function() { @@ -272,7 +275,7 @@ const PostView = Discourse.GroupedView.extend(Ember.Evented, { this._showLinkCounts(); - Discourse.ScreenTrack.current().track($post.prop('id'), postNumber); + ScreenTrack.current().track($post.prop('id'), postNumber); this.trigger('postViewInserted', $post); diff --git a/app/assets/javascripts/discourse/views/topic.js.es6 b/app/assets/javascripts/discourse/views/topic.js.es6 index 206133422f9ffa..f31911ae0f380c 100644 --- a/app/assets/javascripts/discourse/views/topic.js.es6 +++ b/app/assets/javascripts/discourse/views/topic.js.es6 @@ -3,8 +3,9 @@ import AddArchetypeClass from 'discourse/mixins/add-archetype-class'; import ClickTrack from 'discourse/lib/click-track'; import { listenForViewEvent } from 'discourse/lib/app-events'; import { categoryBadgeHTML } from 'discourse/helpers/category-link'; +import Scrolling from 'discourse/mixins/scrolling'; -const TopicView = Discourse.View.extend(AddCategoryClass, AddArchetypeClass, Discourse.Scrolling, { +const TopicView = Discourse.View.extend(AddCategoryClass, AddArchetypeClass, Scrolling, { templateName: 'topic', topicBinding: 'controller.model', diff --git a/app/assets/javascripts/discourse/views/user-card.js.es6 b/app/assets/javascripts/discourse/views/user-card.js.es6 index 08b42013a26a79..2aa1b47593f014 100644 --- a/app/assets/javascripts/discourse/views/user-card.js.es6 +++ b/app/assets/javascripts/discourse/views/user-card.js.es6 @@ -1,5 +1,5 @@ +import { setting } from 'discourse/lib/computed'; import CleansUp from 'discourse/mixins/cleans-up'; - import afterTransition from 'discourse/lib/after-transition'; const clickOutsideEventName = "mousedown.outside-user-card", @@ -9,7 +9,7 @@ const clickOutsideEventName = "mousedown.outside-user-card", export default Discourse.View.extend(CleansUp, { elementId: 'user-card', classNameBindings: ['controller.visible:show', 'controller.showBadges', 'controller.hasCardBadgeImage'], - allowBackgrounds: Discourse.computed.setting('allow_profile_backgrounds'), + allowBackgrounds: setting('allow_profile_backgrounds'), addBackground: function() { const url = this.get('controller.user.card_background'); diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index 8338d7921f78f4..a961cddc291a02 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -8,10 +8,14 @@ //= require ./discourse/lib/load-script //= require ./discourse/lib/notification-levels //= require ./discourse/lib/app-events +//= require ./discourse/lib/avatar-template //= require ./discourse/helpers/i18n //= require ./discourse/helpers/fa-icon +//= require ./discourse/helpers/register-unbound //= require ./discourse/lib/ember_compat_handlebars //= require ./discourse/lib/computed +//= require ./discourse/lib/formatter +//= require ./discourse/lib/eyeline //= require ./discourse/helpers/register-unbound //= require ./discourse/mixins/scrolling //= require_tree ./discourse/mixins @@ -36,7 +40,7 @@ //= require ./discourse/models/post-stream //= require ./discourse/models/topic-details //= require ./discourse/models/topic -//= require ./discourse/models/user_action +//= require ./discourse/models/user-action //= require ./discourse/models/composer //= require ./discourse/controllers/controller //= require ./discourse/controllers/discovery-sortable @@ -58,6 +62,7 @@ //= require ./discourse/lib/link-mentions //= require ./discourse/views/composer //= require ./discourse/lib/show-modal +//= require ./discourse/lib/screen-track //= require ./discourse/routes/discourse //= require ./discourse/routes/build-topic-route //= require ./discourse/routes/restricted-user diff --git a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 index db4637ce79e6e2..8f1a61976fb868 100644 --- a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 +++ b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 @@ -1,4 +1,4 @@ -moduleFor('controller:admin-user-badges', 'Admin User Badges Controller', { +moduleFor('controller:admin-user-badges', { needs: ['controller:adminUser'] }); diff --git a/test/javascripts/ember/resolver-test.js.es6 b/test/javascripts/ember/resolver-test.js.es6 index 14ed97094929b2..948add12d8b2fc 100644 --- a/test/javascripts/ember/resolver-test.js.es6 +++ b/test/javascripts/ember/resolver-test.js.es6 @@ -15,7 +15,7 @@ function setTemplates(lookupTemplateStrings) { }); } -module("Resolver", { +module("lib:resolver", { setup: function() { originalTemplates = Ember.TEMPLATES; Ember.TEMPLATES = {}; diff --git a/test/javascripts/lib/avatar-template-test.js.es6 b/test/javascripts/lib/avatar-template-test.js.es6 index 6ad5cc860dfb49..c2f004c8da23f5 100644 --- a/test/javascripts/lib/avatar-template-test.js.es6 +++ b/test/javascripts/lib/avatar-template-test.js.es6 @@ -1,6 +1,6 @@ import avatarTemplate from 'discourse/lib/avatar-template'; -module('avatarTemplate'); +module('lib:avatar-template'); test("avatarTemplate", function(){ var oldCDN = Discourse.CDN; diff --git a/test/javascripts/lib/category-badge-test.js.es6 b/test/javascripts/lib/category-badge-test.js.es6 index 9dbe2f3f75d9a3..84d2c9c9ae209e 100644 --- a/test/javascripts/lib/category-badge-test.js.es6 +++ b/test/javascripts/lib/category-badge-test.js.es6 @@ -1,4 +1,4 @@ -module("categoryBadgeHTML"); +module("lib:category-link"); import { categoryBadgeHTML } from "discourse/helpers/category-link"; diff --git a/test/javascripts/lib/click-track-test.js.es6 b/test/javascripts/lib/click-track-test.js.es6 index f79b87cdaa5834..337a594339d002 100644 --- a/test/javascripts/lib/click-track-test.js.es6 +++ b/test/javascripts/lib/click-track-test.js.es6 @@ -4,7 +4,7 @@ var windowOpen, win, redirectTo; -module("ClickTrack", { +module("lib:click-track", { setup: function() { // Prevent any of these tests from navigating away diff --git a/test/javascripts/lib/computed-test.js.es6 b/test/javascripts/lib/computed-test.js.es6 index cf4862f09cb047..4a228d33b394f2 100644 --- a/test/javascripts/lib/computed-test.js.es6 +++ b/test/javascripts/lib/computed-test.js.es6 @@ -1,4 +1,6 @@ -module("Discourse.Computed", { +import { setting, propertyEqual, propertyNotEqual, fmt, i18n, url } from 'discourse/lib/computed'; + +module("lib:computed", { setup: function() { sandbox.stub(I18n, "t", function(scope) { return "%@ translated: " + scope; @@ -12,8 +14,8 @@ module("Discourse.Computed", { test("setting", function() { var t = Em.Object.extend({ - vehicle: Discourse.computed.setting('vehicle'), - missingProp: Discourse.computed.setting('madeUpThing') + vehicle: setting('vehicle'), + missingProp: setting('madeUpThing') }).create(); Discourse.SiteSettings.vehicle = "airplane"; @@ -23,7 +25,7 @@ test("setting", function() { test("propertyEqual", function() { var t = Em.Object.extend({ - same: Discourse.computed.propertyEqual('cookies', 'biscuits') + same: propertyEqual('cookies', 'biscuits') }).create({ cookies: 10, biscuits: 10 @@ -36,7 +38,7 @@ test("propertyEqual", function() { test("propertyNotEqual", function() { var t = Em.Object.extend({ - diff: Discourse.computed.propertyNotEqual('cookies', 'biscuits') + diff: propertyNotEqual('cookies', 'biscuits') }).create({ cookies: 10, biscuits: 10 @@ -50,8 +52,8 @@ test("propertyNotEqual", function() { test("fmt", function() { var t = Em.Object.extend({ - exclaimyUsername: Discourse.computed.fmt('username', "!!! %@ !!!"), - multiple: Discourse.computed.fmt('username', 'mood', "%@ is %@") + exclaimyUsername: fmt('username', "!!! %@ !!!"), + multiple: fmt('username', 'mood', "%@ is %@") }).create({ username: 'eviltrout', mood: "happy" @@ -69,8 +71,8 @@ test("fmt", function() { test("i18n", function() { var t = Em.Object.extend({ - exclaimyUsername: Discourse.computed.i18n('username', "!!! %@ !!!"), - multiple: Discourse.computed.i18n('username', 'mood', "%@ is %@") + exclaimyUsername: i18n('username', "!!! %@ !!!"), + multiple: i18n('username', 'mood', "%@ is %@") }).create({ username: 'eviltrout', mood: "happy" @@ -90,7 +92,7 @@ test("url", function() { var t, testClass; testClass = Em.Object.extend({ - userUrl: Discourse.computed.url('username', "/users/%@") + userUrl: url('username', "/users/%@") }); t = testClass.create({ username: 'eviltrout' }); diff --git a/test/javascripts/lib/formatter-test.js.es6 b/test/javascripts/lib/formatter-test.js.es6 index 20a966f61612e7..1774a8c295b9c1 100644 --- a/test/javascripts/lib/formatter-test.js.es6 +++ b/test/javascripts/lib/formatter-test.js.es6 @@ -1,6 +1,8 @@ var clock; -module("Discourse.Formatter", { +import { relativeAge, autoUpdatingRelativeAge, updateRelativeAge, breakUp, number } from 'discourse/lib/formatter'; + +module("lib:formatter", { setup: function() { clock = sinon.useFakeTimers(new Date(2012,11,31,12,0).getTime()); }, @@ -17,7 +19,7 @@ var mins_ago = function(mins){ }; var formatMins = function(mins) { - return Discourse.Formatter.relativeAge(mins_ago(mins), {format: format, leaveAgo: leaveAgo}); + return relativeAge(mins_ago(mins), {format: format, leaveAgo: leaveAgo}); }; var formatHours = function(hours) { @@ -141,26 +143,24 @@ test("formating tiny dates", function() { Discourse.SiteSettings.relative_date_duration = originalValue; }); -module("Discourse.Formatter"); - test("autoUpdatingRelativeAge", function() { var d = moment().subtract(1, 'day').toDate(); - var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d)); + var $elem = $(autoUpdatingRelativeAge(d)); equal($elem.data('format'), "tiny"); equal($elem.data('time'), d.getTime()); equal($elem.attr('title'), undefined); - $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d, {title: true})); + $elem = $(autoUpdatingRelativeAge(d, {title: true})); equal($elem.attr('title'), moment(d).longDate()); - $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d,{format: 'medium', title: true, leaveAgo: true})); + $elem = $(autoUpdatingRelativeAge(d,{format: 'medium', title: true, leaveAgo: true})); equal($elem.data('format'), "medium-with-ago"); equal($elem.data('time'), d.getTime()); equal($elem.attr('title'), moment(d).longDate()); equal($elem.html(), '1 day ago'); - $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d,{format: 'medium'})); + $elem = $(autoUpdatingRelativeAge(d,{format: 'medium'})); equal($elem.data('format'), "medium"); equal($elem.data('time'), d.getTime()); equal($elem.attr('title'), undefined); @@ -170,25 +170,25 @@ test("autoUpdatingRelativeAge", function() { test("updateRelativeAge", function(){ var d = new Date(); - var $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d)); + var $elem = $(autoUpdatingRelativeAge(d)); $elem.data('time', d.getTime() - 2 * 60 * 1000); - Discourse.Formatter.updateRelativeAge($elem); + updateRelativeAge($elem); equal($elem.html(), "2m"); d = new Date(); - $elem = $(Discourse.Formatter.autoUpdatingRelativeAge(d, {format: 'medium', leaveAgo: true})); + $elem = $(autoUpdatingRelativeAge(d, {format: 'medium', leaveAgo: true})); $elem.data('time', d.getTime() - 2 * 60 * 1000); - Discourse.Formatter.updateRelativeAge($elem); + updateRelativeAge($elem); equal($elem.html(), "2 mins ago"); }); test("breakUp", function(){ - var b = function(s,hint){ return Discourse.Formatter.breakUp(s,hint); }; + var b = function(s,hint){ return breakUp(s,hint); }; equal(b("hello"), "hello"); equal(b("helloworld"), "helloworld"); @@ -201,9 +201,9 @@ test("breakUp", function(){ }); test("number", function() { - equal(Discourse.Formatter.number(123), "123", "it returns a string version of the number"); - equal(Discourse.Formatter.number("123"), "123", "it works with a string command"); - equal(Discourse.Formatter.number(NaN), "0", "it returns 0 for NaN"); - equal(Discourse.Formatter.number(3333), "3.3k", "it abbreviates thousands"); - equal(Discourse.Formatter.number(2499999), "2.5M", "it abbreviates millions"); + equal(number(123), "123", "it returns a string version of the number"); + equal(number("123"), "123", "it works with a string command"); + equal(number(NaN), "0", "it returns 0 for NaN"); + equal(number(3333), "3.3k", "it abbreviates thousands"); + equal(number(2499999), "2.5M", "it abbreviates millions"); }); diff --git a/test/javascripts/mixins/selected-posts-count-test.js.es6 b/test/javascripts/mixins/selected-posts-count-test.js.es6 index 9533acdce5a1f7..b07122fc5fa254 100644 --- a/test/javascripts/mixins/selected-posts-count-test.js.es6 +++ b/test/javascripts/mixins/selected-posts-count-test.js.es6 @@ -1,4 +1,4 @@ -module("SelectedPostsCount"); +module("mixin:selected-posts-count"); import SelectedPostsCount from 'discourse/mixins/selected-posts-count'; import Topic from 'discourse/models/topic'; diff --git a/test/javascripts/mixins/singleton-test.js.es6 b/test/javascripts/mixins/singleton-test.js.es6 index dba0f5ab728d38..80f0846dac4d49 100644 --- a/test/javascripts/mixins/singleton-test.js.es6 +++ b/test/javascripts/mixins/singleton-test.js.es6 @@ -1,8 +1,10 @@ -module("Discourse.Singleton"); +import Singleton from 'discourse/mixins/singleton'; + +module("mixin:singleton"); test("current", function() { var DummyModel = Ember.Object.extend({}); - DummyModel.reopenClass(Discourse.Singleton); + DummyModel.reopenClass(Singleton); var current = DummyModel.current(); present(current, 'current returns the current instance'); @@ -12,7 +14,7 @@ test("current", function() { test("currentProp reading", function() { var DummyModel = Ember.Object.extend({}); - DummyModel.reopenClass(Discourse.Singleton); + DummyModel.reopenClass(Singleton); var current = DummyModel.current(); blank(DummyModel.currentProp('evil'), 'by default attributes are blank'); @@ -22,7 +24,7 @@ test("currentProp reading", function() { test("currentProp writing", function() { var DummyModel = Ember.Object.extend({}); - DummyModel.reopenClass(Discourse.Singleton); + DummyModel.reopenClass(Singleton); blank(DummyModel.currentProp('adventure'), 'by default attributes are blank'); var result = DummyModel.currentProp('adventure', 'time'); @@ -38,7 +40,7 @@ test("currentProp writing", function() { test("createCurrent", function() { var Shoe = Ember.Object.extend({}); - Shoe.reopenClass(Discourse.Singleton, { + Shoe.reopenClass(Singleton, { createCurrent: function() { return Shoe.create({toes: 5}); } @@ -50,7 +52,7 @@ test("createCurrent", function() { test("createCurrent that returns null", function() { var Missing = Ember.Object.extend({}); - Missing.reopenClass(Discourse.Singleton, { + Missing.reopenClass(Singleton, { createCurrent: function() { return null; } diff --git a/test/javascripts/models/session-test.js.es6 b/test/javascripts/models/session-test.js.es6 index d4d3ff5a552e2b..320b5fb3665f60 100644 --- a/test/javascripts/models/session-test.js.es6 +++ b/test/javascripts/models/session-test.js.es6 @@ -1,8 +1,8 @@ import Session from "discourse/models/session"; -module("Discourse.Session"); +module("model:session"); test('highestSeenByTopic', function() { - var session = Session.current(); + const session = Session.current(); deepEqual(session.get('highestSeenByTopic'), {}, "by default it returns an empty object"); }); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index f93e3879814971..48cbf025e319c9 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -79,6 +79,7 @@ var origDebounce = Ember.run.debounce, createPretendServer = require('helpers/create-pretender', null, null, false).default, fixtures = require('fixtures/site_fixtures', null, null, false).default, flushMap = require('discourse/models/store', null, null, false).flushMap, + ScrollingDOMMethods = require('discourse/mixins/scrolling', null, null, false).ScrollingDOMMethods, server; function dup(obj) { @@ -92,6 +93,7 @@ QUnit.testStart(function(ctx) { Discourse.SiteSettings = dup(Discourse.SiteSettingsOriginal); Discourse.BaseUri = "/"; Discourse.BaseUrl = "localhost"; + Discourse.Session.resetCurrent(); Discourse.User.resetCurrent(); Discourse.Site.resetCurrent(Discourse.Site.create(dup(fixtures['site.json'].site))); @@ -103,8 +105,8 @@ QUnit.testStart(function(ctx) { PreloadStore.reset(); window.sandbox = sinon.sandbox.create(); - window.sandbox.stub(Discourse.ScrollingDOMMethods, "bindOnScroll"); - window.sandbox.stub(Discourse.ScrollingDOMMethods, "unbindOnScroll"); + window.sandbox.stub(ScrollingDOMMethods, "bindOnScroll"); + window.sandbox.stub(ScrollingDOMMethods, "unbindOnScroll"); // Don't debounce in test unless we're testing debouncing if (ctx.module.indexOf('debounce') === -1) {