diff --git a/Gemfile b/Gemfile index 12e9d142932..1c88d6d1d23 100644 --- a/Gemfile +++ b/Gemfile @@ -48,8 +48,7 @@ gem 'onebox' gem 'http_accept_language', '~>2.0.5', require: false gem 'ember-rails', '0.18.5' -gem 'ember-source', '2.10.0' -gem 'ember-handlebars-template', '0.7.5' +gem 'ember-source', '2.4.6' gem 'barber' gem 'babel-transpiler' diff --git a/Gemfile.lock b/Gemfile.lock index 60ff724ccb8..a44a4b3ff11 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -52,7 +52,7 @@ GEM babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) execjs (~> 2.0) - barber (0.11.2) + barber (0.11.1) ember-source (>= 1.0, < 3) execjs (>= 1.2, < 3) better_errors (2.1.1) @@ -82,7 +82,7 @@ GEM email_reply_trimmer (0.1.6) ember-data-source (2.2.1) ember-source (>= 1.8, < 3.0) - ember-handlebars-template (0.7.5) + ember-handlebars-template (0.7.4) barber (>= 0.11.0) sprockets (>= 3.3, < 4) ember-rails (0.18.5) @@ -92,7 +92,7 @@ GEM ember-source (>= 1.1.0) jquery-rails (>= 1.0.17) railties (>= 3.1) - ember-source (2.10.0) + ember-source (2.4.6) erubis (2.7.0) eventmachine (1.2.0.1) excon (0.53.0) @@ -231,7 +231,7 @@ GEM pry (>= 0.9.10) puma (3.6.0) r2 (0.2.6) - rack (1.6.5) + rack (1.6.4) rack-mini-profiler (0.10.1) rack (>= 1.2.0) rack-openid (1.3.1) @@ -355,7 +355,7 @@ GEM spork-rails (4.0.0) rails (>= 3.0.0, < 5) spork (>= 1.0rc0) - sprockets (3.7.0) + sprockets (3.6.3) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.1.1) @@ -401,9 +401,8 @@ DEPENDENCIES discourse-qunit-rails discourse_fastimage (= 2.0.3) email_reply_trimmer (= 0.1.6) - ember-handlebars-template (= 0.7.5) ember-rails (= 0.18.5) - ember-source (= 2.10.0) + ember-source (= 2.4.6) excon execjs fabrication (= 2.9.8) diff --git a/app/assets/javascripts/admin/components/ace-editor.js.es6 b/app/assets/javascripts/admin/components/ace-editor.js.es6 index a03865c40ce..01773d2cbf8 100644 --- a/app/assets/javascripts/admin/components/ace-editor.js.es6 +++ b/app/assets/javascripts/admin/components/ace-editor.js.es6 @@ -36,7 +36,6 @@ export default Ember.Component.extend({ loadScript("/javascripts/ace/ace.js", { scriptTag: true }).then(() => { window.ace.require(['ace/ace'], loadedAce => { - if (!this.element || this.isDestroying || this.isDestroyed) { return; } const editor = loadedAce.edit(this.$('.ace')[0]); editor.setTheme("ace/theme/chrome"); 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 7ddc6f3ac4e..7d11fc86226 100644 --- a/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-badges-show.js.es6 @@ -68,7 +68,7 @@ export default Ember.Controller.extend(BufferedContent, { this.get('model').save(data).then(() => { if (newBadge) { const adminBadges = this.get('adminBadges.model'); - if (!adminBadges.includes(model)) { + if (!adminBadges.contains(model)) { adminBadges.pushObject(model); } this.transitionToRoute('adminBadges.show', model.get('id')); diff --git a/app/assets/javascripts/admin/templates/admin.hbs b/app/assets/javascripts/admin/templates/admin.hbs index 7f34c00b772..77904edc48b 100644 --- a/app/assets/javascripts/admin/templates/admin.hbs +++ b/app/assets/javascripts/admin/templates/admin.hbs @@ -23,7 +23,7 @@ {{nav-item route='admin.backups' label='admin.backups.title'}} {{/if}} {{nav-item route='adminPlugins' label='admin.plugins.title'}} - {{plugin-outlet name="admin-menu" connectorTagName="li"}} + {{plugin-outlet "admin-menu" tagName="li"}}
diff --git a/app/assets/javascripts/admin/templates/dashboard.hbs b/app/assets/javascripts/admin/templates/dashboard.hbs index ec7753ac6c9..e02a5a925ca 100644 --- a/app/assets/javascripts/admin/templates/dashboard.hbs +++ b/app/assets/javascripts/admin/templates/dashboard.hbs @@ -1,4 +1,4 @@ -{{plugin-outlet name="admin-dashboard-top"}} +{{plugin-outlet "admin-dashboard-top"}} {{#conditional-loading-spinner condition=loading}}
diff --git a/app/assets/javascripts/admin/templates/group.hbs b/app/assets/javascripts/admin/templates/group.hbs index 095b3f5f4b8..9f4f2a941ce 100644 --- a/app/assets/javascripts/admin/templates/group.hbs +++ b/app/assets/javascripts/admin/templates/group.hbs @@ -108,7 +108,7 @@ {{#if siteSettings.email_in}} {{text-field name="incoming_email" value=model.incoming_email placeholderKey="admin.groups.incoming_email_placeholder"}} - {{plugin-outlet name="group-email-in" args=(hash model=model)}} + {{plugin-outlet "group-email-in"}} {{/if}} {{/unless}} diff --git a/app/assets/javascripts/admin/templates/version-checks.hbs b/app/assets/javascripts/admin/templates/version-checks.hbs index 5fe53213f13..542020d8ebd 100644 --- a/app/assets/javascripts/admin/templates/version-checks.hbs +++ b/app/assets/javascripts/admin/templates/version-checks.hbs @@ -1,7 +1,7 @@
- {{custom-html name="upgrade-header"}} + {{custom-html 'upgrade-header'}} diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 96a2066c414..2a4085f785e 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -89,6 +89,7 @@ //= require_tree ./discourse/models //= require_tree ./discourse/components //= require_tree ./discourse/raw-views +//= require_tree ./discourse/views //= require_tree ./discourse/helpers //= require_tree ./discourse/templates //= require_tree ./discourse/routes diff --git a/app/assets/javascripts/discourse-common/resolver.js.es6 b/app/assets/javascripts/discourse-common/resolver.js.es6 index 19247192086..a69efc4e30b 100644 --- a/app/assets/javascripts/discourse-common/resolver.js.es6 +++ b/app/assets/javascripts/discourse-common/resolver.js.es6 @@ -10,23 +10,19 @@ export function setResolverOption(name, value) { _options[name] = value; } -export function getResolverOption(name) { - return _options[name]; -} - function parseName(fullName) { - const nameParts = fullName.split(":"); - const type = nameParts[0]; - let fullNameWithoutType = nameParts[1]; - const namespace = get(this, 'namespace'); - const root = namespace; + const nameParts = fullName.split(":"), + type = nameParts[0], fullNameWithoutType = nameParts[1], + name = fullNameWithoutType, + namespace = get(this, 'namespace'), + root = namespace; return { - fullName, - type, - fullNameWithoutType, - name: fullNameWithoutType, - root, + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, resolveMethodName: "resolve" + classify(type) }; } @@ -129,21 +125,12 @@ export function buildResolver(baseName) { } }, - findConnectorTemplate(parsedName) { - const full = parsedName.fullNameWithoutType.replace('components/', ''); - if (full.indexOf('connectors') === 0) { - return Ember.TEMPLATES[`javascripts/${full}`]; - } - - }, - resolveTemplate(parsedName) { return this.findPluginMobileTemplate(parsedName) || this.findPluginTemplate(parsedName) || this.findMobileTemplate(parsedName) || this.findTemplate(parsedName) || this.findLoadingTemplate(parsedName) || - this.findConnectorTemplate(parsedName) || Ember.TEMPLATES.not_found; }, diff --git a/app/assets/javascripts/discourse.js.es6 b/app/assets/javascripts/discourse.js.es6 index 140cb5f7eac..9012e8301b2 100644 --- a/app/assets/javascripts/discourse.js.es6 +++ b/app/assets/javascripts/discourse.js.es6 @@ -6,7 +6,7 @@ const _pluginCallbacks = []; const Discourse = Ember.Application.extend({ rootElement: '#main', _docTitle: document.title, - RAW_TEMPLATES: {}, + __TAGS_INCLUDED__: true, getURL(url) { if (!url) return url; diff --git a/app/assets/javascripts/discourse/components/badge-selector.js.es6 b/app/assets/javascripts/discourse/components/badge-selector.js.es6 index 8f0bd5ecfeb..315f7398a78 100644 --- a/app/assets/javascripts/discourse/components/badge-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/badge-selector.js.es6 @@ -1,5 +1,5 @@ import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { getOwner } from 'discourse-common/lib/get-owner'; export default Ember.Component.extend({ @computed('placeholderKey') @@ -18,6 +18,7 @@ export default Ember.Component.extend({ var self = this; var selectedBadges; + var template = getOwner(this).lookup('template:badge-selector-autocomplete.raw'); self.$('input').autocomplete({ allowAny: false, items: _.isArray(this.get('badgeNames')) ? this.get('badgeNames') : [this.get('badgeNames')], @@ -42,7 +43,7 @@ export default Ember.Component.extend({ }); }); }, - template: findRawTemplate('badge-selector-autocomplete') + template: template }); } }); diff --git a/app/assets/javascripts/discourse/components/category-selector.js.es6 b/app/assets/javascripts/discourse/components/category-selector.js.es6 index 9cb3eec14ae..460a1dfdd65 100644 --- a/app/assets/javascripts/discourse/components/category-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/category-selector.js.es6 @@ -1,7 +1,7 @@ import { categoryBadgeHTML } from 'discourse/helpers/category-link'; import Category from 'discourse/models/category'; import { on, observes } from 'ember-addons/ember-computed-decorators'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { getOwner } from 'discourse-common/lib/get-owner'; export default Ember.Component.extend({ @observes('categories') @@ -13,6 +13,7 @@ export default Ember.Component.extend({ @on('didInsertElement') _initializeAutocomplete(opts) { const self = this, + template = getOwner(this).lookup('template:category-selector-autocomplete.raw'), regexp = new RegExp(`href=['\"]${Discourse.getURL('/c/')}([^'\"]+)`); this.$('input').autocomplete({ @@ -40,7 +41,7 @@ export default Ember.Component.extend({ self.set('categories', categories); }); }, - template: findRawTemplate('category-selector-autocomplete'), + template, transformComplete(category) { return categoryBadgeHTML(category, {allowUncategorized: true}); } diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 7473ff08d8c..55b69c64a1c 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -6,7 +6,7 @@ import { linkSeenTagHashtags, fetchUnseenTagHashtags } from 'discourse/lib/link- import { load } from 'pretty-text/oneboxer'; import { ajax } from 'discourse/lib/ajax'; import InputValidation from 'discourse/models/input-validation'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { getOwner } from 'discourse-common/lib/get-owner'; import { tinyAvatar, displayErrorForUpload, getUploadMarkdown, @@ -62,9 +62,10 @@ export default Ember.Component.extend({ @on('didInsertElement') _composerEditorInit() { const topicId = this.get('topic.id'); + const template = getOwner(this).lookup('template:user-selector-autocomplete.raw'); const $input = this.$('.d-editor-input'); $input.autocomplete({ - template: findRawTemplate('user-selector-autocomplete'), + template, dataSource: term => userSearch({ term, topicId, includeGroups: true }), key: "@", transformComplete: v => v.username || v.name diff --git a/app/assets/javascripts/discourse/components/composer-title.js.es6 b/app/assets/javascripts/discourse/components/composer-title.js.es6 index 8db46e574bf..fd8f89cb82b 100644 --- a/app/assets/javascripts/discourse/components/composer-title.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-title.js.es6 @@ -51,8 +51,6 @@ export default Ember.Component.extend({ }, _checkForUrl() { - if (!this.element || this.isDestroying || this.isDestroyed) { return; } - if (this.get('isAbsoluteUrl') && (this.get('composer.reply')||"").length === 0) { // Try to onebox. If success, update post body and title. diff --git a/app/assets/javascripts/discourse/components/custom-html.js.es6 b/app/assets/javascripts/discourse/components/custom-html.js.es6 deleted file mode 100644 index c5df7fb51ed..00000000000 --- a/app/assets/javascripts/discourse/components/custom-html.js.es6 +++ /dev/null @@ -1,20 +0,0 @@ -import { getCustomHTML } from 'discourse/helpers/custom-html'; -import { getOwner } from 'discourse-common/lib/get-owner'; - -export default Ember.Component.extend({ - init() { - this._super(); - const name = this.get('name'); - const html = getCustomHTML(name); - - if (html) { - this.set('html', html); - this.set('layoutName', 'components/custom-html-container'); - } else { - const template = getOwner(this).lookup(`template:${name}`); - if (template) { - this.set('layoutName', name); - } - } - } -}); diff --git a/app/assets/javascripts/discourse/components/d-editor.js.es6 b/app/assets/javascripts/discourse/components/d-editor.js.es6 index b4b3c31fb39..6e43dfde817 100644 --- a/app/assets/javascripts/discourse/components/d-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/d-editor.js.es6 @@ -11,7 +11,6 @@ import { translations } from 'pretty-text/emoji/data'; import { emojiSearch } from 'pretty-text/emoji'; import { emojiUrlFor } from 'discourse/lib/text'; import { getRegister } from 'discourse-common/lib/get-owner'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; import deprecated from 'discourse-common/lib/deprecated'; // Our head can be a static string or a function that returns a string @@ -298,10 +297,11 @@ export default Ember.Component.extend({ }, _applyCategoryHashtagAutocomplete() { + const template = this.register.lookup('template:category-tag-autocomplete.raw'); const siteSettings = this.siteSettings; this.$('.d-editor-input').autocomplete({ - template: findRawTemplate('category-tag-autocomplete'), + template: template, key: '#', transformComplete(obj) { if (obj.model) { @@ -323,10 +323,11 @@ export default Ember.Component.extend({ if (!this.siteSettings.enable_emoji) { return; } const register = this.register; + const template = this.register.lookup('template:emoji-selector-autocomplete.raw'); const self = this; $editorInput.autocomplete({ - template: findRawTemplate('emoji-selector-autocomplete'), + template: template, key: ":", afterComplete(text) { self.set('value', text); diff --git a/app/assets/javascripts/discourse/components/group-selector.js.es6 b/app/assets/javascripts/discourse/components/group-selector.js.es6 index 4beb5a3a932..4f4fa0f6a5e 100644 --- a/app/assets/javascripts/discourse/components/group-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/group-selector.js.es6 @@ -1,5 +1,5 @@ import { on, observes, default as computed } from 'ember-addons/ember-computed-decorators'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { getOwner } from 'discourse-common/lib/get-owner'; export default Ember.Component.extend({ @computed('placeholderKey') @@ -19,6 +19,7 @@ export default Ember.Component.extend({ var selectedGroups; var groupNames = this.get('groupNames'); + var template = getOwner(this).lookup('template:group-selector-autocomplete.raw'); self.$('input').autocomplete({ allowAny: false, items: _.isArray(groupNames) ? groupNames : (Ember.isEmpty(groupNames)) ? [] : [groupNames], @@ -43,7 +44,7 @@ export default Ember.Component.extend({ }); }); }, - template: findRawTemplate('group-selector-autocomplete') + template: template }); } }); diff --git a/app/assets/javascripts/discourse/components/mount-widget.js.es6 b/app/assets/javascripts/discourse/components/mount-widget.js.es6 index 3c41721fe63..3c56961ff8c 100644 --- a/app/assets/javascripts/discourse/components/mount-widget.js.es6 +++ b/app/assets/javascripts/discourse/components/mount-widget.js.es6 @@ -23,6 +23,8 @@ export default Ember.Component.extend({ this._super(); const name = this.get('widget'); + (this.get('delegated') || []).forEach(m => this.set(m, m)); + this.register = getRegister(this); this._widgetClass = queryRegistry(name) || this.register.lookupFactory(`widget:${name}`); @@ -31,6 +33,7 @@ export default Ember.Component.extend({ console.error(`Error: Could not find widget: ${name}`); } + this._childEvents = []; this._connected = []; this._dispatched = []; diff --git a/app/assets/javascripts/discourse/components/plugin-connector.js.es6 b/app/assets/javascripts/discourse/components/plugin-connector.js.es6 deleted file mode 100644 index 21be7a7622c..00000000000 --- a/app/assets/javascripts/discourse/components/plugin-connector.js.es6 +++ /dev/null @@ -1,22 +0,0 @@ -export default Ember.Component.extend({ - - init() { - this._super(); - - const connector = this.get('connector'); - this.set('layoutName', connector.templateName); - - const args = this.get('args') || {}; - Object.keys(args).forEach(key => this.set(key, args[key])); - - const connectorClass = this.get('connector.connectorClass'); - connectorClass.setupComponent.call(this, args, this); - }, - - send(name, ...args) { - const connectorClass = this.get('connector.connectorClass'); - const action = connectorClass.actions[name]; - return action ? action.call(this, ...args) : this._super(name, ...args); - } - -}); diff --git a/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 deleted file mode 100644 index 91bf45560e9..00000000000 --- a/app/assets/javascripts/discourse/components/plugin-outlet.js.es6 +++ /dev/null @@ -1,51 +0,0 @@ -/** - A plugin outlet is an extension point for templates where other templates can - be inserted by plugins. - - ## Usage - - If your handlebars template has: - - ```handlebars - {{plugin-outlet name="evil-trout"}} - ``` - - Then any handlebars files you create in the `connectors/evil-trout` directory - will automatically be appended. For example: - - plugins/hello/assets/javascripts/discourse/templates/connectors/evil-trout/hello.hbs - - With the contents: - - ```handlebars - Hello World - ``` - - Will insert Hello World at that point in the template. - - ## Disabling - - If a plugin returns a disabled status, the outlets will not be wired up for it. - The list of disabled plugins is returned via the `Site` singleton. - -**/ -import { connectorsFor } from 'discourse/lib/plugin-connectors'; - -export default Ember.Component.extend({ - tagName: 'span', - connectors: null, - - init() { - this._super(); - const name = this.get('name'); - - if (name) { - const args = this.get('args'); - const connectors = connectorsFor(name).filter(con => { - return con.connectorClass.shouldRender(args, this); - }); - - this.set('connectors', connectors); - } - } -}); diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 23bdac794b4..51ec9b4483b 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -48,15 +48,12 @@ export default Em.Component.extend({ init() { this._super(); - Ember.run.scheduleOnce('afterRender', () => { - this._init(); - this._update(); - }); + this._init(); + this._update(); }, @observes('searchTerm') _updateOptions() { - this._update(); Ember.run.debounce(this, this._update, 250); }, diff --git a/app/assets/javascripts/discourse/components/tag-chooser.js.es6 b/app/assets/javascripts/discourse/components/tag-chooser.js.es6 index 578fb9a16d1..a8fa6bc1835 100644 --- a/app/assets/javascripts/discourse/components/tag-chooser.js.es6 +++ b/app/assets/javascripts/discourse/components/tag-chooser.js.es6 @@ -8,17 +8,10 @@ export default Ember.TextField.extend({ classNameBindings: [':tag-chooser'], attributeBindings: ['tabIndex', 'placeholderKey', 'categoryId'], - init() { - this._super(); + _initValue: function() { const tags = this.get('tags') || []; this.set('value', tags.join(", ")); - - if (this.get('allowCreate') !== false) { - this.set('allowCreate', this.site.get('can_create_tag')); - } - - this.set('termMatchesForbidden', false); - }, + }.on('init'), _valueChanged: function() { const tags = this.get('value').split(',').map(v => v.trim()).reject(v => v.length === 0).uniq(); @@ -39,13 +32,18 @@ export default Ember.TextField.extend({ } }.observes('tags'), - didInsertElement() { - this._super(); + _initializeTags: function() { + const site = this.site, + self = this, + filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); - const self = this; - const filterRegexp = new RegExp(this.site.tags_filter_regexp, "g"); + var limit = this.siteSettings.max_tags_per_topic; - let limit = this.siteSettings.max_tags_per_topic; + if (this.get('allowCreate') !== false) { + this.set('allowCreate', site.get('can_create_tag')); + } + + this.set('termMatchesForbidden', false); if (this.get('unlimitedTagCount')) { limit = null; @@ -79,7 +77,7 @@ export default Ember.TextField.extend({ callback(data); }, - createSearchChoice(term, data) { + createSearchChoice: function(term, data) { term = term.replace(filterRegexp, '').trim().toLowerCase(); // No empty terms, make sure the user has permission to create the tag @@ -91,14 +89,14 @@ export default Ember.TextField.extend({ return { id: term, text: term }; } }, - createSearchChoicePosition(list, item) { + createSearchChoicePosition: function(list, item) { // Search term goes on the bottom list.push(item); }, - formatSelection(data) { + formatSelection: function (data) { return data ? renderTag(this.text(data)) : undefined; }, - formatSelectionCssClass() { + formatSelectionCssClass: function(){ return "discourse-tag-select2"; }, formatResult: formatTag, @@ -129,11 +127,10 @@ export default Ember.TextField.extend({ } }, }); - }, + }.on('didInsertElement'), - willDestroyElement() { - this._super(); + _destroyTags: function() { this.$().select2('destroy'); - } + }.on('willDestroyElement') }); diff --git a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 index 13473c0e0f0..aeb9db8baab 100644 --- a/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-footer-buttons.js.es6 @@ -1,11 +1,17 @@ import computed from 'ember-addons/ember-computed-decorators'; +import DelegatedActions from 'discourse/mixins/delegated-actions'; -export default Ember.Component.extend({ +export default Ember.Component.extend(DelegatedActions, { elementId: 'topic-footer-buttons', // Allow us to extend it layoutName: 'components/topic-footer-buttons', + init() { + this._super(); + this.delegateAll(this.get('topicDelegated')); + }, + @computed('topic.details.can_invite_to') canInviteTo(result) { return !this.site.mobileView && result; diff --git a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 b/app/assets/javascripts/discourse/components/topic-list-item.js.es6 index 583ba344a14..a38dd9c8f4c 100644 --- a/app/assets/javascripts/discourse/components/topic-list-item.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-list-item.js.es6 @@ -1,6 +1,6 @@ import computed from 'ember-addons/ember-computed-decorators'; import { bufferedRender } from 'discourse-common/lib/buffered-render'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { getOwner } from 'discourse-common/lib/get-owner'; export function showEntrance(e) { let target = $(e.target); @@ -32,7 +32,7 @@ export default Ember.Component.extend(bufferedRender({ }, buildBuffer(buffer) { - const template = findRawTemplate('list/topic-list-item'); + const template = getOwner(this).lookup('template:list/topic-list-item.raw'); if (template) { buffer.push(template(this)); } diff --git a/app/assets/javascripts/discourse/components/topic-progress.js.es6 b/app/assets/javascripts/discourse/components/topic-progress.js.es6 index 938c7085494..85cb5209552 100644 --- a/app/assets/javascripts/discourse/components/topic-progress.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-progress.js.es6 @@ -3,11 +3,17 @@ import { default as computed, observes } from 'ember-addons/ember-computed-decor export default Ember.Component.extend({ elementId: 'topic-progress-wrapper', classNameBindings: ['docked'], + expanded: false, docked: false, progressPosition: null, postStream: Ember.computed.alias('topic.postStream'), _streamPercentage: null, + init() { + this._super(); + (this.get('delegated') || []).forEach(m => this.set(m, m)); + }, + @computed('progressPosition') jumpTopDisabled(progressPosition) { return progressPosition <= 3; diff --git a/app/assets/javascripts/discourse/components/user-selector.js.es6 b/app/assets/javascripts/discourse/components/user-selector.js.es6 index 5fda51dec6f..94d6db9bfe4 100644 --- a/app/assets/javascripts/discourse/components/user-selector.js.es6 +++ b/app/assets/javascripts/discourse/components/user-selector.js.es6 @@ -1,7 +1,7 @@ import { observes } from 'ember-addons/ember-computed-decorators'; import TextField from 'discourse/components/text-field'; import userSearch from 'discourse/lib/user-search'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; +import { getOwner } from 'discourse-common/lib/get-owner'; export default TextField.extend({ @observes('usernames') @@ -31,7 +31,7 @@ export default TextField.extend({ } this.$().val(this.get('usernames')).autocomplete({ - template: findRawTemplate('user-selector-autocomplete'), + template: getOwner(this).lookup('template:user-selector-autocomplete.raw'), disabled: this.get('disabled'), single: this.get('single'), allowAny: this.get('allowAny'), diff --git a/app/assets/javascripts/discourse/controllers/application.js.es6 b/app/assets/javascripts/discourse/controllers/application.js.es6 index 78402acd259..dc9f45d3220 100644 --- a/app/assets/javascripts/discourse/controllers/application.js.es6 +++ b/app/assets/javascripts/discourse/controllers/application.js.es6 @@ -15,10 +15,4 @@ export default Ember.Controller.extend({ loginRequired() { return Discourse.SiteSettings.login_required && !Discourse.User.current(); }, - - actions: { - appRouteAction(name) { - return this.send(name); - } - } }); diff --git a/app/assets/javascripts/discourse/controllers/create-account.js.es6 b/app/assets/javascripts/discourse/controllers/create-account.js.es6 index 50bd0188021..ea7dee44093 100644 --- a/app/assets/javascripts/discourse/controllers/create-account.js.es6 +++ b/app/assets/javascripts/discourse/controllers/create-account.js.es6 @@ -114,7 +114,7 @@ export default Ember.Controller.extend(ModalFunctionality, { email = this.get("accountEmail"); - if (this.get('rejectedEmails').includes(email)) { + if (this.get('rejectedEmails').contains(email)) { return InputValidation.create({ failed: true, reason: I18n.t('user.email.invalid') @@ -314,7 +314,7 @@ export default Ember.Controller.extend(ModalFunctionality, { }); } - if (this.get('rejectedPasswords').includes(password)) { + if (this.get('rejectedPasswords').contains(password)) { return InputValidation.create({ failed: true, reason: I18n.t('user.password.common') diff --git a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 b/app/assets/javascripts/discourse/controllers/tags-show.js.es6 index 1e8e0c2fa0b..0e8e15db508 100644 --- a/app/assets/javascripts/discourse/controllers/tags-show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/tags-show.js.es6 @@ -16,7 +16,7 @@ if (customNavItemHref) { if (navItem.get('tagId')) { var name = navItem.get('name'); - if ( !Discourse.Site.currentProp('filters').includes(name) ) { + if ( !Discourse.Site.currentProp('filters').contains(name) ) { return null; } diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index bc42e729259..4b9650fd98c 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -32,6 +32,30 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { filter: null, quoteState: null, + topicDelegated: [ + 'toggleMultiSelect', + 'deleteTopic', + 'recoverTopic', + 'toggleClosed', + 'showAutoClose', + 'showFeatureTopic', + 'showChangeTimestamp', + 'toggleArchived', + 'toggleVisibility', + 'convertToPublicTopic', + 'convertToPrivateMessage', + 'jumpTop', + 'jumpToPost', + 'jumpToPostPrompt', + 'jumpToIndex', + 'jumpBottom', + 'replyToPost', + 'toggleArchiveMessage', + 'showInvite', + 'toggleBookmark', + 'showFlagTopic' + ], + updateQueryParams() { const postStream = this.get('model.postStream'); this.setProperties(postStream.get('streamFilters')); @@ -151,22 +175,6 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { actions: { - showPostFlags(post) { - return this.send('showFlags', post); - }, - - topicRouteAction(name, model) { - return this.send(name, model); - }, - - openAutoClose() { - this.send('showAutoClose'); - }, - - openFeatureTopic() { - this.send('showFeatureTopic'); - }, - deselectText() { this.get('quoteState').setProperties({ buffer: null, postId: null }); }, @@ -810,7 +818,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, { postSelected(post) { if (this.get('allPostsSelected')) { return true; } - if (this.get('selectedPosts').includes(post)) { return true; } + if (this.get('selectedPosts').contains(post)) { return true; } if (this.get('selectedReplies').findBy('post_number', post.get('reply_to_post_number'))) { return true; } return false; diff --git a/app/assets/javascripts/discourse/helpers/category-badge.js.es6 b/app/assets/javascripts/discourse/helpers/category-badge.js.es6 index 41aad35a597..74d28b745db 100644 --- a/app/assets/javascripts/discourse/helpers/category-badge.js.es6 +++ b/app/assets/javascripts/discourse/helpers/category-badge.js.es6 @@ -2,9 +2,6 @@ import { categoryLinkHTML } from 'discourse/helpers/category-link'; import { registerUnbound } from 'discourse-common/lib/helpers'; registerUnbound('category-badge', function(cat, options) { - return categoryLinkHTML(cat, { - hideParent: options.hideParent, - allowUncategorized: options.allowUncategorized, - link: false - }); + options.link = false; + return categoryLinkHTML(cat, options); }); diff --git a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 index 1fbc94eb832..29b98c46cf6 100644 --- a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 +++ b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 @@ -1,3 +1,5 @@ +const { registerKeyword } = Ember.__loader.require("ember-htmlbars/keywords"); +const { internal } = Ember.__loader.require('htmlbars-runtime'); import PreloadStore from 'preload-store'; let _customizations = {}; @@ -22,3 +24,36 @@ export function clearHTMLCache() { export function setCustomHTML(key, html) { _customizations[key] = html; } + +registerKeyword('custom-html', { + setupState(state, env, scope, params) { + return { htmlKey: env.hooks.getValue(params[0]) }; + }, + + render(renderNode, env, scope, params, hash, template, inverse, visitor) { + let state = renderNode.getState(); + if (!state.htmlKey) { return true; } + + const html = getCustomHTML(state.htmlKey); + if (html) { + const htmlHash = { html }; + env.hooks.component(renderNode, + env, + scope, + 'custom-html-container', + params, + htmlHash, + { default: template, inverse }, + visitor); + return true; + } + + template = env.owner.lookup(`template:${state.htmlKey}`); + if (template) { + internal.hostBlock(renderNode, env, scope, template.raw, null, null, visitor, function(options) { + options.templates.template.yield(); + }); + } + return true; + } +}); diff --git a/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 new file mode 100644 index 00000000000..32fd7d8bae9 --- /dev/null +++ b/app/assets/javascripts/discourse/helpers/plugin-outlet.js.es6 @@ -0,0 +1,138 @@ +/** + A plugin outlet is an extension point for templates where other templates can + be inserted by plugins. + + ## Usage + + If your handlebars template has: + + ```handlebars + {{plugin-outlet "evil-trout"}} + ``` + + Then any handlebars files you create in the `connectors/evil-trout` directory + will automatically be appended. For example: + + plugins/hello/assets/javascripts/discourse/templates/connectors/evil-trout/hello.hbs + + With the contents: + + ```handlebars + Hello World + ``` + + Will insert Hello World at that point in the template. + + ## Disabling + + If a plugin returns a disabled status, the outlets will not be wired up for it. + The list of disabled plugins is returned via the `Site` singleton. + +**/ +let _connectorCache, _templateCache; + +function findOutlets(collection, callback) { + const disabledPlugins = Discourse.Site.currentProp('disabled_plugins') || []; + + Object.keys(collection).forEach(function(res) { + if (res.indexOf("/connectors/") !== -1) { + // Skip any disabled plugins + for (let i=0; i { + const connector = _connectorCache[outletName]; + (connector || []).forEach(s => { + _templateCache.push(s.template); + s.templateId = parseInt(_templateCache.length - 1); + }); + }); +} + +// unbound version of outlets, only has a template +Handlebars.registerHelper('plugin-outlet', function(name) { + if (!_connectorCache) { buildConnectorCache(); } + + const connector = _connectorCache[name]; + if (connector && connector.length) { + const output = connector.map(c => c.template({context: this})); + return new Handlebars.SafeString(output.join("")); + } +}); + +const { registerKeyword } = Ember.__loader.require("ember-htmlbars/keywords"); +const { internal } = Ember.__loader.require('htmlbars-runtime'); + +registerKeyword('plugin-outlet', { + setupState(state, env, scope, params) { + if (!_connectorCache) { buildConnectorCache(); } + return { outletName: env.hooks.getValue(params[0]) }; + }, + + render(renderNode, env, scope, params, hash, template, inverse, visitor) { + let state = renderNode.getState(); + if (!state.outletName) { return true; } + const connector = _connectorCache[state.outletName]; + if (!connector || connector.length === 0) { return true; } + + const listTemplate = Ember.TEMPLATES['outlet-list']; + listTemplate.raw.locals = ['templateId', 'outletClasses', 'tagName']; + + internal.hostBlock(renderNode, env, scope, listTemplate.raw, null, null, visitor, function(options) { + connector.forEach(source => { + const tid = source.templateId; + options.templates.template.yieldItem(`d-outlet-${tid}`, [ + tid, + source.classNames, + hash.tagName || 'div' + ]); + }); + }); + return true; + } +}); + +registerKeyword('connector', function(morph, env, scope, params, hash, template, inverse, visitor) { + template = _templateCache[parseInt(env.hooks.getValue(hash.templateId))]; + + env.hooks.component(morph, + env, + scope, + 'connector-container', + params, + hash, + { default: template.raw, inverse }, + visitor); + return true; +}); diff --git a/app/assets/javascripts/discourse/helpers/raw-plugin-outlet.js.es6 b/app/assets/javascripts/discourse/helpers/raw-plugin-outlet.js.es6 deleted file mode 100644 index ccea57e1e22..00000000000 --- a/app/assets/javascripts/discourse/helpers/raw-plugin-outlet.js.es6 +++ /dev/null @@ -1,9 +0,0 @@ -import { connectorsFor } from 'discourse/lib/plugin-connectors'; - -Handlebars.registerHelper('raw-plugin-outlet', function(args) { - const connectors = connectorsFor(args.hash.name); - if (connectors.length) { - const output = connectors.map(c => c.template({context: this})); - return new Handlebars.SafeString(output.join("")); - } -}); diff --git a/app/assets/javascripts/discourse/helpers/raw.js.es6 b/app/assets/javascripts/discourse/helpers/raw.js.es6 index 7f3d8b247b0..a6cf56e31f9 100644 --- a/app/assets/javascripts/discourse/helpers/raw.js.es6 +++ b/app/assets/javascripts/discourse/helpers/raw.js.es6 @@ -1,10 +1,8 @@ import { registerUnbound } from 'discourse-common/lib/helpers'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; let _injections; function renderRaw(ctx, container, template, templateName, params) { - params = jQuery.extend({}, params); params.parent = params.parent || ctx; if (!params.view) { @@ -34,9 +32,9 @@ registerUnbound('raw', function(templateName, params) { templateName = templateName.replace('.', '/'); const container = Discourse.__container__; - const template = findRawTemplate(templateName); + var template = container.lookup('template:' + templateName + '.raw'); if (!template) { - console.warn('Could not find raw template: ' + templateName); + Ember.warn('Could not find raw template: ' + templateName); return; } return renderRaw(this, container, template, templateName, params); diff --git a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 index 3666df1b580..d3b6e12f125 100644 --- a/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 +++ b/app/assets/javascripts/discourse/lib/emoji/toolbar.js.es6 @@ -2,7 +2,6 @@ import groups from 'discourse/lib/emoji/groups'; import KeyValueStore from "discourse/lib/key-value-store"; import { emojiList } from 'pretty-text/emoji'; import { emojiUrlFor } from 'discourse/lib/text'; -import { findRawTemplate } from 'discourse/lib/raw-templates'; const keyValueStore = new KeyValueStore("discourse_emojis_"); const EMOJI_USAGE = "emojiUsage"; @@ -152,7 +151,7 @@ function render(page, offset, options) { }; $('.emoji-modal', options.appendTo).remove(); - const template = findRawTemplate('emoji-toolbar'); + const template = options.register.lookup('template:emoji-toolbar.raw'); options.appendTo.append(template(model)); bindEvents(page, offset, options); diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index cc24df86de8..4edc9a452ac 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -5,16 +5,13 @@ const _loading = {}; function loadWithTag(path, cb) { const head = document.getElementsByTagName('head')[0]; - let finished = false; let s = document.createElement('script'); s.src = path; - if (Ember.Test) { - Ember.Test.registerWaiter(() => finished); - } + if (Ember.Test) { Ember.Test.pendingAjaxRequests++; } head.appendChild(s); s.onload = s.onreadystatechange = function(_, abort) { - finished = true; + if (Ember.Test) { Ember.Test.pendingAjaxRequests--; } if (abort || !s.readyState || s.readyState === "loaded" || s.readyState === "complete") { s = s.onload = s.onreadystatechange = null; if (!abort) { diff --git a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 index 7419562b747..c4833d4b45e 100644 --- a/app/assets/javascripts/discourse/lib/plugin-api.js.es6 +++ b/app/assets/javascripts/discourse/lib/plugin-api.js.es6 @@ -11,7 +11,6 @@ import { preventCloak } from 'discourse/widgets/post-stream'; import { h } from 'virtual-dom'; import { addFlagProperty } from 'discourse/components/site-header'; import { addPopupMenuOptionsCallback } from 'discourse/controllers/composer'; -import { extraConnectorClass } from 'discourse/lib/plugin-connectors'; class PluginApi { constructor(version, container) { @@ -331,33 +330,12 @@ class PluginApi { addStorePluralization(thing, plural) { this.container.lookup("store:main").addPluralization(thing, plural); } - - /** - * Register a Connector class for a particular outlet and connector. - * - * For example, if the outlet is `user-profile-primary` and your connector - * template is called `my-connector.hbs`: - * - * ```javascript - * api.registerConnectorClass('user-profile-primary', 'my-connector', { - * shouldRender(args, component) { - * return component.siteSettings.my_plugin_enabled; - * } - * }); - * ``` - * - * For more information on connector classes, see: - * https://meta.discourse.org/t/important-changes-to-plugin-outlets-for-ember-2-10/54136 - **/ - registerConnectorClass(outletName, connectorName, klass) { - extraConnectorClass(`${outletName}/${connectorName}`, klass); - } } let _pluginv01; function getPluginApi(version) { version = parseFloat(version); - if (version <= 0.6) { + if (version <= 0.5) { if (!_pluginv01) { _pluginv01 = new PluginApi(version, Discourse.__container__); } diff --git a/app/assets/javascripts/discourse/lib/plugin-connectors.js.es6 b/app/assets/javascripts/discourse/lib/plugin-connectors.js.es6 deleted file mode 100644 index 73ed1d9678d..00000000000 --- a/app/assets/javascripts/discourse/lib/plugin-connectors.js.es6 +++ /dev/null @@ -1,81 +0,0 @@ -let _connectorCache; -let _extraConnectorClasses = {}; -let _classPaths; - -export function resetExtraClasses() { - _extraConnectorClasses = {}; - _classPaths = undefined; -} - -// Note: In plugins, define a class by path and it will be wired up automatically -// eg: discourse/connectors//.js.es6 -export function extraConnectorClass(name, obj) { - _extraConnectorClasses[name] = obj; -} - -const DefaultConnectorClass = { - actions: {}, - shouldRender: () => true, - setupComponent() { } -}; - -function findOutlets(collection, callback) { - const disabledPlugins = Discourse.Site.currentProp('disabled_plugins') || []; - - Object.keys(collection).forEach(function(res) { - if (res.indexOf("/connectors/") !== -1) { - // Skip any disabled plugins - for (let i=0; i { - _classPaths[`${outlet}/${un}`] = require(res).default; - }); - } - - const id = `${outletName}/${uniqueName}`; - let foundClass = _extraConnectorClasses[id] || _classPaths[id]; - - return foundClass ? - jQuery.extend({}, DefaultConnectorClass, foundClass) : - DefaultConnectorClass; -} - -function buildConnectorCache() { - _connectorCache = {}; - - findOutlets(Ember.TEMPLATES, function(outletName, resource, uniqueName) { - _connectorCache[outletName] = _connectorCache[outletName] || []; - - _connectorCache[outletName].push({ - templateName: resource.replace('javascripts/', ''), - template: Ember.TEMPLATES[resource], - classNames: `${outletName}-outlet ${uniqueName}`, - connectorClass: findClass(outletName, uniqueName) - }); - }); -} - -export function connectorsFor(outletName) { - if (!_connectorCache) { buildConnectorCache(); } - return _connectorCache[outletName] || []; -} diff --git a/app/assets/javascripts/discourse/lib/raw-templates.js.es6 b/app/assets/javascripts/discourse/lib/raw-templates.js.es6 deleted file mode 100644 index 5df3190b5a3..00000000000 --- a/app/assets/javascripts/discourse/lib/raw-templates.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -import { getResolverOption } from 'discourse-common/resolver'; - -export function findRawTemplate(name) { - if (getResolverOption('mobileView')) { - return Discourse.RAW_TEMPLATES[`mobile/${name}`] || - Discourse.RAW_TEMPLATES[name]; - } - - return Discourse.RAW_TEMPLATES[name]; -} diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index ed2457e065f..c0a50a83044 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -11,22 +11,26 @@ export default function(name, opts) { const controllerName = opts.admin ? `modals/${name}` : name; + const viewClass = container.lookupFactory('view:' + name); const controller = container.lookup('controller:' + controllerName); - const templateName = opts.templateName || Ember.String.dasherize(name); + if (viewClass) { + route.render(name, { into: 'modal', outlet: 'modalBody' }); + } else { + const templateName = opts.templateName || Ember.String.dasherize(name); - const renderArgs = { into: 'modal', outlet: 'modalBody'}; - if (controller) { renderArgs.controller = controllerName; } + const renderArgs = { into: 'modal', outlet: 'modalBody'}; + if (controller) { renderArgs.controller = controllerName; } - if (opts.addModalBodyView) { - renderArgs.view = 'modal-body'; - } + if (opts.addModalBodyView) { + renderArgs.view = 'modal-body'; + } - - const modalName = `modal/${templateName}`; - const fullName = opts.admin ? `admin/templates/${modalName}` : modalName; - route.render(fullName, renderArgs); - if (opts.title) { - modalController.set('title', I18n.t(opts.title)); + const modalName = `modal/${templateName}`; + const fullName = opts.admin ? `admin/templates/${modalName}` : modalName; + route.render(fullName, renderArgs); + if (opts.title) { + modalController.set('title', I18n.t(opts.title)); + } } if (controller) { diff --git a/app/assets/javascripts/discourse/mapping-router.js.es6 b/app/assets/javascripts/discourse/mapping-router.js.es6 index 21e91303ec1..31d7c2c2eaf 100644 --- a/app/assets/javascripts/discourse/mapping-router.js.es6 +++ b/app/assets/javascripts/discourse/mapping-router.js.es6 @@ -1,14 +1,8 @@ -import { defaultHomepage } from 'discourse/lib/utilities'; const rootURL = Discourse.BaseUri; const BareRouter = Ember.Router.extend({ rootURL, - location: Ember.testing ? 'none': 'discourse-location', - - handleURL(url) { - if (url === "/") { url = defaultHomepage(); } - return this._super(url); - } + location: Ember.testing ? 'none': 'discourse-location' }); // Ember's router can't be extended. We need to allow plugins to add routes to routes that were defined @@ -73,8 +67,7 @@ class RouteNode { if (paths.length > 1) { paths.filter(p => p !== this.opts.path).forEach(path => { const newOpts = jQuery.extend({}, this.opts, { path }); - console.log(`warning: we can't have duplicate route names anymore`, newOpts); - // router.route(this.name, newOpts, builder); + router.route(this.name, newOpts, builder); }); } } diff --git a/app/assets/javascripts/discourse/mixins/delegate-actions.js.es6 b/app/assets/javascripts/discourse/mixins/delegate-actions.js.es6 new file mode 100644 index 00000000000..ce3e46a56f5 --- /dev/null +++ b/app/assets/javascripts/discourse/mixins/delegate-actions.js.es6 @@ -0,0 +1,6 @@ +export default Ember.Mixin.create({ + init() { + this._super(); + (this.get('delegated') || []).forEach(m => this.set(m, m)); + }, +}); diff --git a/app/assets/javascripts/discourse/mixins/delegated-actions.js.es6 b/app/assets/javascripts/discourse/mixins/delegated-actions.js.es6 new file mode 100644 index 00000000000..2aae916a9df --- /dev/null +++ b/app/assets/javascripts/discourse/mixins/delegated-actions.js.es6 @@ -0,0 +1,12 @@ +export default Ember.Mixin.create({ + delegateAll(actionNames) { + actionNames = actionNames || []; + + this.actions = this.actions || {}; + + actionNames.forEach(m => { + this.actions[m] = function() { this.sendAction(m); }; + this.set(m, m); + }); + } +}); diff --git a/app/assets/javascripts/discourse/models/nav-item.js.es6 b/app/assets/javascripts/discourse/models/nav-item.js.es6 index d28b6728345..58845c2d51f 100644 --- a/app/assets/javascripts/discourse/models/nav-item.js.es6 +++ b/app/assets/javascripts/discourse/models/nav-item.js.es6 @@ -86,9 +86,9 @@ NavItem.reopenClass({ testName = name.split("/")[0], anonymous = !Discourse.User.current(); - if (anonymous && !Discourse.Site.currentProp('anonymous_top_menu_items').includes(testName)) return null; + if (anonymous && !Discourse.Site.currentProp('anonymous_top_menu_items').contains(testName)) return null; if (!Discourse.Category.list() && testName === "categories") return null; - if (!Discourse.Site.currentProp('top_menu_items').includes(testName)) return null; + if (!Discourse.Site.currentProp('top_menu_items').contains(testName)) return null; var args = { name: name, hasIcon: name === "unread" }, extra = null, self = this; if (opts.category) { args.category = opts.category; } diff --git a/app/assets/javascripts/discourse/models/post-stream.js.es6 b/app/assets/javascripts/discourse/models/post-stream.js.es6 index 32cfa6427f7..a711303f228 100644 --- a/app/assets/javascripts/discourse/models/post-stream.js.es6 +++ b/app/assets/javascripts/discourse/models/post-stream.js.es6 @@ -168,7 +168,7 @@ export default RestModel.extend({ this.set('summary', false); let jump = false; - if (userFilters.includes(username)) { + if (userFilters.contains(username)) { userFilters.removeObject(username); } else { userFilters.addObject(username); @@ -256,7 +256,7 @@ export default RestModel.extend({ return this.findPostsByIds(gap).then(posts => { posts.forEach(p => { const stored = this.storePost(p); - if (!currentPosts.includes(stored)) { + if (!currentPosts.contains(stored)) { currentPosts.insertAt(postIdx++, stored); } }); @@ -410,7 +410,7 @@ export default RestModel.extend({ if (stored) { const posts = this.get('posts'); - if (!posts.includes(stored)) { + if (!posts.contains(stored)) { if (!this.get('loadingBelow')) { this.get('postsWithPlaceholders').appendPost(() => posts.pushObject(stored)); } else { diff --git a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 index 51849ef4025..5e3de23fee3 100644 --- a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 @@ -17,7 +17,7 @@ function inject() { } function injectAll(app, name) { - inject(app, name, 'controller', 'component', 'route', 'model', 'adapter'); + inject(app, name, 'controller', 'component', 'route', 'view', 'model', 'adapter'); } export default { diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index 38cebdd9659..04da387763c 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -1,3 +1,5 @@ +import { defaultHomepage } from 'discourse/lib/utilities'; + export default function() { // Error page this.route('exception', { path: '/exception' }); @@ -43,6 +45,9 @@ export default function() { this.route('categoryNone', { path: '/c/:slug/none' }); this.route('category', { path: '/c/:parentSlug/:slug' }); this.route('categoryWithID', { path: '/c/:parentSlug/:slug/:id' }); + + // homepage + this.route(defaultHomepage(), { path: '/' }); }); this.route('groups', { resetNamespace: true }); diff --git a/app/assets/javascripts/discourse/templates/additional-composer-buttons.hbs b/app/assets/javascripts/discourse/templates/additional-composer-buttons.hbs new file mode 100644 index 00000000000..43ccd1b392d --- /dev/null +++ b/app/assets/javascripts/discourse/templates/additional-composer-buttons.hbs @@ -0,0 +1 @@ +{{!-- THIS IS AN EMPTY TEMPLATE THAT NEEDS TO BE OVERWRITTEN --}} diff --git a/app/assets/javascripts/discourse/templates/application.hbs b/app/assets/javascripts/discourse/templates/application.hbs index bf2de38396f..8a074e2eb37 100644 --- a/app/assets/javascripts/discourse/templates/application.hbs +++ b/app/assets/javascripts/discourse/templates/application.hbs @@ -1,17 +1,17 @@ -{{plugin-outlet name="above-site-header"}} +{{plugin-outlet "above-site-header"}} {{site-header canSignUp=canSignUp - showCreateAccount=(action "appRouteAction" "showCreateAccount") - showLogin=(action "appRouteAction" "showLogin") - showKeyboard=(action "appRouteAction" "showKeyboardShortcutsHelp") - toggleMobileView=(action "appRouteAction" "toggleMobileView") - toggleAnonymous=(action "appRouteAction" "toggleAnonymous") - logout=(action "appRouteAction" "logout")}} -{{plugin-outlet name="below-site-header"}} + showCreateAccount="showCreateAccount" + showLogin="showLogin" + showKeyboard="showKeyboardShortcutsHelp" + toggleMobileView="toggleMobileView" + toggleAnonymous="toggleAnonymous" + logout="logout"}} +{{plugin-outlet "below-site-header"}}
{{#if showTop}} - {{custom-html name="top"}} + {{custom-html "top"}} {{/if}} {{global-notice}} {{create-topics-notice}} @@ -20,11 +20,11 @@ {{outlet "user-card"}}
-{{plugin-outlet name="above-footer"}} +{{plugin-outlet "above-footer"}} {{#if showFooter}} - {{custom-html name="footer"}} + {{custom-html "footer"}} {{/if}} -{{plugin-outlet name="below-footer"}} +{{plugin-outlet "below-footer"}} {{outlet "modal"}} {{topic-entrance}} diff --git a/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs b/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs index bbf8ef4caba..f737c969760 100644 --- a/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs +++ b/app/assets/javascripts/discourse/templates/components/bread-crumbs.hbs @@ -8,6 +8,6 @@ {{tag-drop firstCategory=firstCategory secondCategory=secondCategory tagId=tagId}} {{/if}} -{{plugin-outlet name="bread-crumbs-right" connectorTagName="li"}} +{{plugin-outlet "bread-crumbs-right" tagName="li"}}
diff --git a/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs index 2900ab3af8f..790e61e9390 100644 --- a/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs +++ b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs @@ -56,7 +56,7 @@ - {{plugin-outlet name="category-email-in" args=(hash category=category)}} + {{plugin-outlet "category-email-in"}} {{/if}} {{#if showPositionInput}} @@ -82,4 +82,4 @@ {{/unless}} -{{plugin-outlet name="category-custom-settings" args=(hash category=category)}} +{{plugin-outlet "category-custom-settings"}} diff --git a/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs b/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs index 3a2496cc969..c7d381e5679 100644 --- a/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs +++ b/app/assets/javascripts/discourse/templates/components/navigation-bar.hbs @@ -1,5 +1,5 @@ {{#each navItems as |navItem|}} {{navigation-item content=navItem filterMode=filterMode}} {{/each}} -{{custom-html name="extraNavItem"}} -{{plugin-outlet name="extra-nav-item" connectorTagName="li"}} +{{custom-html "extraNavItem"}} +{{plugin-outlet "extra-nav-item" tagName="li"}} diff --git a/app/assets/javascripts/discourse/templates/components/plugin-outlet.hbs b/app/assets/javascripts/discourse/templates/components/plugin-outlet.hbs deleted file mode 100644 index 73126a2572f..00000000000 --- a/app/assets/javascripts/discourse/templates/components/plugin-outlet.hbs +++ /dev/null @@ -1,3 +0,0 @@ -{{#each connectors as |c|}} - {{plugin-connector connector=c args=args class=c.classNames tagName=connectorTagName}} -{{/each}} diff --git a/app/assets/javascripts/discourse/templates/components/stream-item.hbs b/app/assets/javascripts/discourse/templates/components/stream-item.hbs index fed530753ef..0018f8a2d84 100644 --- a/app/assets/javascripts/discourse/templates/components/stream-item.hbs +++ b/app/assets/javascripts/discourse/templates/components/stream-item.hbs @@ -6,7 +6,7 @@ {{{item.title}}}
{{category-link item.category}}
- {{plugin-outlet name="user-stream-item-header" args=(hash item=item)}} + {{plugin-outlet "user-stream-item-header"}}
{{#if actionDescription}} diff --git a/app/assets/javascripts/discourse/templates/components/topic-category.hbs b/app/assets/javascripts/discourse/templates/components/topic-category.hbs index edf11686ba9..cf717a09922 100644 --- a/app/assets/javascripts/discourse/templates/components/topic-category.hbs +++ b/app/assets/javascripts/discourse/templates/components/topic-category.hbs @@ -14,4 +14,4 @@ {{topic-featured-link topic}} {{/if}} -{{plugin-outlet name="topic-category" args=(hash topic=topic category=topic.category)}} +{{plugin-outlet "topic-category"}} diff --git a/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs b/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs index bca64f23167..518abc95c28 100644 --- a/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs +++ b/app/assets/javascripts/discourse/templates/components/topic-footer-buttons.hbs @@ -1,18 +1,5 @@ {{#if showAdminButton}} - {{topic-admin-menu-button - topic=topic - openUpwards="true" - toggleMultiSelect=toggleMultiSelect - deleteTopic=deleteTopic - recoverTopic=recoverTopic - toggleClosed=toggleClosed - toggleArchived=toggleArchived - toggleVisibility=toggleVisibility - showAutoClose=showAutoClose - showFeatureTopic=showFeatureTopic - showChangeTimestamp=showChangeTimestamp - convertToPublicTopic=convertToPublicTopic - convertToPrivateMessage=convertToPrivateMessage}} + {{topic-admin-menu-button topic=topic delegated=topicDelegated openUpwards="true"}} {{/if}} {{#unless topic.isPrivateMessage}} @@ -23,7 +10,7 @@ title=bookmarkTitle label=bookmarkLabel icon="bookmark" - action=toggleBookmark}} + action="toggleBookmark"}} {{/if}} + {{render "additional-composer-buttons" model}} {{/if}} {{/if}} - {{plugin-outlet name="composer-fields" args=(hash model=model)}} + {{plugin-outlet "composer-fields"}} {{composer-editor topic=topic @@ -103,7 +104,7 @@ {{#if currentUser}}
- {{plugin-outlet name="composer-fields-below" args=(hash model=model)}} + {{plugin-outlet "composer-fields-below"}} {{#if canEditTags}} {{tag-chooser tags=model.tags tabIndex="4" categoryId=model.categoryId}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/discovery.hbs b/app/assets/javascripts/discourse/templates/discovery.hbs index 0796cbecdfe..069be994bad 100644 --- a/app/assets/javascripts/discourse/templates/discovery.hbs +++ b/app/assets/javascripts/discourse/templates/discovery.hbs @@ -21,11 +21,11 @@
- {{plugin-outlet name="discovery-list-container-top"}} + {{plugin-outlet "discovery-list-container-top"}} {{outlet "list-container"}}
-{{plugin-outlet name="discovery-below"}} +{{plugin-outlet "discovery-below"}} diff --git a/app/assets/javascripts/discourse/templates/full-page-search.hbs b/app/assets/javascripts/discourse/templates/full-page-search.hbs index bfeab09cfe2..edaf9172db9 100644 --- a/app/assets/javascripts/discourse/templates/full-page-search.hbs +++ b/app/assets/javascripts/discourse/templates/full-page-search.hbs @@ -94,7 +94,7 @@ {{#each result.topic.tags as |tag|}} {{discourse-tag tag}} {{/each}} - {{plugin-outlet name="full-page-search-category" args=(hash result=result)}} + {{plugin-outlet "full-page-search-category"}} diff --git a/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs b/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs index bd444a8e55c..da825c4774b 100644 --- a/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs +++ b/app/assets/javascripts/discourse/templates/list/topic-list-item.raw.hbs @@ -10,7 +10,7 @@ {{#if topic.featured_link}} {{topic-featured-link topic}} {{/if}} - {{raw-plugin-outlet name="topic-list-after-title"}} + {{plugin-outlet "topic-list-after-title"}} {{#if showTopicPostBadges}} {{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl}} {{/if}} @@ -21,7 +21,7 @@ {{/each}} {{/if}} - {{raw-plugin-outlet name="topic-list-tags"}} + {{plugin-outlet "topic-list-tags"}} {{#if expandPinned}} {{raw "list/topic-excerpt" topic=topic}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs b/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs index 48cf5244f32..731c080bd8c 100644 --- a/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/list/topic-list-item.raw.hbs @@ -40,7 +40,7 @@ {{/if}} - {{raw-plugin-outlet name="topic-list-tags"}} + {{plugin-outlet "topic-list-tags"}}
diff --git a/app/assets/javascripts/discourse/templates/modal/create-account.hbs b/app/assets/javascripts/discourse/templates/modal/create-account.hbs index bdaa3d82394..7921b2a2452 100644 --- a/app/assets/javascripts/discourse/templates/modal/create-account.hbs +++ b/app/assets/javascripts/discourse/templates/modal/create-account.hbs @@ -52,11 +52,7 @@
{{/if}} - {{plugin-outlet name="create-account-before-password" - args=(hash accountName=accountName - accountUsername=accountUsername - accountPassword=accountPassword - userFields=userFields)}} + {{plugin-outlet "create-account-before-password"}} {{#if passwordRequired}} diff --git a/app/assets/javascripts/discourse/templates/modal/history.hbs b/app/assets/javascripts/discourse/templates/modal/history.hbs index 9714e004096..ce860fefcbf 100644 --- a/app/assets/javascripts/discourse/templates/modal/history.hbs +++ b/app/assets/javascripts/discourse/templates/modal/history.hbs @@ -94,7 +94,7 @@ {{/if}} - {{plugin-outlet name="post-revisions" args=(hash model=model)}} + {{plugin-outlet "post-revisions"}} {{#links-redirect class="row"}} {{{bodyDiff}}} diff --git a/app/assets/javascripts/discourse/templates/preferences.hbs b/app/assets/javascripts/discourse/templates/preferences.hbs index 3f39e111fd6..2afbb4d9869 100644 --- a/app/assets/javascripts/discourse/templates/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/preferences.hbs @@ -248,7 +248,7 @@ {{preference-checkbox labelKey="user.enable_quoting" checked=model.user_option.enable_quoting}} {{preference-checkbox labelKey="user.dynamic_favicon" checked=model.user_option.dynamic_favicon}} {{preference-checkbox labelKey="user.disable_jump_reply" checked=model.user_option.disable_jump_reply}} - {{plugin-outlet name="user-custom-preferences" args=(hash model=model)}} + {{plugin-outlet "user-custom-preferences"}}
@@ -350,7 +350,7 @@
{{/if}} - {{plugin-outlet name="user-custom-controls" args=(hash model=model)}} + {{plugin-outlet "user-custom-controls"}}
diff --git a/app/assets/javascripts/discourse/templates/static.hbs b/app/assets/javascripts/discourse/templates/static.hbs index c535f16fb35..529b5ba149e 100644 --- a/app/assets/javascripts/discourse/templates/static.hbs +++ b/app/assets/javascripts/discourse/templates/static.hbs @@ -1,7 +1,7 @@ {{#d-section bodyClass=bodyClass class="container"}} {{#watch-read action="markFaqRead" path=model.path}}
- {{plugin-outlet name="above-static"}} + {{plugin-outlet "above-static"}} {{{model.html}}} {{#if showSignupButton}} diff --git a/app/assets/javascripts/discourse/templates/tags/show.hbs b/app/assets/javascripts/discourse/templates/tags/show.hbs index 4b33995216c..9cf29e587af 100644 --- a/app/assets/javascripts/discourse/templates/tags/show.hbs +++ b/app/assets/javascripts/discourse/templates/tags/show.hbs @@ -42,7 +42,7 @@
-{{plugin-outlet name="discovery-list-container-top"}} +{{plugin-outlet "discovery-list-container-top"}}
{{conditional-loading-spinner condition=loading}} diff --git a/app/assets/javascripts/discourse/templates/topic.hbs b/app/assets/javascripts/discourse/templates/topic.hbs index e21c2e18809..65c0f3f6a81 100644 --- a/app/assets/javascripts/discourse/templates/topic.hbs +++ b/app/assets/javascripts/discourse/templates/topic.hbs @@ -6,7 +6,7 @@
{{/if}} - {{plugin-outlet name="topic-above-post-stream" args=(hash model=model)}} + {{plugin-outlet "topic-above-post-stream"}} {{#if model.postStream.loaded}} {{#if model.postStream.firstPostPresent}} @@ -30,7 +30,7 @@ {{tag-chooser tags=buffered.tags categoryId=buffered.category_id}} {{/if}} - {{plugin-outlet name="edit-topic" args=(hash model=model buffered=buffered)}} + {{plugin-outlet "edit-topic"}} {{d-button action="finishedEditingTopic" class="btn-primary btn-small submit-edit" icon="check"}} {{d-button action="cancelEditingTopic" class="btn-small cancel-edit" icon="times"}} @@ -59,7 +59,7 @@ {{/unless}} {{/if}} - {{plugin-outlet name="topic-title" args=(hash model=model)}} + {{plugin-outlet "topic-title"}} {{/if}} @@ -70,53 +70,24 @@ {{#topic-navigation jumpToIndex="jumpToIndex" as |info|}} + {{#if info.renderAdminMenuButton}} - {{topic-admin-menu-button - topic=model - fixed="true" - toggleMultiSelect=(action "toggleMultiSelect") - deleteTopic=(action "deleteTopic") - recoverTopic=(action "recoverTopic") - toggleClosed=(action "toggleClosed") - toggleArchived=(action "toggleArchived") - toggleVisibility=(action "toggleVisibility") - showAutoClose=(action "topicRouteAction" "showAutoClose") - showFeatureTopic=(action "topicRouteAction" "showFeatureTopic") - showChangeTimestamp=(action "topicRouteAction" "showChangeTimestamp") - convertToPublicTopic=(action "convertToPublicTopic") - convertToPrivateMessage=(action "convertToPrivateMessage")}} + {{topic-admin-menu-button topic=model fixed="true" delegated=topicDelegated}} {{/if}} {{#if info.renderTimeline}} - {{topic-timeline - topic=model - prevEvent=info.prevEvent - fullscreen=info.topicProgressExpanded - enteredIndex=enteredIndex - loading=model.postStream.loading - jumpToPost=(action "jumpToPost") - jumpTop=(action "jumpTop") - jumpBottom=(action "jumpBottom") - jumpToPostPrompt=(action "jumpToPostPrompt") - jumpToIndex=(action "jumpToIndex") - replyToPost=(action "replyToPost") - toggleMultiSelect=(action "toggleMultiSelect") - deleteTopic=(action "deleteTopic") - recoverTopic=(action "recoverTopic") - toggleClosed=(action "toggleClosed") - toggleArchived=(action "toggleArchived") - toggleVisibility=(action "toggleVisibility") - showAutoClose=(action "topicRouteAction" "showAutoClose") - showFeatureTopic=(action "topicRouteAction" "showFeatureTopic") - showChangeTimestamp=(action "topicRouteAction" "showChangeTimestamp") - convertToPublicTopic=(action "convertToPublicTopic") - convertToPrivateMessage=(action "convertToPrivateMessage")}} + {{topic-timeline topic=model + prevEvent=info.prevEvent + fullscreen=info.topicProgressExpanded + enteredIndex=enteredIndex + loading=model.postStream.loading + delegated=topicDelegated}} + {{else}} - {{topic-progress - prevEvent=info.prevEvent - topic=model - expanded=info.topicProgressExpanded}} + {{topic-progress prevEvent=info.prevEvent topic=model delegated=topicDelegated expanded=info.topicProgressExpanded}} {{/if}} + + {{/topic-navigation}}
@@ -125,7 +96,7 @@
{{conditional-loading-spinner condition=model.postStream.loadingAbove}} - {{plugin-outlet name="topic-above-posts" args=(hash model=model)}} + {{plugin-outlet "topic-above-posts"}} {{#unless model.postStream.loadingFilter}} {{scrolling-post-stream @@ -135,34 +106,35 @@ selectedPostsCount=selectedPostsCount selectedQuery=selectedQuery gaps=model.postStream.gaps - showFlags=(action "showPostFlags") - editPost=(action "editPost") - showHistory=(action "topicRouteAction" "showHistory") - showLogin=(action "topicRouteAction" "showLogin") - showRawEmail=(action "topicRouteAction" "showRawEmail") - deletePost=(action "deletePost") - recoverPost=(action "recoverPost") - expandHidden=(action "expandHidden") - newTopicAction=(action "replyAsNewTopic") - toggleBookmark=(action "toggleBookmark") - togglePostType=(action "togglePostType") - rebakePost=(action "rebakePost") - changePostOwner=(action "changePostOwner") - unhidePost=(action "unhidePost") - replyToPost=(action "replyToPost") - toggleWiki=(action "toggleWiki") - toggleSummary=(action "toggleSummary") - removeAllowedUser=(action "removeAllowedUser") - removeAllowedGroup=(action "removeAllowedGroup") - showInvite=(action "topicRouteAction" "showInvite") - topVisibleChanged=(action "topVisibleChanged") - currentPostChanged=(action "currentPostChanged") - currentPostScrolled=(action "currentPostScrolled") - bottomVisibleChanged=(action "bottomVisibleChanged") - selectPost=(action "toggledSelectedPost") - selectReplies=(action "toggledSelectedPostReplies") - fillGapBefore=(action "fillGapBefore") - fillGapAfter=(action "fillGapAfter")}} + showFlags="showFlags" + editPost="editPost" + showHistory="showHistory" + showLogin="showLogin" + showRawEmail="showRawEmail" + deletePost="deletePost" + recoverPost="recoverPost" + expandHidden="expandHidden" + newTopicAction="replyAsNewTopic" + expandFirstPost="expandFirstPost" + toggleBookmark="toggleBookmark" + togglePostType="togglePostType" + rebakePost="rebakePost" + changePostOwner="changePostOwner" + unhidePost="unhidePost" + replyToPost="replyToPost" + toggleWiki="toggleWiki" + toggleSummary="toggleSummary" + removeAllowedUser="removeAllowedUser" + removeAllowedGroup="removeAllowedGroup" + showInvite="showInvite" + topVisibleChanged="topVisibleChanged" + currentPostChanged="currentPostChanged" + currentPostScrolled="currentPostScrolled" + bottomVisibleChanged="bottomVisibleChanged" + selectPost="toggledSelectedPost" + selectReplies="toggledSelectedPostReplies" + fillGapBefore="fillGapBefore" + fillGapAfter="fillGapAfter"}} {{/unless}} {{conditional-loading-spinner condition=model.postStream.loadingBelow}} @@ -178,25 +150,7 @@ {{signup-cta}} {{else}} {{#if currentUser}} - {{topic-footer-buttons - topic=model - toggleMultiSelect=(action "toggleMultiSelect") - deleteTopic=(action "deleteTopic") - recoverTopic=(action "recoverTopic") - toggleClosed=(action "toggleClosed") - toggleArchived=(action "toggleArchived") - toggleVisibility=(action "toggleVisibility") - showAutoClose=(action "topicRouteAction" "showAutoClose") - showFeatureTopic=(action "topicRouteAction" "showFeatureTopic") - showChangeTimestamp=(action "topicRouteAction" "showChangeTimestamp") - convertToPublicTopic=(action "convertToPublicTopic") - convertToPrivateMessage=(action "convertToPrivateMessage") - toggleBookmark=(action "toggleBookmark") - showFlagTopic=(action "topicRouteAction" "showFlagTopic") - showInvite=(action "topicRouteAction" "showInvite") - toggleArchiveMessage=(action "toggleArchiveMessage") - replyToPost=(action "replyToPost") - }} + {{topic-footer-buttons topic=model topicDelegated=topicDelegated}} {{else}} {{d-button icon="reply" class="btn-primary" action="showLogin" label="topic.reply.title"}} {{/if}} @@ -221,7 +175,7 @@
{{/if}} - {{plugin-outlet name="topic-above-suggested" args=(hash model=model)}} + {{plugin-outlet "topic-above-suggested"}} {{#if model.details.suggested_topics.length}}
diff --git a/app/assets/javascripts/discourse/templates/user.hbs b/app/assets/javascripts/discourse/templates/user.hbs index de997c39fda..64a5b2583a5 100644 --- a/app/assets/javascripts/discourse/templates/user.hbs +++ b/app/assets/javascripts/discourse/templates/user.hbs @@ -47,9 +47,7 @@ {{#if currentUser.staff}}
  • {{fa-icon "wrench"}}{{i18n 'admin.user.show_admin_profile'}}
  • {{/if}} - {{plugin-outlet name="user-profile-controls" - connectorTagName="li" - args=(hash model=model)}} + {{plugin-outlet "user-profile-controls" tagName="li"}} {{#if collapsedInfo}} {{#if viewingSelf}} @@ -66,7 +64,7 @@ {{#if model.title}}

    {{model.title}}

    {{/if}} - {{plugin-outlet name="user-post-names" args=(hash model=model)}} + {{plugin-outlet "user-post-names"}}

    {{#if model.location}}{{fa-icon "map-marker"}} {{model.location}}{{/if}} {{#if model.website_name}} @@ -77,7 +75,7 @@ {{model.website_name}} {{/if}} {{/if}} - {{plugin-outlet name="user-location-and-website" args=(hash model=model)}} + {{plugin-outlet "user-location-and-website"}}

    @@ -104,13 +102,12 @@ {{/if}} {{/each}} - {{plugin-outlet name="user-profile-public-fields" - args=(hash publicUserFields=publicUserFields - model=model)}} + {{plugin-outlet "user-profile-public-fields"}}
    {{/if}} - {{plugin-outlet name="user-profile-primary" args=(hash model=model)}} + {{plugin-outlet "user-profile-primary"}} +
    @@ -156,7 +153,7 @@ {{d-button action="adminDelete" icon="exclamation-triangle" label="user.admin_delete" class="btn-danger"}} {{/if}} - {{plugin-outlet name="user-profile-secondary" args=(hash model=model)}} + {{plugin-outlet "user-profile-secondary"}} {{/unless}} diff --git a/app/assets/javascripts/discourse/templates/user/activity.hbs b/app/assets/javascripts/discourse/templates/user/activity.hbs index b0fa84ba144..f1818f2ec9a 100644 --- a/app/assets/javascripts/discourse/templates/user/activity.hbs +++ b/app/assets/javascripts/discourse/templates/user/activity.hbs @@ -23,9 +23,7 @@ {{/link-to}} {{/if}} - {{plugin-outlet name="user-activity-bottom" - connectorTagName='li' - args=(hash model=model)}} + {{plugin-outlet "user-activity-bottom" tagName='li'}} {{/mobile-nav}} {{#if viewingSelf}} diff --git a/app/assets/javascripts/discourse/templates/user/summary.hbs b/app/assets/javascripts/discourse/templates/user/summary.hbs index ceae695ecb1..e36928a986a 100644 --- a/app/assets/javascripts/discourse/templates/user/summary.hbs +++ b/app/assets/javascripts/discourse/templates/user/summary.hbs @@ -37,9 +37,7 @@
  • {{user-stat value=model.likes_received label="user.summary.likes_received"}}
  • - {{plugin-outlet name="user-summary-stat" - connectorTagName="li" - args=(hash model=model)}} + {{plugin-outlet "user-summary-stat" tagName="li"}} diff --git a/app/assets/javascripts/discourse/views/modal-body.js.es6 b/app/assets/javascripts/discourse/views/modal-body.js.es6 new file mode 100644 index 00000000000..e7e1f865baa --- /dev/null +++ b/app/assets/javascripts/discourse/views/modal-body.js.es6 @@ -0,0 +1,40 @@ +import deprecated from 'discourse-common/lib/deprecated'; + +export default Ember.View.extend({ + focusInput: true, + + didInsertElement() { + this._super(); + + deprecated('ModalBodyView is deprecated. Use the `d-modal-body` component instead'); + + $('#modal-alert').hide(); + $('#discourse-modal').modal('show'); + Ember.run.scheduleOnce('afterRender', this, this._afterFirstRender); + + this.appEvents.on('modal-body:flash', msg => this._flash(msg)); + }, + + willDestroyElement() { + this._super(); + this.appEvents.off('modal-body:flash'); + }, + + _afterFirstRender() { + if (!this.site.mobileView && this.get('focusInput')) { + this.$('input:first').focus(); + } + + const title = this.get('title'); + if (title) { + this.set('controller.modal.title', title); + } + }, + + _flash(msg) { + $('#modal-alert').hide() + .removeClass('alert-error', 'alert-success') + .addClass(`alert alert-${msg.messageClass || 'success'}`).html(msg.text || '') + .fadeIn(); + } +}); diff --git a/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 b/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 index 20045a93718..a3d5ad585d7 100644 --- a/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 +++ b/app/assets/javascripts/discourse/widgets/header-topic-info.js.es6 @@ -53,12 +53,9 @@ export default createWidget('header-topic-info', { } } if (this.siteSettings.topic_featured_link_enabled) { - const featured = topicFeaturedLinkNode(attrs.topic); - if (featured) { - extra.push(featured); - } + extra.push(topicFeaturedLinkNode(attrs.topic)); } - if (extra.length) { + if (extra) { title.push(h('div.topic-header-extra', extra)); } } diff --git a/app/assets/javascripts/discourse/widgets/topic-map.js.es6 b/app/assets/javascripts/discourse/widgets/topic-map.js.es6 index 67f70aefd9b..675e8b9d3a3 100644 --- a/app/assets/javascripts/discourse/widgets/topic-map.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-map.js.es6 @@ -11,7 +11,7 @@ function renderParticipants(userFilters, participants) { userFilters = userFilters || []; return participants.map(p => { - return this.attach('topic-participant', p, { state: { toggled: userFilters.includes(p.username) } }); + return this.attach('topic-participant', p, { state: { toggled: userFilters.contains(p.username) } }); }); } diff --git a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 index eaa6aac250d..da4bc1be528 100644 --- a/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 +++ b/app/assets/javascripts/discourse/widgets/topic-timeline.js.es6 @@ -19,18 +19,16 @@ createWidget('timeline-last-read', { return { style: `height: 40px; top: ${attrs.top}px` }; }, - html(attrs) { - const result = [ iconNode('minus', { class: 'progress' }) ]; - if (attrs.showButton) { - result.push(this.attach('button', { + html() { + return [ + iconNode('circle', { class: 'progress' }), + this.attach('button', { className: 'btn btn-primary btn-small', label: 'topic.timeline.back', title: 'topic.timeline.back_description', action: 'goBack' - })); - } - - return result; + }) + ]; }, goBack() { @@ -161,12 +159,8 @@ createWidget('timeline-scrollarea', { if (position.lastRead && position.lastRead !== position.total) { const lastReadTop = Math.round(position.lastReadPercentage * SCROLLAREA_HEIGHT); - if (lastReadTop > (before + SCROLLER_HEIGHT * 0.5)) { - result.push(this.attach('timeline-last-read', { - top: lastReadTop, - lastRead: position.lastRead, - showButton: (lastReadTop > (before + SCROLLER_HEIGHT)) && (lastReadTop < (SCROLLAREA_HEIGHT - SCROLLER_HEIGHT)) - })); + if ((lastReadTop > (before + SCROLLER_HEIGHT)) && (lastReadTop < (SCROLLAREA_HEIGHT - SCROLLER_HEIGHT))) { + result.push(this.attach('timeline-last-read', { top: lastReadTop, lastRead: position.lastRead })); } } diff --git a/app/assets/javascripts/discourse/widgets/widget.js.es6 b/app/assets/javascripts/discourse/widgets/widget.js.es6 index f3f5d95356a..8cf85e2555f 100644 --- a/app/assets/javascripts/discourse/widgets/widget.js.es6 +++ b/app/assets/javascripts/discourse/widgets/widget.js.es6 @@ -256,24 +256,31 @@ export default class Widget { } _sendComponentAction(name, param) { - let promise; + const view = this._findAncestorWithProperty('_emberView'); - const view = this._findView(); + let promise; if (view) { - const method = view.get(name); - if (!method) { - console.warn(`${name} not found`); + // Peek into ember internals to allow us to return promises from actions + const ev = view._emberView; + const target = ev.get('targetObject'); + + const actionName = ev.get(name); + if (!actionName) { + Ember.warn(`${name} not found`); return; } - if (typeof method === "string") { - view.sendAction(method, param); - promise = Ember.RSVP.resolve(); - } else { - const target = view.get('targetObject'); - promise = method.call(target, param); - if (!promise || !promise.then) { - promise = Ember.RSVP.resolve(promise); + if (target) { + // TODO: Use ember closure actions + const actions = target.actions || target.actionHooks || {}; + const method = actions[actionName]; + if (method) { + promise = method.call(target, param); + if (!promise || !promise.then) { + promise = Ember.RSVP.resolve(promise); + } + } else { + return ev.sendAction(name, param); } } } diff --git a/app/assets/javascripts/env.js b/app/assets/javascripts/env.js index f561c7fad78..12deda108c5 100644 --- a/app/assets/javascripts/env.js +++ b/app/assets/javascripts/env.js @@ -1,3 +1,4 @@ window.ENV = { }; window.EmberENV = window.EmberENV || {}; window.EmberENV.FORCE_JQUERY = true; +window.EmberENV._ENABLE_LEGACY_VIEW_SUPPORT = true; diff --git a/app/assets/stylesheets/common/topic-timeline.scss b/app/assets/stylesheets/common/topic-timeline.scss index 47e9653d68f..4ce8a903bf1 100644 --- a/app/assets/stylesheets/common/topic-timeline.scss +++ b/app/assets/stylesheets/common/topic-timeline.scss @@ -106,7 +106,8 @@ right: 0px; margin-left: 0; i.progress { - display: none + margin-right: -3px; + margin-left: 1em; } } .timeline-footer-controls { @@ -261,15 +262,15 @@ .timeline-last-read { position: absolute; - margin-left: -0.35em; + margin-left: -0.19em; .btn-small { padding: 2px 5px; } i.progress { - font-size: 0.8em; - color: $tertiary; + font-size: 0.5em; + color: dark-light-choose(scale-color($tertiary, $lightness: 80%), scale-color($tertiary, $lightness: 20%)); margin-right: 1em; } } diff --git a/app/views/user_notifications/digest.html.erb b/app/views/user_notifications/digest.html.erb index 8b3db7ee640..446c8add754 100644 --- a/app/views/user_notifications/digest.html.erb +++ b/app/views/user_notifications/digest.html.erb @@ -47,7 +47,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
      {{i18n 'admin.dashboard.installed_version'}}
    -
    +
    @@ -58,13 +58,13 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo @@ -123,7 +123,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo <%- if show_image_with_url(t.image_url) -%> @@ -189,7 +189,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo <% end %> @@ -215,8 +215,8 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    - +
    <%- @counts.each do |count| -%> - <%- end -%> <%- @counts.each do |count| -%> - <%- end -%>

    -
    <%=t 'user_notifications.digest.since_last_visit' %>
    +
    <%=t 'user_notifications.digest.since_last_visit' %>
    @@ -72,22 +72,22 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    - <%= count[:value] -%> + + <%= count[:value] -%>
    - <%=t count[:label_key] -%> + + <%=t count[:label_key] -%>
    -
    <%=t 'user_notifications.digest.popular_topics' %>
    +
    <%=t 'user_notifications.digest.popular_topics' %>

    - + <%= t.title.truncate(60, separator: /\s/) -%>

    @@ -143,10 +143,10 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    <% if t.user %> +
    <%= t.user.username -%>
    <% if SiteSetting.enable_names? && t.user.name.present? && t.user.name.downcase != t.user.username.downcase %> -
    <%= t.user.name -%>
    +

    <%= t.user.name -%>

    <% end %> -

    <%= t.user.username -%>

    <% end %>
    - + <%=t 'user_notifications.digest.join_the_discussion' %>
    - -
    + +
    @@ -277,18 +277,18 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo @@ -331,12 +331,12 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
    <% if post.user %> +
    <%= post.user.username -%>
    <% if SiteSetting.enable_names? && post.user.name && post.user.name.downcase != post.user.username.downcase %> -
    <%= post.user.name -%>
    +

    <%= post.user.name -%>

    <% end %> -

    <%= post.user.username -%>

    <% end %>

    <%=t 'user_notifications.digest.from_topic_label' %> - <%= post.topic.title.truncate(60, separator: /\s/) -%> + <%= post.topic.title.truncate(60, separator: /\s/) -%>

    - + <%=t 'user_notifications.digest.join_the_discussion' %>
    -

    +

    <%= t.user_data ? (t.highest_post_number - (t.user_data.last_read_post_number || 0)) : t.highest_post_number %>

    - + <%= t.title.truncate(60, separator: /\s/) -%> <%- if SiteSetting.show_topic_featured_link_in_digest && t.featured_link %> diff --git a/config/application.rb b/config/application.rb index a7a5531a691..5ac23191642 100644 --- a/config/application.rb +++ b/config/application.rb @@ -142,7 +142,7 @@ module Discourse # Our templates shouldn't start with 'discourse/templates' config.handlebars.templates_root = 'discourse/templates' - config.handlebars.raw_template_namespace = "Discourse.RAW_TEMPLATES" + config.handlebars.raw_template_namespace = "Ember.TEMPLATES" require 'discourse_redis' require 'logster/redis_store' diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 8d36e36d2ee..2260ce3ab94 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1306,9 +1306,6 @@ en: delete_digest_email_after_days: "Suppress summary emails for users not seen on the site for more than (n) days." digest_suppress_categories: "Suppress these categories from summary emails." disable_digest_emails: "Disable summary emails for all users." - email_accent_bg_color: "The accent color to be used as the background of some elements in HTML emails. Enter a color name ('red') or hex value ('#FF000')." - email_accent_fg_color: "The color of text rendered on the email bg color in HTML emails. Enter a color name ('white') or hex value ('#FFFFFF')." - email_link_color: "The color of links in HTML emails. Enter a color name ('blue') or hex value ('#0000FF')." detect_custom_avatars: "Whether or not to check that users have uploaded custom profile pictures." max_daily_gravatar_crawls: "Maximum number of times Discourse will check Gravatar for custom avatars in a day" diff --git a/config/site_settings.yml b/config/site_settings.yml index 4eeb9489e1c..1d4eaee0a33 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -599,9 +599,6 @@ email: disable_digest_emails: default: false client: true - email_accent_bg_color: "#2F70AC" - email_accent_fg_color: "#FFFFFF" - email_link_color: "#006699" show_topic_featured_link_in_digest: false email_custom_headers: 'Auto-Submitted: auto-generated' email_subject: '[%{site_name}] %{optional_pm}%{optional_cat}%{topic_title}' diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 8db24d48672..39adcf88cd1 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -152,19 +152,20 @@ module Email end def format_html - style('.with-accent-colors', "background-color: #{SiteSetting.email_accent_bg_color}; color: #{SiteSetting.email_accent_fg_color};") style('h4', 'color: #222;') style('h3', 'margin: 15px 0 20px 0;') style('hr', 'background-color: #ddd; height: 1px; border: 1px;') - style('a', "text-decoration: none; font-weight: bold; color: #{SiteSetting.email_link_color};") + style('a', 'text-decoration: none; font-weight: bold; color: #006699;') style('ul', 'margin: 0 0 0 10px; padding: 0 0 0 20px;') style('li', 'padding-bottom: 10px') + style('div.digest-post', 'margin-left: 15px; margin-top: -5px; max-width: 694px;') + style('div.digest-post h1', 'font-size: 20px;') style('div.footer', 'color:#666; font-size:95%; text-align:center; padding-top:15px;') style('span.post-count', 'margin: 0 5px; color: #777;') style('pre', 'word-wrap: break-word; max-width: 694px;') style('code', 'background-color: #f1f1ff; padding: 2px 5px;') style('pre code', 'display: block; background-color: #f1f1ff; padding: 5px;') - style('.featured-topic a', "text-decoration: none; font-weight: bold; color: #{SiteSetting.email_link_color}; line-height:1.5em;") + style('.featured-topic a', 'text-decoration: none; font-weight: bold; color: #006699; line-height:1.5em;') onebox_styles plugin_styles diff --git a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 index 074d93a3b42..ca9cbbda66a 100644 --- a/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 +++ b/plugins/discourse-details/assets/javascripts/initializers/apply-details.js.es6 @@ -21,7 +21,6 @@ function initializeDetails(api) { "details_text", { multiline: false } ); - this.set('optionsVisible', false); } } }); diff --git a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 index 427687886ab..afe45dfffd6 100644 --- a/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 +++ b/plugins/discourse-details/test/javascripts/acceptance/details-button-test.js.es6 @@ -36,7 +36,7 @@ test('details button', () => { equal( find(".d-editor-input").val(), `[details=${I18n.t("composer.details_title")}]This is my title[/details]`, - 'it should contain the right selected output' + 'it should contain the right output' ); const textarea = findTextarea(); diff --git a/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 b/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 index 35aec81b5c4..401838b6103 100644 --- a/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 +++ b/plugins/poll/test/javascripts/acceptance/polls-test.js.es6 @@ -1,4 +1,5 @@ -import { acceptance } from "helpers/qunit-helpers"; +import { acceptance, controllerFor } from "helpers/qunit-helpers"; +import PostCooked from 'discourse/widgets/post-cooked'; acceptance("Rendering polls", { loggedIn: true, @@ -10,7 +11,7 @@ acceptance("Rendering polls", { { "Content-Type": "application/json" }, object ]; - }; + } server.get('/t/13.json', () => { return response({"post_stream":{"posts":[{"id":19,"name":null,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png","created_at":"2016-12-01T02:39:49.199Z","cooked":"
    \n
    \n
      \n
    • test
    • \n
    • haha
    • \n
    \n

    0voters

    \n
    \n\n
    \n\n
    \n
    \n
      \n
    • donkey
    • \n
    • kong
    • \n
    \n

    0voters

    \n
    \n\n
    ","post_number":1,"post_type":1,"updated_at":"2016-12-01T02:47:18.317Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":null,"incoming_link_count":0,"reads":1,"score":0,"yours":true,"topic_id":13,"topic_slug":"this-is-a-test-topic-for-polls","display_username":null,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_bg_color":null,"primary_group_flair_color":null,"version":2,"can_edit":true,"can_delete":false,"can_recover":true,"can_wiki":true,"read":true,"user_title":null,"actions_summary":[{"id":3,"can_act":true},{"id":4,"can_act":true},{"id":5,"hidden":true,"can_act":true},{"id":7,"can_act":true},{"id":8,"can_act":true}],"moderator":false,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":4,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"polls":{"poll":{"options":[{"id":"57ddd734344eb7436d64a7d68a0df444","html":"test","votes":0},{"id":"b5b78d79ab5b5d75d4d33d8b87f5d2aa","html":"haha","votes":0}],"voters":2,"status":"open","name":"poll"},"test":{"options":[{"id":"c26ad90783b0d80936e5fdb292b7963c","html":"donkey","votes":0},{"id":"99f2b9ac452ba73b115fcf3556e6d2d4","html":"kong","votes":0}],"voters":3,"status":"open","name":"test"}}}],"stream":[19]},"timeline_lookup":[[1,0]],"id":13,"title":"This is a test topic for polls","fancy_title":"This is a test topic for polls","posts_count":1,"created_at":"2016-12-01T02:39:48.055Z","views":1,"reply_count":0,"participant_count":1,"like_count":0,"last_posted_at":"2016-12-01T02:39:49.199Z","visible":true,"closed":false,"archived":false,"has_summary":false,"archetype":"regular","slug":"this-is-a-test-topic-for-polls","category_id":1,"word_count":10,"deleted_at":null,"user_id":1,"draft":null,"draft_key":"topic_13","draft_sequence":4,"posted":true,"unpinned":null,"pinned_globally":false,"pinned":false,"pinned_at":null,"pinned_until":null,"details":{"auto_close_at":null,"auto_close_hours":null,"auto_close_based_on_last_post":false,"created_by":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"},"last_poster":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"},"participants":[{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png","post_count":1}],"suggested_topics":[{"id":8,"title":"Welcome to Discourse","fancy_title":"Welcome to Discourse","slug":"welcome-to-discourse","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-11-24T02:10:54.328Z","last_posted_at":"2016-11-24T02:10:54.393Z","bumped":true,"bumped_at":"2016-11-24T02:10:54.393Z","unseen":false,"pinned":true,"unpinned":null,"excerpt":"The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! \n\nEdit this into a brief description of your community: \n\n\nWho is it for?\nWhat can they …","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"archetype":"regular","like_count":0,"views":0,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":-1,"username":"system","avatar_template":"/letter_avatar_proxy/v2/letter/s/bcef8e/{size}.png"}}]},{"id":12,"title":"Some testing topic testing","fancy_title":"Some testing topic testing","slug":"some-testing-topic-testing","posts_count":4,"reply_count":0,"highest_post_number":4,"image_url":null,"created_at":"2016-11-24T08:36:08.773Z","last_posted_at":"2016-12-01T01:15:52.008Z","bumped":true,"bumped_at":"2016-12-01T01:15:52.008Z","unseen":false,"last_read_post_number":4,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":2,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"}}]},{"id":11,"title":"Some testing topic","fancy_title":"Some testing topic","slug":"some-testing-topic","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-11-24T08:35:26.758Z","last_posted_at":"2016-11-24T08:35:26.894Z","bumped":true,"bumped_at":"2016-11-24T08:35:26.894Z","unseen":false,"last_read_post_number":1,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":0,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/letter_avatar_proxy/v2/letter/t/ecae2f/{size}.png"}}]}],"notification_level":3,"notifications_reason_id":1,"can_move_posts":true,"can_edit":true,"can_delete":true,"can_recover":true,"can_remove_allowed_users":true,"can_invite_to":true,"can_create_post":true,"can_reply_as_new_topic":true,"can_flag_topic":true},"highest_post_number":1,"last_read_post_number":1,"last_read_post_id":19,"deleted_by":null,"has_deleted":false,"actions_summary":[{"id":4,"count":0,"hidden":false,"can_act":true},{"id":7,"count":0,"hidden":false,"can_act":true},{"id":8,"count":0,"hidden":false,"can_act":true}],"chunk_size":20,"bookmarked":false}); diff --git a/spec/phantom_js/smoke_test.js b/spec/phantom_js/smoke_test.js index 6cac5534f5c..f703257fa82 100644 --- a/spec/phantom_js/smoke_test.js +++ b/spec/phantom_js/smoke_test.js @@ -139,7 +139,7 @@ var runTests = function() { }); test("at least one topic shows up", function() { - return $(".topic-list tbody tr").length; + return document.querySelector(".topic-list tbody tr"); }); execAsync("navigate to 1st topic", 500, function() { @@ -147,7 +147,7 @@ var runTests = function() { }); test("at least one post body", function() { - return $(".topic-post").length; + return document.querySelector(".topic-post"); }); execAsync("click on the 1st user", 500, function() { @@ -157,7 +157,7 @@ var runTests = function() { }); test("user has details", function() { - return $("#user-card .names").length; + return document.querySelector("#user-card .names"); }); exec("open login modal", function() { @@ -165,7 +165,7 @@ var runTests = function() { }); test("login modal is open", function() { - return $(".login-modal").length; + return document.querySelector(".login-modal"); }); exec("type in credentials & log in", function() { @@ -175,7 +175,7 @@ var runTests = function() { }); test("is logged in", function() { - return $(".current-user").length; + return document.querySelector(".current-user"); }); exec("go home", function() { @@ -183,11 +183,11 @@ var runTests = function() { }); test("it shows a topic list", function() { - return $(".topic-list").length; + return document.querySelector(".topic-list"); }); test('we have a create topic button', function() { - return $("#create-topic").length; + return document.querySelector("#create-topic"); }); exec("open composer", function() { @@ -195,7 +195,7 @@ var runTests = function() { }); test('the editor is visible', function() { - return $(".d-editor").length; + return document.querySelector(".d-editor"); }); exec("compose new topic", function() { @@ -209,7 +209,7 @@ var runTests = function() { }); test("updates preview", function() { - return $(".d-editor-preview p").length; + return document.querySelector(".d-editor-preview p"); }); exec("open upload modal", function() { @@ -217,7 +217,7 @@ var runTests = function() { }); test("upload modal is open", function() { - return $("#filename-input").length; + return document.querySelector("#filename-input"); }); // TODO: Looks like PhantomJS 2.0.0 has a bug with `uploadFile` @@ -246,7 +246,7 @@ var runTests = function() { }); test("topic is created", function() { - return $(".fancy-title").length; + return document.querySelector(".fancy-title"); }); exec("click reply button", function() { @@ -254,7 +254,7 @@ var runTests = function() { }); test("composer is open", function() { - return $("#reply-control .d-editor-input").length; + return document.querySelector("#reply-control .d-editor-input"); }); exec("compose reply", function() { diff --git a/test/javascripts/acceptance/plugin-outlet-connector-class-test.js.es6 b/test/javascripts/acceptance/plugin-outlet-connector-class-test.js.es6 deleted file mode 100644 index 82b34f7ca7c..00000000000 --- a/test/javascripts/acceptance/plugin-outlet-connector-class-test.js.es6 +++ /dev/null @@ -1,47 +0,0 @@ -import { acceptance } from "helpers/qunit-helpers"; -import { extraConnectorClass } from 'discourse/lib/plugin-connectors'; - -const PREFIX = "javascripts/single-test/connectors"; -acceptance("Plugin Outlet - Connector Class", { - setup() { - extraConnectorClass('user-profile-primary/hello', { - actions: { - sayHello() { - this.set('hello', 'hello!'); - } - } - }); - - extraConnectorClass('user-profile-primary/dont-render', { - shouldRender(args) { - return args.model.get('username') !== 'eviltrout'; - } - }); - - Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hello`] = Ember.HTMLBars.compile( - `{{model.username}} - - {{hello}}` - ); - Ember.TEMPLATES[`${PREFIX}/user-profile-primary/dont-render`] = Ember.HTMLBars.compile( - `I'm not rendered!` - ); - }, - - teardown() { - delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/hello`]; - delete Ember.TEMPLATES[`${PREFIX}/user-profile-primary/dont-render`]; - } -}); - -test("Renders a template into the outlet", assert => { - visit("/users/eviltrout"); - andThen(() => { - assert.ok(find('.user-profile-primary-outlet.hello').length === 1, 'it has class names'); - assert.ok(!find('.user-profile-primary-outlet.dont-render').length, "doesn't render"); - }); - click('.say-hello'); - andThen(() => { - assert.equal(find('.hello-result').text(), 'hello!', 'actions delegate properly'); - }); -}); diff --git a/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 b/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 index 0379b2d8e54..34d5bc00459 100644 --- a/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 +++ b/test/javascripts/acceptance/plugin-outlet-multi-template-test.js.es6 @@ -1,5 +1,5 @@ import { acceptance } from "helpers/qunit-helpers"; -import { clearCache } from 'discourse/lib/plugin-connectors'; +import { clearCache } from 'discourse/helpers/plugin-outlet'; const HELLO = 'javascripts/multi-test/connectors/user-profile-primary/hello'; const GOODBYE = 'javascripts/multi-test/connectors/user-profile-primary/goodbye'; diff --git a/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 b/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 index ee236ed8518..228506e27c9 100644 --- a/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 +++ b/test/javascripts/acceptance/plugin-outlet-single-template-test.js.es6 @@ -4,7 +4,9 @@ const CONNECTOR = 'javascripts/single-test/connectors/user-profile-primary/hello acceptance("Plugin Outlet - Single Template", { setup() { Ember.TEMPLATES[CONNECTOR] = Ember.HTMLBars.compile( - `{{model.username}}` + `{{model.username}} + + {{model.email}}` ); }, @@ -19,4 +21,8 @@ test("Renders a template into the outlet", assert => { assert.ok(find('.user-profile-primary-outlet.hello').length === 1, 'it has class names'); assert.equal(find('.hello-username').text(), 'eviltrout', 'it renders into the outlet'); }); + click('.hello-check-email'); + andThen(() => { + assert.equal(find('.hello-email').text(), 'eviltrout@example.com', 'actions delegate properly'); + }); }); diff --git a/test/javascripts/acceptance/search-full-test.js.es6 b/test/javascripts/acceptance/search-full-test.js.es6 index 47fdbc8bf6e..99820e7d9d9 100644 --- a/test/javascripts/acceptance/search-full-test.js.es6 +++ b/test/javascripts/acceptance/search-full-test.js.es6 @@ -71,29 +71,27 @@ test("open advanced search", assert => { andThen(() => assert.ok(visible('.search-advanced .search-advanced-options'), '"search-advanced-options" is visible')); }); -// these tests are screwy with the runloop +test("validate population of advanced search", assert => { + visit("/search"); + fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes in:private in:wiki in:bookmarks status:open after:2016-10-05 min_post_count:10'); + click('.search-advanced-btn'); -// test("validate population of advanced search", assert => { -// visit("/search"); -// fillIn('.search input.full-page-search', 'test user:admin #bug group:moderators badge:Reader tags:monkey in:likes in:private in:wiki in:bookmarks status:open after:2016-10-05 min_post_count:10'); -// click('.search-advanced-btn'); -// -// andThen(() => { -// assert.ok(exists('.search-advanced-options span:contains("admin")'), 'has "admin" pre-populated'); -// assert.ok(exists('.search-advanced-options .badge-category:contains("bug")'), 'has "bug" pre-populated'); -// //assert.ok(exists('.search-advanced-options span:contains("moderators")'), 'has "moderators" pre-populated'); -// //assert.ok(exists('.search-advanced-options span:contains("Reader")'), 'has "Reader" pre-populated'); -// assert.ok(exists('.search-advanced-options .tag-chooser .tag-monkey'), 'has "monkey" pre-populated'); -// assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" pre-populated'); -// assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" pre-populated'); -// assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" pre-populated'); -// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" pre-populated'); -// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("are open")'), 'has "are open" pre-populated'); -// assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("after")'), 'has "after" pre-populated'); -// assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" pre-populated'); -// assert.equal(find('.search-advanced-options #search-min-post-count').val(), "10", 'has "10" pre-populated'); -// }); -// }); + andThen(() => { + assert.ok(exists('.search-advanced-options span:contains("admin")'), 'has "admin" pre-populated'); + assert.ok(exists('.search-advanced-options .badge-category:contains("bug")'), 'has "bug" pre-populated'); + //assert.ok(exists('.search-advanced-options span:contains("moderators")'), 'has "moderators" pre-populated'); + //assert.ok(exists('.search-advanced-options span:contains("Reader")'), 'has "Reader" pre-populated'); + assert.ok(exists('.search-advanced-options .tag-chooser .tag-monkey'), 'has "monkey" pre-populated'); + assert.ok(exists('.search-advanced-options .in-likes:checked'), 'has "I liked" pre-populated'); + assert.ok(exists('.search-advanced-options .in-private:checked'), 'has "are in my messages" pre-populated'); + assert.ok(exists('.search-advanced-options .in-wiki:checked'), 'has "are wiki" pre-populated'); + assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("I\'ve bookmarked")'), 'has "I\'ve bookmarked" pre-populated'); + assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("are open")'), 'has "are open" pre-populated'); + assert.ok(exists('.search-advanced-options .combobox .select2-choice .select2-chosen:contains("after")'), 'has "after" pre-populated'); + assert.equal(find('.search-advanced-options #search-post-date').val(), "2016-10-05", 'has "2016-10-05" pre-populated'); + assert.equal(find('.search-advanced-options #search-min-post-count').val(), "10", 'has "10" pre-populated'); + }); +}); test("escape search term", (assert) => { visit("/search"); 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 f58845ecfc0..e4a7aaceb4f 100644 --- a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 +++ b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 @@ -20,6 +20,6 @@ test("grantableBadges", function() { }); - not(badgeNames.includes(badgeDisabled), "excludes disabled badges"); + not(badgeNames.contains(badgeDisabled), "excludes disabled badges"); deepEqual(badgeNames, sortedNames, "sorts badges by name"); }); diff --git a/test/javascripts/helpers/qunit-helpers.js.es6 b/test/javascripts/helpers/qunit-helpers.js.es6 index 1fdc796b693..d8351405f0c 100644 --- a/test/javascripts/helpers/qunit-helpers.js.es6 +++ b/test/javascripts/helpers/qunit-helpers.js.es6 @@ -5,10 +5,8 @@ import siteFixtures from 'fixtures/site-fixtures'; import HeaderComponent from 'discourse/components/site-header'; import { forceMobile, resetMobile } from 'discourse/lib/mobile'; import { resetPluginApi } from 'discourse/lib/plugin-api'; -import { clearCache as clearOutletCache, resetExtraClasses } from 'discourse/lib/plugin-connectors'; +import { clearCache as clearOutletCache } from 'discourse/helpers/plugin-outlet'; import { clearHTMLCache } from 'discourse/helpers/custom-html'; -import { flushMap } from 'discourse/models/store'; - function currentUser() { return Discourse.User.create(sessionFixtures['/session/current.json'].current_user); @@ -46,7 +44,6 @@ function acceptance(name, options) { // For now don't do scrolling stuff in Test Mode HeaderComponent.reopen({examineDockHeader: Ember.K}); - resetExtraClasses(); const siteJson = siteFixtures['site.json'].site; if (options) { if (options.setup) { @@ -80,11 +77,9 @@ function acceptance(name, options) { if (options && options.teardown) { options.teardown.call(this); } - flushMap(); Discourse.User.resetCurrent(); Discourse.Site.resetCurrent(Discourse.Site.create(jQuery.extend(true, {}, fixtures['site.json'].site))); - resetExtraClasses(); clearOutletCache(); clearHTMLCache(); resetPluginApi(); diff --git a/test/javascripts/models/post-stream-test.js.es6 b/test/javascripts/models/post-stream-test.js.es6 index b0c455e8fa9..5f825d9fbcc 100644 --- a/test/javascripts/models/post-stream-test.js.es6 +++ b/test/javascripts/models/post-stream-test.js.es6 @@ -170,7 +170,7 @@ test("toggleParticipant", function() { equal(postStream.get('userFilters.length'), 0, "by default no participants are toggled"); postStream.toggleParticipant(participant.username); - ok(postStream.get('userFilters').includes('eviltrout'), 'eviltrout is in the filters'); + ok(postStream.get('userFilters').contains('eviltrout'), 'eviltrout is in the filters'); postStream.toggleParticipant(participant.username); blank(postStream.get('userFilters'), "toggling the participant again removes them"); @@ -283,7 +283,7 @@ test("identity map", function() { }); test("loadIntoIdentityMap with no data", () => { - return buildStream(1234).loadIntoIdentityMap([]).then(result => { + buildStream(1234).loadIntoIdentityMap([]).then(result => { equal(result.length, 0, 'requesting no posts produces no posts'); }); }); @@ -291,7 +291,7 @@ test("loadIntoIdentityMap with no data", () => { test("loadIntoIdentityMap with post ids", function() { const postStream = buildStream(1234); - return postStream.loadIntoIdentityMap([10]).then(function() { + postStream.loadIntoIdentityMap([10]).then(function() { present(postStream.findLoadedPost(10), "it adds the returned post to the store"); }); }); @@ -327,7 +327,7 @@ test("staging and undoing a new post", function() { equal(stagedPost.get('topic'), topic, "it assigns the topic reference"); equal(stagedPost.get('post_number'), 2, "it is assigned the probable post_number"); present(stagedPost.get('created_at'), "it is assigned a created date"); - ok(postStream.get('posts').includes(stagedPost), "the post is added to the stream"); + ok(postStream.get('posts').contains(stagedPost), "the post is added to the stream"); equal(stagedPost.get('id'), -1, "the post has a magical -1 id"); // Undoing a created post (there was an error) @@ -337,7 +337,7 @@ test("staging and undoing a new post", function() { equal(topic.get('highest_post_number'), 1, "it reverts the highest_post_number"); equal(topic.get('posts_count'), 1, "it reverts the post count"); equal(postStream.get('filteredPostsCount'), 1, "it retains the filteredPostsCount"); - ok(!postStream.get('posts').includes(stagedPost), "the post is removed from the stream"); + ok(!postStream.get('posts').contains(stagedPost), "the post is removed from the stream"); ok(postStream.get('lastAppended'), original, "it doesn't consider undid post lastAppended"); }); @@ -367,7 +367,7 @@ test("staging and committing a post", function() { ok(postStream.get('lastAppended'), original, "staging a post doesn't change the lastAppended"); postStream.commitPost(stagedPost); - ok(postStream.get('posts').includes(stagedPost), "the post is still in the stream"); + ok(postStream.get('posts').contains(stagedPost), "the post is still in the stream"); ok(!postStream.get('loading'), "it is no longer loading"); equal(postStream.get('filteredPostsCount'), 2, "it increases the filteredPostsCount"); diff --git a/test/javascripts/models/result-set-test.js.es6 b/test/javascripts/models/result-set-test.js.es6 index 18c9aa0c80f..c846fd88720 100644 --- a/test/javascripts/models/result-set-test.js.es6 +++ b/test/javascripts/models/result-set-test.js.es6 @@ -15,7 +15,7 @@ test('defaults', function() { test('pagination support', function() { const store = createStore(); - return store.findAll('widget').then(function(rs) { + store.findAll('widget').then(function(rs) { equal(rs.get('length'), 2); equal(rs.get('totalRows'), 4); ok(rs.get('loadMoreUrl'), 'has a url to load more'); @@ -36,7 +36,7 @@ test('pagination support', function() { test('refresh support', function() { const store = createStore(); - return store.findAll('widget').then(function(rs) { + store.findAll('widget').then(function(rs) { equal(rs.get('refreshUrl'), '/widgets?refresh=true', 'it has the refresh url'); const promise = rs.refresh(); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index f82d4b70653..69855950146 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -30,9 +30,9 @@ //= require sinon-1.7.1 //= require sinon-qunit-1.0.0 +//= require helpers/qunit-helpers //= require helpers/assertions -//= require helpers/qunit-helpers //= require_tree ./fixtures //= require_tree ./lib //= require_tree . diff --git a/test/javascripts/widgets/actions-summary-test.js.es6 b/test/javascripts/widgets/actions-summary-test.js.es6 index 6542d17b12c..9b7f9cea233 100644 --- a/test/javascripts/widgets/actions-summary-test.js.es6 +++ b/test/javascripts/widgets/actions-summary-test.js.es6 @@ -23,7 +23,7 @@ widgetTest('listing actions', { }); widgetTest('undo', { - template: '{{mount-widget widget="actions-summary" args=args undoPostAction=undoPostAction}}', + template: '{{mount-widget widget="actions-summary" args=args undoPostAction="undoPostAction"}}', setup() { this.set('args', { actionsSummary: [ @@ -31,7 +31,7 @@ widgetTest('undo', { ] }); - this.set('undoPostAction', () => this.undid = true); + this.on('undoPostAction', () => this.undid = true); }, test(assert) { assert.equal(this.$('.post-actions .post-action').length, 1); diff --git a/vendor/assets/javascripts/ember-qunit.js b/vendor/assets/javascripts/ember-qunit.js index cf41920e2e6..759edca9be9 100644 --- a/vendor/assets/javascripts/ember-qunit.js +++ b/vendor/assets/javascripts/ember-qunit.js @@ -111,82 +111,81 @@ var define, requireModule, require, requirejs; }; })(); -define('ember-qunit', ['exports', 'ember-qunit/module-for', 'ember-qunit/module-for-component', 'ember-qunit/module-for-model', 'ember-qunit/adapter', 'ember-test-helpers', 'qunit'], function (exports, _emberQunitModuleFor, _emberQunitModuleForComponent, _emberQunitModuleForModel, _emberQunitAdapter, _emberTestHelpers, _qunit) { +define('ember-qunit', ['exports', 'ember-qunit/module-for', 'ember-qunit/module-for-component', 'ember-qunit/module-for-model', 'ember-qunit/test', 'ember-qunit/only', 'ember-test-helpers'], function (exports, moduleFor, moduleForComponent, moduleForModel, test, only, ember_test_helpers) { + 'use strict'; - exports.module = _qunit.module; - exports.test = _qunit.test; - exports.skip = _qunit.skip; - exports.only = _qunit.only; - exports.moduleFor = _emberQunitModuleFor['default']; - exports.moduleForComponent = _emberQunitModuleForComponent['default']; - exports.moduleForModel = _emberQunitModuleForModel['default']; - exports.setResolver = _emberTestHelpers.setResolver; - exports.QUnitAdapter = _emberQunitAdapter['default']; + + + exports.moduleFor = moduleFor['default']; + exports.moduleForComponent = moduleForComponent['default']; + exports.moduleForModel = moduleForModel['default']; + exports.test = test['default']; + exports.only = only['default']; + exports.setResolver = ember_test_helpers.setResolver; + }); -define('ember-qunit/adapter', ['exports', 'ember', 'qunit'], function (exports, _ember, _qunit) { +define('ember-qunit/module-for-component', ['exports', 'ember-qunit/qunit-module', 'ember-test-helpers'], function (exports, qunit_module, ember_test_helpers) { + 'use strict'; - exports['default'] = _ember['default'].Test.Adapter.extend({ - init: function init() { - this.doneCallbacks = []; - }, - - asyncStart: function asyncStart() { - this.doneCallbacks.push(_qunit['default'].config.current.assert.async()); - }, - - asyncEnd: function asyncEnd() { - this.doneCallbacks.pop()(); - }, - - exception: function exception(error) { - _qunit['default'].config.current.assert.ok(false, _ember['default'].inspect(error)); - } - }); -}); -define('ember-qunit/module-for-component', ['exports', './qunit-module', 'ember-test-helpers'], function (exports, _qunitModule, _emberTestHelpers) { - 'use strict'; - - exports['default'] = moduleForComponent; - function moduleForComponent(name, description, callbacks) { - _qunitModule.createModule(_emberTestHelpers.TestModuleForComponent, name, description, callbacks); + qunit_module.createModule(ember_test_helpers.TestModuleForComponent, name, description, callbacks); } -}); -define('ember-qunit/module-for-model', ['exports', './qunit-module', 'ember-test-helpers'], function (exports, _qunitModule, _emberTestHelpers) { - 'use strict'; + exports['default'] = moduleForComponent; - exports['default'] = moduleForModel; +}); +define('ember-qunit/module-for-model', ['exports', 'ember-qunit/qunit-module', 'ember-test-helpers'], function (exports, qunit_module, ember_test_helpers) { + + 'use strict'; function moduleForModel(name, description, callbacks) { - _qunitModule.createModule(_emberTestHelpers.TestModuleForModel, name, description, callbacks); + qunit_module.createModule(ember_test_helpers.TestModuleForModel, name, description, callbacks); } + exports['default'] = moduleForModel; + }); -define('ember-qunit/module-for', ['exports', './qunit-module', 'ember-test-helpers'], function (exports, _qunitModule, _emberTestHelpers) { +define('ember-qunit/module-for', ['exports', 'ember-qunit/qunit-module', 'ember-test-helpers'], function (exports, qunit_module, ember_test_helpers) { + 'use strict'; + function moduleFor(name, description, callbacks) { + qunit_module.createModule(ember_test_helpers.TestModule, name, description, callbacks); + } exports['default'] = moduleFor; - function moduleFor(name, description, callbacks) { - _qunitModule.createModule(_emberTestHelpers.TestModule, name, description, callbacks); - } }); -define('ember-qunit/qunit-module', ['exports', 'ember', 'qunit'], function (exports, _ember, _qunit) { +define('ember-qunit/only', ['exports', 'ember-qunit/test-wrapper', 'qunit'], function (exports, testWrapper, qunit) { + + 'use strict'; + + function only(/* testName, expected, callback, async */) { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; ++_key) { + args[_key] = arguments[_key]; + } + args.unshift(qunit.only); + testWrapper['default'].apply(null, args); + } + exports['default'] = only; + +}); +define('ember-qunit/qunit-module', ['exports', 'qunit'], function (exports, qunit) { + 'use strict'; exports.createModule = createModule; function beforeEachCallback(callbacks) { - if (typeof callbacks !== 'object') { - return; - } - if (!callbacks) { - return; - } + if (typeof callbacks !== 'object') { return; } + if (!callbacks) { return; } var beforeEach; + if (callbacks.setup) { + beforeEach = callbacks.setup; + delete callbacks.setup; + } + if (callbacks.beforeEach) { beforeEach = callbacks.beforeEach; delete callbacks.beforeEach; @@ -196,15 +195,16 @@ define('ember-qunit/qunit-module', ['exports', 'ember', 'qunit'], function (expo } function afterEachCallback(callbacks) { - if (typeof callbacks !== 'object') { - return; - } - if (!callbacks) { - return; - } + if (typeof callbacks !== 'object') { return; } + if (!callbacks) { return; } var afterEach; + if (callbacks.teardown) { + afterEach = callbacks.teardown; + delete callbacks.teardown; + } + if (callbacks.afterEach) { afterEach = callbacks.afterEach; delete callbacks.afterEach; @@ -214,349 +214,129 @@ define('ember-qunit/qunit-module', ['exports', 'ember', 'qunit'], function (expo } function createModule(Constructor, name, description, callbacks) { - var _beforeEach = beforeEachCallback(callbacks || description); - var _afterEach = afterEachCallback(callbacks || description); + var beforeEach = beforeEachCallback(callbacks || description); + var afterEach = afterEachCallback(callbacks || description); var module = new Constructor(name, description, callbacks); - _qunit.module(module.name, { - beforeEach: function beforeEach() { - var _this = this, - _arguments = arguments; - - // provide the test context to the underlying module - module.setContext(this); - - return module.setup.apply(module, arguments).then(function () { - if (_beforeEach) { - return _beforeEach.apply(_this, _arguments); + qunit.module(module.name, { + setup: function(assert) { + var done = assert.async(); + return module.setup().then(function() { + if (beforeEach) { + beforeEach.call(module.context, assert); } - }); + })['finally'](done); }, - afterEach: function afterEach() { - var _arguments2 = arguments; - - var result = undefined; - - if (_afterEach) { - result = _afterEach.apply(this, arguments); + teardown: function(assert) { + if (afterEach) { + afterEach.call(module.context, assert); } - - return _ember['default'].RSVP.resolve(result).then(function () { - return module.teardown.apply(module, _arguments2); - }); + var done = assert.async(); + return module.teardown()['finally'](done); } }); } + }); -define('ember-test-helpers', ['exports', 'ember', 'ember-test-helpers/test-module', 'ember-test-helpers/test-module-for-acceptance', 'ember-test-helpers/test-module-for-integration', 'ember-test-helpers/test-module-for-component', 'ember-test-helpers/test-module-for-model', 'ember-test-helpers/test-context', 'ember-test-helpers/test-resolver'], function (exports, _ember, _emberTestHelpersTestModule, _emberTestHelpersTestModuleForAcceptance, _emberTestHelpersTestModuleForIntegration, _emberTestHelpersTestModuleForComponent, _emberTestHelpersTestModuleForModel, _emberTestHelpersTestContext, _emberTestHelpersTestResolver) { +define('ember-qunit/test-wrapper', ['exports', 'ember', 'ember-test-helpers'], function (exports, Ember, ember_test_helpers) { + 'use strict'; - _ember['default'].testing = true; - - exports.TestModule = _emberTestHelpersTestModule['default']; - exports.TestModuleForAcceptance = _emberTestHelpersTestModuleForAcceptance['default']; - exports.TestModuleForIntegration = _emberTestHelpersTestModuleForIntegration['default']; - exports.TestModuleForComponent = _emberTestHelpersTestModuleForComponent['default']; - exports.TestModuleForModel = _emberTestHelpersTestModuleForModel['default']; - exports.getContext = _emberTestHelpersTestContext.getContext; - exports.setContext = _emberTestHelpersTestContext.setContext; - exports.unsetContext = _emberTestHelpersTestContext.unsetContext; - exports.setResolver = _emberTestHelpersTestResolver.setResolver; -}); -define('ember-test-helpers/-legacy-overrides', ['exports', 'ember', './has-ember-version'], function (exports, _ember, _hasEmberVersion) { - 'use strict'; - - exports.preGlimmerSetupIntegrationForComponent = preGlimmerSetupIntegrationForComponent; - - function preGlimmerSetupIntegrationForComponent() { - var module = this; - var context = this.context; - - this.actionHooks = {}; - - context.dispatcher = this.container.lookup('event_dispatcher:main') || _ember['default'].EventDispatcher.create(); - context.dispatcher.setup({}, '#ember-testing'); - context.actions = module.actionHooks; - - (this.registry || this.container).register('component:-test-holder', _ember['default'].Component.extend()); - - context.render = function (template) { - // in case `this.render` is called twice, make sure to teardown the first invocation - module.teardownComponent(); - - if (!template) { - throw new Error("in a component integration test you must pass a template to `render()`"); - } - if (_ember['default'].isArray(template)) { - template = template.join(''); - } - if (typeof template === 'string') { - template = _ember['default'].Handlebars.compile(template); - } - module.component = module.container.lookupFactory('component:-test-holder').create({ - layout: template - }); - - module.component.set('context', context); - module.component.set('controller', context); - - _ember['default'].run(function () { - module.component.appendTo('#ember-testing'); - }); - - context._element = module.component.element; - }; - - context.$ = function () { - return module.component.$.apply(module.component, arguments); - }; - - context.set = function (key, value) { - var ret = _ember['default'].run(function () { - return _ember['default'].set(context, key, value); - }); - - if (_hasEmberVersion['default'](2, 0)) { - return ret; - } - }; - - context.setProperties = function (hash) { - var ret = _ember['default'].run(function () { - return _ember['default'].setProperties(context, hash); - }); - - if (_hasEmberVersion['default'](2, 0)) { - return ret; - } - }; - - context.get = function (key) { - return _ember['default'].get(context, key); - }; - - context.getProperties = function () { - var args = Array.prototype.slice.call(arguments); - return _ember['default'].getProperties(context, args); - }; - - context.on = function (actionName, handler) { - module.actionHooks[actionName] = handler; - }; - - context.send = function (actionName) { - var hook = module.actionHooks[actionName]; - if (!hook) { - throw new Error("integration testing template received unexpected action " + actionName); - } - hook.apply(module, Array.prototype.slice.call(arguments, 1)); - }; - - context.clearRender = function () { - module.teardownComponent(); - }; - } -}); -define('ember-test-helpers/abstract-test-module', ['exports', './wait', './test-context', 'ember'], function (exports, _wait, _testContext, _ember) { - 'use strict'; - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - // calling this `merge` here because we cannot - // actually assume it is like `Object.assign` - // with > 2 args - var merge = _ember['default'].assign || _ember['default'].merge; - - var _default = (function () { - function _default(name, options) { - _classCallCheck(this, _default); - - this.context = undefined; - this.name = name; - this.callbacks = options || {}; - - this.initSetupSteps(); - this.initTeardownSteps(); + function testWrapper(qunit /*, testName, expected, callback, async */) { + var callback; + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; ++_key) { + args[_key - 1] = arguments[_key]; } - _default.prototype.setup = function setup(assert) { - var _this = this; + function wrapper() { + var context = ember_test_helpers.getContext(); - return this.invokeSteps(this.setupSteps, this, assert).then(function () { - _this.contextualizeCallbacks(); - return _this.invokeSteps(_this.contextualizedSetupSteps, _this.context, assert); - }); - }; + var result = callback.apply(context, arguments); - _default.prototype.teardown = function teardown(assert) { - var _this2 = this; - - return this.invokeSteps(this.contextualizedTeardownSteps, this.context, assert).then(function () { - return _this2.invokeSteps(_this2.teardownSteps, _this2, assert); - }).then(function () { - _this2.cache = null; - _this2.cachedCalls = null; - }); - }; - - _default.prototype.initSetupSteps = function initSetupSteps() { - this.setupSteps = []; - this.contextualizedSetupSteps = []; - - if (this.callbacks.beforeSetup) { - this.setupSteps.push(this.callbacks.beforeSetup); - delete this.callbacks.beforeSetup; - } - - this.setupSteps.push(this.setupContext); - this.setupSteps.push(this.setupTestElements); - this.setupSteps.push(this.setupAJAXListeners); - - if (this.callbacks.setup) { - this.contextualizedSetupSteps.push(this.callbacks.setup); - delete this.callbacks.setup; - } - }; - - _default.prototype.invokeSteps = function invokeSteps(steps, context, assert) { - steps = steps.slice(); - - function nextStep() { - var step = steps.shift(); - if (step) { - // guard against exceptions, for example missing components referenced from needs. - return new _ember['default'].RSVP.Promise(function (resolve) { - resolve(step.call(context, assert)); - }).then(nextStep); + function failTestOnPromiseRejection(reason) { + var message; + if (reason instanceof Error) { + message = reason.stack; + if (reason.message && message.indexOf(reason.message) < 0) { + // PhantomJS has a `stack` that does not contain the actual + // exception message. + message = Ember['default'].inspect(reason) + "\n" + message; + } } else { - return _ember['default'].RSVP.resolve(); + message = Ember['default'].inspect(reason); } - } - return nextStep(); - }; - - _default.prototype.contextualizeCallbacks = function contextualizeCallbacks() {}; - - _default.prototype.initTeardownSteps = function initTeardownSteps() { - this.teardownSteps = []; - this.contextualizedTeardownSteps = []; - - if (this.callbacks.teardown) { - this.contextualizedTeardownSteps.push(this.callbacks.teardown); - delete this.callbacks.teardown; + ok(false, message); } - this.teardownSteps.push(this.teardownContext); - this.teardownSteps.push(this.teardownTestElements); - this.teardownSteps.push(this.teardownAJAXListeners); - - if (this.callbacks.afterTeardown) { - this.teardownSteps.push(this.callbacks.afterTeardown); - delete this.callbacks.afterTeardown; - } - }; - - _default.prototype.setupTestElements = function setupTestElements() { - var testEl = document.querySelector('#ember-testing'); - if (!testEl) { - var element = document.createElement('div'); - element.setAttribute('id', 'ember-testing'); - - document.body.appendChild(element); - this.fixtureResetValue = ''; - } else { - this.fixtureResetValue = testEl.innerHTML; - } - }; - - _default.prototype.setupContext = function setupContext(options) { - var context = this.getContext(); - - merge(context, { - dispatcher: null, - inject: {} + Ember['default'].run(function(){ + QUnit.stop(); + Ember['default'].RSVP.Promise.resolve(result)['catch'](failTestOnPromiseRejection)['finally'](QUnit.start); }); - merge(context, options); + } - this.setToString(); - _testContext.setContext(context); - this.context = context; - }; + if (args.length === 2) { + callback = args.splice(1, 1, wrapper)[0]; + } else { + callback = args.splice(2, 1, wrapper)[0]; + } - _default.prototype.setContext = function setContext(context) { - this.context = context; - }; + qunit.apply(null, args); + } + exports['default'] = testWrapper; - _default.prototype.getContext = function getContext() { - if (this.context) { - return this.context; - } - - return this.context = _testContext.getContext() || {}; - }; - - _default.prototype.setToString = function setToString() { - var _this3 = this; - - this.context.toString = function () { - if (_this3.subjectName) { - return 'test context for: ' + _this3.subjectName; - } - - if (_this3.name) { - return 'test context for: ' + _this3.name; - } - }; - }; - - _default.prototype.setupAJAXListeners = function setupAJAXListeners() { - _wait._setupAJAXHooks(); - }; - - _default.prototype.teardownAJAXListeners = function teardownAJAXListeners() { - _wait._teardownAJAXHooks(); - }; - - _default.prototype.teardownTestElements = function teardownTestElements() { - document.getElementById('ember-testing').innerHTML = this.fixtureResetValue; - - // Ember 2.0.0 removed Ember.View as public API, so only do this when - // Ember.View is present - if (_ember['default'].View && _ember['default'].View.views) { - _ember['default'].View.views = {}; - } - }; - - _default.prototype.teardownContext = function teardownContext() { - var context = this.context; - this.context = undefined; - _testContext.unsetContext(); - - if (context && context.dispatcher && !context.dispatcher.isDestroyed) { - _ember['default'].run(function () { - context.dispatcher.destroy(); - }); - } - }; - - return _default; - })(); - - exports['default'] = _default; }); -define('ember-test-helpers/build-registry', ['exports', 'ember'], function (exports, _ember) { - /* globals global, self, requirejs, require */ +define('ember-qunit/test', ['exports', 'ember-qunit/test-wrapper', 'qunit'], function (exports, testWrapper, qunit) { + + 'use strict'; + + function test(/* testName, expected, callback, async */) { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; ++_key) { + args[_key] = arguments[_key]; + } + args.unshift(qunit.test); + testWrapper['default'].apply(null, args); + } + exports['default'] = test; + +}); +define('ember-test-helpers', ['exports', 'ember', 'ember-test-helpers/test-module', 'ember-test-helpers/test-module-for-component', 'ember-test-helpers/test-module-for-model', 'ember-test-helpers/test-context', 'ember-test-helpers/test-resolver'], function (exports, Ember, TestModule, TestModuleForComponent, TestModuleForModel, test_context, test_resolver) { + + 'use strict'; + + Ember['default'].testing = true; + + exports.TestModule = TestModule['default']; + exports.TestModuleForComponent = TestModuleForComponent['default']; + exports.TestModuleForModel = TestModuleForModel['default']; + exports.getContext = test_context.getContext; + exports.setContext = test_context.setContext; + exports.setResolver = test_resolver.setResolver; + +}); +define('ember-test-helpers/build-registry', ['exports', 'ember'], function (exports, Ember) { 'use strict'; function exposeRegistryMethodsWithoutDeprecations(container) { - var methods = ['register', 'unregister', 'resolve', 'normalize', 'typeInjection', 'injection', 'factoryInjection', 'factoryTypeInjection', 'has', 'options', 'optionsForType']; + var methods = [ + 'register', + 'unregister', + 'resolve', + 'normalize', + 'typeInjection', + 'injection', + 'factoryInjection', + 'factoryTypeInjection', + 'has', + 'options', + 'optionsForType' + ]; function exposeRegistryMethod(container, method) { if (method in container) { - container[method] = function () { + container[method] = function() { return container._registry[method].apply(container._registry, arguments); }; } @@ -567,20 +347,18 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo } } - var Owner = (function () { - if (_ember['default']._RegistryProxyMixin && _ember['default']._ContainerProxyMixin) { - return _ember['default'].Object.extend(_ember['default']._RegistryProxyMixin, _ember['default']._ContainerProxyMixin); + var Owner = (function() { + if (Ember['default']._RegistryProxyMixin && Ember['default']._ContainerProxyMixin) { + return Ember['default'].Object.extend(Ember['default']._RegistryProxyMixin, Ember['default']._ContainerProxyMixin); } - return _ember['default'].Object.extend(); + return Ember['default'].Object.extend(); })(); - exports['default'] = function (resolver) { + exports['default'] = function(resolver) { var fallbackRegistry, registry, container; - var namespace = _ember['default'].Object.create({ - Resolver: { create: function create() { - return resolver; - } } + var namespace = Ember['default'].Object.create({ + Resolver: { create: function() { return resolver; } } }); function register(name, factory) { @@ -591,18 +369,14 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo } } - if (_ember['default'].Application.buildRegistry) { - fallbackRegistry = _ember['default'].Application.buildRegistry(namespace); - fallbackRegistry.register('component-lookup:main', _ember['default'].ComponentLookup); + if (Ember['default'].Application.buildRegistry) { + fallbackRegistry = Ember['default'].Application.buildRegistry(namespace); + fallbackRegistry.register('component-lookup:main', Ember['default'].ComponentLookup); - registry = new _ember['default'].Registry({ + registry = new Ember['default'].Registry({ fallback: fallbackRegistry }); - if (_ember['default'].ApplicationInstance && _ember['default'].ApplicationInstance.setupRegistry) { - _ember['default'].ApplicationInstance.setupRegistry(registry); - } - // these properties are set on the fallback registry by `buildRegistry` // and on the primary registry within the ApplicationInstance constructor // but we need to manually recreate them since ApplicationInstance's are not @@ -621,8 +395,8 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo exposeRegistryMethodsWithoutDeprecations(container); } else { - container = _ember['default'].Application.buildContainer(namespace); - container.register('component-lookup:main', _ember['default'].ComponentLookup); + container = Ember['default'].Application.buildContainer(namespace); + container.register('component-lookup:main', Ember['default'].ComponentLookup); } // Ember 1.10.0 did not properly add `view:toplevel` or `view:default` @@ -630,26 +404,18 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo // // Ember 2.0.0 removed Ember.View as public API, so only do this when // Ember.View is present - if (_ember['default'].View) { - register('view:toplevel', _ember['default'].View.extend()); + if (Ember['default'].View) { + register('view:toplevel', Ember['default'].View.extend()); } // Ember 2.0.0 removed Ember._MetamorphView from the Ember global, so only // do this when present - if (_ember['default']._MetamorphView) { - register('view:default', _ember['default']._MetamorphView); + if (Ember['default']._MetamorphView) { + register('view:default', Ember['default']._MetamorphView); } var globalContext = typeof global === 'object' && global || self; - if (requirejs.entries['ember-data/setup-container']) { - // ember-data is a proper ember-cli addon since 2.3; if no 'import - // 'ember-data'' is present somewhere in the tests, there is also no `DS` - // available on the globalContext and hence ember-data wouldn't be setup - // correctly for the tests; that's why we import and call setupContainer - // here; also see https://github.com/emberjs/data/issues/4071 for context - var setupContainer = require('ember-data/setup-container')['default']; - setupContainer(registry || container); - } else if (globalContext.DS) { + if (globalContext.DS) { var DS = globalContext.DS; if (DS._setupContainer) { DS._setupContainer(registry || container); @@ -668,26 +434,30 @@ define('ember-test-helpers/build-registry', ['exports', 'ember'], function (expo registry: registry, container: container }; - }; + } + }); -define('ember-test-helpers/has-ember-version', ['exports', 'ember'], function (exports, _ember) { +define('ember-test-helpers/has-ember-version', ['exports', 'ember'], function (exports, Ember) { + 'use strict'; - exports['default'] = hasEmberVersion; - function hasEmberVersion(major, minor) { - var numbers = _ember['default'].VERSION.split('-')[0].split('.'); + var numbers = Ember['default'].VERSION.split('-')[0].split('.'); var actualMajor = parseInt(numbers[0], 10); var actualMinor = parseInt(numbers[1], 10); - return actualMajor > major || actualMajor === major && actualMinor >= minor; + return actualMajor > major || (actualMajor === major && actualMinor >= minor); } + exports['default'] = hasEmberVersion; + }); -define("ember-test-helpers/test-context", ["exports"], function (exports) { - "use strict"; +define('ember-test-helpers/test-context', ['exports'], function (exports) { + + 'use strict'; exports.setContext = setContext; exports.getContext = getContext; exports.unsetContext = unsetContext; + var __test_context__; function setContext(context) { @@ -701,82 +471,16 @@ define("ember-test-helpers/test-context", ["exports"], function (exports) { function unsetContext() { __test_context__ = undefined; } + }); -define('ember-test-helpers/test-module-for-acceptance', ['exports', './abstract-test-module', 'ember', './test-context'], function (exports, _abstractTestModule, _ember, _testContext) { +define('ember-test-helpers/test-module-for-component', ['exports', 'ember-test-helpers/test-module', 'ember', 'ember-test-helpers/test-resolver'], function (exports, TestModule, Ember, test_resolver) { + 'use strict'; - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var _default = (function (_AbstractTestModule) { - _inherits(_default, _AbstractTestModule); - - function _default() { - _classCallCheck(this, _default); - - _AbstractTestModule.apply(this, arguments); - } - - _default.prototype.setupContext = function setupContext() { - _AbstractTestModule.prototype.setupContext.call(this, { application: this.createApplication() }); - }; - - _default.prototype.teardownContext = function teardownContext() { - _ember['default'].run(function () { - _testContext.getContext().application.destroy(); - }); - - _AbstractTestModule.prototype.teardownContext.call(this); - }; - - _default.prototype.createApplication = function createApplication() { - var _callbacks = this.callbacks; - var Application = _callbacks.Application; - var config = _callbacks.config; - - var application = undefined; - - _ember['default'].run(function () { - application = Application.create(config); - application.setupForTesting(); - application.injectTestHelpers(); - }); - - return application; - }; - - return _default; - })(_abstractTestModule['default']); - - exports['default'] = _default; -}); -define('ember-test-helpers/test-module-for-component', ['exports', './test-module', 'ember', './has-ember-version', './-legacy-overrides'], function (exports, _testModule, _ember, _hasEmberVersion, _legacyOverrides) { - 'use strict'; - - exports.setupComponentIntegrationTest = _setupComponentIntegrationTest; - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var ACTION_KEY = undefined; - if (_hasEmberVersion['default'](2, 0)) { - ACTION_KEY = 'actions'; - } else { - ACTION_KEY = '_actions'; - } - - var isPreGlimmer = !_hasEmberVersion['default'](1, 13); - - var getOwner = _ember['default'].getOwner; - - var _default = (function (_TestModule) { - _inherits(_default, _TestModule); - - function _default(componentName, description, callbacks) { - _classCallCheck(this, _default); + exports['default'] = TestModule['default'].extend({ + isComponentTestModule: true, + init: function(componentName, description, callbacks) { // Allow `description` to be omitted if (!callbacks && typeof description === 'object') { callbacks = description; @@ -785,21 +489,30 @@ define('ember-test-helpers/test-module-for-component', ['exports', './test-modul callbacks = {}; } - var integrationOption = callbacks.integration; - - _TestModule.call(this, 'component:' + componentName, description, callbacks); - this.componentName = componentName; - if (callbacks.needs || callbacks.unit || integrationOption === false) { + if (callbacks.needs || callbacks.unit || callbacks.integration === false) { this.isUnitTest = true; - } else if (integrationOption) { + } else if (callbacks.integration) { this.isUnitTest = false; } else { - _ember['default'].deprecate("the component:" + componentName + " test module is implicitly running in unit test mode, " + "which will change to integration test mode by default in an upcoming version of " + "ember-test-helpers. Add `unit: true` or a `needs:[]` list to explicitly opt in to unit " + "test mode.", false, { id: 'ember-test-helpers.test-module-for-component.test-type', until: '0.6.0' }); + Ember['default'].deprecate( + "the component:" + componentName + " test module is implicitly running in unit test mode, " + + "which will change to integration test mode by default in an upcoming version of " + + "ember-test-helpers. Add `unit: true` or a `needs:[]` list to explicitly opt in to unit " + + "test mode.", + false, + { id: 'ember-test-helpers.test-module-for-component.test-type', until: '0.6.0' } + ); this.isUnitTest = true; } + if (description) { + this._super.call(this, 'component:' + componentName, description, callbacks); + } else { + this._super.call(this, 'component:' + componentName, callbacks); + } + if (!this.isUnitTest && !this.isLegacy) { callbacks.integration = true; } @@ -807,40 +520,35 @@ define('ember-test-helpers/test-module-for-component', ['exports', './test-modul if (this.isUnitTest || this.isLegacy) { this.setupSteps.push(this.setupComponentUnitTest); } else { - this.callbacks.subject = function () { - throw new Error("component integration tests do not support `subject()`. Instead, render the component as if it were HTML: `this.render('');`. For more information, read: http://guides.emberjs.com/v2.2.0/testing/testing-components/"); + this.callbacks.subject = function() { + throw new Error("component integration tests do not support `subject()`."); }; this.setupSteps.push(this.setupComponentIntegrationTest); this.teardownSteps.unshift(this.teardownComponent); } - if (_ember['default'].View && _ember['default'].View.views) { + if (Ember['default'].View && Ember['default'].View.views) { this.setupSteps.push(this._aliasViewRegistry); this.teardownSteps.unshift(this._resetViewRegistry); } - } + }, - _default.prototype.initIntegration = function initIntegration(options) { - this.isLegacy = options.integration === 'legacy'; - this.isIntegration = options.integration !== 'legacy'; - }; - - _default.prototype._aliasViewRegistry = function _aliasViewRegistry() { - this._originalGlobalViewRegistry = _ember['default'].View.views; + _aliasViewRegistry: function() { + this._originalGlobalViewRegistry = Ember['default'].View.views; var viewRegistry = this.container.lookup('-view-registry:main'); if (viewRegistry) { - _ember['default'].View.views = viewRegistry; + Ember['default'].View.views = viewRegistry; } - }; + }, - _default.prototype._resetViewRegistry = function _resetViewRegistry() { - _ember['default'].View.views = this._originalGlobalViewRegistry; - }; + _resetViewRegistry: function() { + Ember['default'].View.views = this._originalGlobalViewRegistry; + }, - _default.prototype.setupComponentUnitTest = function setupComponentUnitTest() { + setupComponentUnitTest: function() { var _this = this; - var resolver = this.resolver; + var resolver = test_resolver.getResolver(); var context = this.context; var layoutName = 'template:components/' + this.componentName; @@ -853,51 +561,114 @@ define('ember-test-helpers/test-module-for-component', ['exports', './test-modul thingToRegisterWith.injection(this.subjectName, 'layout', layoutName); } - context.dispatcher = this.container.lookup('event_dispatcher:main') || _ember['default'].EventDispatcher.create(); + context.dispatcher = this.container.lookup('event_dispatcher:main') || Ember['default'].EventDispatcher.create(); context.dispatcher.setup({}, '#ember-testing'); - context._element = null; - - this.callbacks.render = function () { + this.callbacks.render = function() { var subject; - _ember['default'].run(function () { + Ember['default'].run(function(){ subject = context.subject(); subject.appendTo('#ember-testing'); }); - context._element = subject.element; - - _this.teardownSteps.unshift(function () { - _ember['default'].run(function () { - _ember['default'].tryInvoke(subject, 'destroy'); + _this.teardownSteps.unshift(function() { + Ember['default'].run(function() { + Ember['default'].tryInvoke(subject, 'destroy'); }); }); }; - this.callbacks.append = function () { - _ember['default'].deprecate('this.append() is deprecated. Please use this.render() or this.$() instead.', false, { id: 'ember-test-helpers.test-module-for-component.append', until: '0.6.0' }); + this.callbacks.append = function() { + Ember['default'].deprecate( + 'this.append() is deprecated. Please use this.render() or this.$() instead.', + false, + { id: 'ember-test-helpers.test-module-for-component.append', until: '0.6.0' } + ); return context.$(); }; - context.$ = function () { + context.$ = function() { this.render(); var subject = this.subject(); return subject.$.apply(subject, arguments); }; - }; + }, - _default.prototype.setupComponentIntegrationTest = function setupComponentIntegrationTest() { - if (isPreGlimmer) { - return _legacyOverrides.preGlimmerSetupIntegrationForComponent.apply(this, arguments); - } else { - return _setupComponentIntegrationTest.apply(this, arguments); - } - }; + setupComponentIntegrationTest: function() { + var module = this; + var context = this.context; - _default.prototype.setupContext = function setupContext() { - _TestModule.prototype.setupContext.call(this); + this.actionHooks = {}; + + context.dispatcher = this.container.lookup('event_dispatcher:main') || Ember['default'].EventDispatcher.create(); + context.dispatcher.setup({}, '#ember-testing'); + context.actions = module.actionHooks; + + (this.registry || this.container).register('component:-test-holder', Ember['default'].Component.extend()); + + context.render = function(template) { + if (!template) { + throw new Error("in a component integration test you must pass a template to `render()`"); + } + if (Ember['default'].isArray(template)) { + template = template.join(''); + } + if (typeof template === 'string') { + template = Ember['default'].Handlebars.compile(template); + } + module.component = module.container.lookupFactory('component:-test-holder').create({ + layout: template + }); + + module.component.set('context' ,context); + module.component.set('controller', context); + + Ember['default'].run(function() { + module.component.appendTo('#ember-testing'); + }); + }; + + context.$ = function() { + return module.component.$.apply(module.component, arguments); + }; + + context.set = function(key, value) { + Ember['default'].run(function() { + Ember['default'].set(context, key, value); + }); + }; + + context.setProperties = function(hash) { + Ember['default'].run(function() { + Ember['default'].setProperties(context, hash); + }); + }; + + context.get = function(key) { + return Ember['default'].get(context, key); + }; + + context.getProperties = function() { + var args = Array.prototype.slice.call(arguments); + return Ember['default'].getProperties(context, args); + }; + + context.on = function(actionName, handler) { + module.actionHooks[actionName] = handler; + }; + context.send = function(actionName) { + var hook = module.actionHooks[actionName]; + if (!hook) { + throw new Error("integration testing template received unexpected action " + actionName); + } + hook.apply(module, Array.prototype.slice.call(arguments, 1)); + }; + }, + + setupContext: function() { + this._super.call(this); // only setup the injection if we are running against a version // of Ember that has `-view-registry:main` (Ember >= 1.12) @@ -906,409 +677,35 @@ define('ember-test-helpers/test-module-for-component', ['exports', './test-modul } if (!this.isUnitTest && !this.isLegacy) { - this.context.factory = function () {}; + this.context.factory = function() {}; } - }; + }, - _default.prototype.teardownComponent = function teardownComponent() { + teardownComponent: function() { var component = this.component; if (component) { - _ember['default'].run(component, 'destroy'); - this.component = null; - } - }; - - return _default; - })(_testModule['default']); - - exports['default'] = _default; - - function _setupComponentIntegrationTest() { - var module = this; - var context = this.context; - - this.actionHooks = context[ACTION_KEY] = {}; - context.dispatcher = this.container.lookup('event_dispatcher:main') || _ember['default'].EventDispatcher.create(); - context.dispatcher.setup({}, '#ember-testing'); - - var hasRendered = false; - var OutletView = module.container.lookupFactory('view:-outlet'); - var OutletTemplate = module.container.lookup('template:-outlet'); - var toplevelView = module.component = OutletView.create(); - var hasOutletTemplate = !!OutletTemplate; - var outletState = { - render: { - owner: getOwner ? getOwner(module.container) : undefined, - into: undefined, - outlet: 'main', - name: 'application', - controller: module.context, - ViewClass: undefined, - template: OutletTemplate - }, - - outlets: {} - }; - - var element = document.getElementById('ember-testing'); - var templateId = 0; - - if (hasOutletTemplate) { - _ember['default'].run(function () { - toplevelView.setOutletState(outletState); - }); - } - - context.render = function (template) { - if (!template) { - throw new Error("in a component integration test you must pass a template to `render()`"); - } - if (_ember['default'].isArray(template)) { - template = template.join(''); - } - if (typeof template === 'string') { - template = _ember['default'].Handlebars.compile(template); - } - - var templateFullName = 'template:-undertest-' + ++templateId; - this.registry.register(templateFullName, template); - var stateToRender = { - owner: getOwner ? getOwner(module.container) : undefined, - into: undefined, - outlet: 'main', - name: 'index', - controller: module.context, - ViewClass: undefined, - template: module.container.lookup(templateFullName), - outlets: {} - }; - - if (hasOutletTemplate) { - stateToRender.name = 'index'; - outletState.outlets.main = { render: stateToRender, outlets: {} }; - } else { - stateToRender.name = 'application'; - outletState = { render: stateToRender, outlets: {} }; - } - - _ember['default'].run(function () { - toplevelView.setOutletState(outletState); - }); - - if (!hasRendered) { - _ember['default'].run(module.component, 'appendTo', '#ember-testing'); - hasRendered = true; - } - - // ensure the element is based on the wrapping toplevel view - // Ember still wraps the main application template with a - // normal tagged view - context._element = element = document.querySelector('#ember-testing > .ember-view'); - }; - - context.$ = function (selector) { - // emulates Ember internal behavor of `this.$` in a component - // https://github.com/emberjs/ember.js/blob/v2.5.1/packages/ember-views/lib/views/states/has_element.js#L18 - return selector ? _ember['default'].$(selector, element) : _ember['default'].$(element); - }; - - context.set = function (key, value) { - var ret = _ember['default'].run(function () { - return _ember['default'].set(context, key, value); - }); - - if (_hasEmberVersion['default'](2, 0)) { - return ret; - } - }; - - context.setProperties = function (hash) { - var ret = _ember['default'].run(function () { - return _ember['default'].setProperties(context, hash); - }); - - if (_hasEmberVersion['default'](2, 0)) { - return ret; - } - }; - - context.get = function (key) { - return _ember['default'].get(context, key); - }; - - context.getProperties = function () { - var args = Array.prototype.slice.call(arguments); - return _ember['default'].getProperties(context, args); - }; - - context.on = function (actionName, handler) { - module.actionHooks[actionName] = handler; - }; - - context.send = function (actionName) { - var hook = module.actionHooks[actionName]; - if (!hook) { - throw new Error("integration testing template received unexpected action " + actionName); - } - hook.apply(module.context, Array.prototype.slice.call(arguments, 1)); - }; - - context.clearRender = function () { - _ember['default'].run(function () { - toplevelView.setOutletState({ - render: { - owner: module.container, - into: undefined, - outlet: 'main', - name: 'application', - controller: module.context, - ViewClass: undefined, - template: undefined - }, - outlets: {} - }); - }); - }; - } -}); -define('ember-test-helpers/test-module-for-integration', ['exports', 'ember', './abstract-test-module', './test-resolver', './build-registry', './has-ember-version', './-legacy-overrides', './test-module-for-component'], function (exports, _ember, _abstractTestModule, _testResolver, _buildRegistry, _hasEmberVersion, _legacyOverrides, _testModuleForComponent) { - 'use strict'; - - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var ACTION_KEY = undefined; - if (_hasEmberVersion['default'](2, 0)) { - ACTION_KEY = 'actions'; - } else { - ACTION_KEY = '_actions'; - } - - var isPreGlimmer = !_hasEmberVersion['default'](1, 13); - - var _default = (function (_AbstractTestModule) { - _inherits(_default, _AbstractTestModule); - - function _default() { - _classCallCheck(this, _default); - - _AbstractTestModule.apply(this, arguments); - this.resolver = this.callbacks.resolver || _testResolver.getResolver(); - } - - _default.prototype.initSetupSteps = function initSetupSteps() { - this.setupSteps = []; - this.contextualizedSetupSteps = []; - - if (this.callbacks.beforeSetup) { - this.setupSteps.push(this.callbacks.beforeSetup); - delete this.callbacks.beforeSetup; - } - - this.setupSteps.push(this.setupContainer); - this.setupSteps.push(this.setupContext); - this.setupSteps.push(this.setupTestElements); - this.setupSteps.push(this.setupAJAXListeners); - this.setupSteps.push(this.setupComponentIntegrationTest); - - if (_ember['default'].View && _ember['default'].View.views) { - this.setupSteps.push(this._aliasViewRegistry); - } - - if (this.callbacks.setup) { - this.contextualizedSetupSteps.push(this.callbacks.setup); - delete this.callbacks.setup; - } - }; - - _default.prototype.initTeardownSteps = function initTeardownSteps() { - this.teardownSteps = []; - this.contextualizedTeardownSteps = []; - - if (this.callbacks.teardown) { - this.contextualizedTeardownSteps.push(this.callbacks.teardown); - delete this.callbacks.teardown; - } - - this.teardownSteps.push(this.teardownContainer); - this.teardownSteps.push(this.teardownContext); - this.teardownSteps.push(this.teardownAJAXListeners); - this.teardownSteps.push(this.teardownComponent); - - if (_ember['default'].View && _ember['default'].View.views) { - this.teardownSteps.push(this._resetViewRegistry); - } - - this.teardownSteps.push(this.teardownTestElements); - - if (this.callbacks.afterTeardown) { - this.teardownSteps.push(this.callbacks.afterTeardown); - delete this.callbacks.afterTeardown; - } - }; - - _default.prototype.setupContainer = function setupContainer() { - var resolver = this.resolver; - var items = _buildRegistry['default'](resolver); - - this.container = items.container; - this.registry = items.registry; - - if (_hasEmberVersion['default'](1, 13)) { - var thingToRegisterWith = this.registry || this.container; - var router = resolver.resolve('router:main'); - router = router || _ember['default'].Router.extend(); - thingToRegisterWith.register('router:main', router); - } - }; - - _default.prototype.setupContext = function setupContext() { - var subjectName = this.subjectName; - var container = this.container; - - var factory = function factory() { - return container.lookupFactory(subjectName); - }; - - _AbstractTestModule.prototype.setupContext.call(this, { - container: this.container, - registry: this.registry, - factory: factory, - register: function register() { - var target = this.registry || this.container; - return target.register.apply(target, arguments); - } - }); - - var context = this.context; - - if (_ember['default'].setOwner) { - _ember['default'].setOwner(context, this.container.owner); - } - - if (_ember['default'].inject) { - var keys = (Object.keys || _ember['default'].keys)(_ember['default'].inject); - keys.forEach(function (typeName) { - context.inject[typeName] = function (name, opts) { - var alias = opts && opts.as || name; - _ember['default'].run(function () { - _ember['default'].set(context, alias, context.container.lookup(typeName + ':' + name)); - }); - }; - }); - } - - // only setup the injection if we are running against a version - // of Ember that has `-view-registry:main` (Ember >= 1.12) - if (this.container.lookupFactory('-view-registry:main')) { - (this.registry || this.container).injection('component', '_viewRegistry', '-view-registry:main'); - } - }; - - _default.prototype.setupComponentIntegrationTest = function setupComponentIntegrationTest() { - if (isPreGlimmer) { - return _legacyOverrides.preGlimmerSetupIntegrationForComponent.apply(this, arguments); - } else { - return _testModuleForComponent.setupComponentIntegrationTest.apply(this, arguments); - } - }; - - _default.prototype.teardownComponent = function teardownComponent() { - var component = this.component; - if (component) { - _ember['default'].run(function () { + Ember['default'].run(function() { component.destroy(); }); } - }; + } + }); - _default.prototype.teardownContainer = function teardownContainer() { - var container = this.container; - _ember['default'].run(function () { - container.destroy(); - }); - }; - - // allow arbitrary named factories, like rspec let - - _default.prototype.contextualizeCallbacks = function contextualizeCallbacks() { - var callbacks = this.callbacks; - var context = this.context; - - this.cache = this.cache || {}; - this.cachedCalls = this.cachedCalls || {}; - - var keys = (Object.keys || _ember['default'].keys)(callbacks); - var keysLength = keys.length; - - if (keysLength) { - for (var i = 0; i < keysLength; i++) { - this._contextualizeCallback(context, keys[i], context); - } - } - }; - - _default.prototype._contextualizeCallback = function _contextualizeCallback(context, key, callbackContext) { - var _this = this; - var callbacks = this.callbacks; - var factory = context.factory; - - context[key] = function (options) { - if (_this.cachedCalls[key]) { - return _this.cache[key]; - } - - var result = callbacks[key].call(callbackContext, options, factory()); - - _this.cache[key] = result; - _this.cachedCalls[key] = true; - - return result; - }; - }; - - _default.prototype._aliasViewRegistry = function _aliasViewRegistry() { - this._originalGlobalViewRegistry = _ember['default'].View.views; - var viewRegistry = this.container.lookup('-view-registry:main'); - - if (viewRegistry) { - _ember['default'].View.views = viewRegistry; - } - }; - - _default.prototype._resetViewRegistry = function _resetViewRegistry() { - _ember['default'].View.views = this._originalGlobalViewRegistry; - }; - - return _default; - })(_abstractTestModule['default']); - - exports['default'] = _default; }); -define('ember-test-helpers/test-module-for-model', ['exports', './test-module', 'ember'], function (exports, _testModule, _ember) { - /* global DS, require, requirejs */ // added here to prevent an import from erroring when ED is not present +define('ember-test-helpers/test-module-for-model', ['exports', 'ember-test-helpers/test-module', 'ember'], function (exports, TestModule, Ember) { 'use strict'; - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var _default = (function (_TestModule) { - _inherits(_default, _TestModule); - - function _default(modelName, description, callbacks) { - _classCallCheck(this, _default); - - _TestModule.call(this, 'model:' + modelName, description, callbacks); - + exports['default'] = TestModule['default'].extend({ + init: function(modelName, description, callbacks) { this.modelName = modelName; - this.setupSteps.push(this.setupModel); - } + this._super.call(this, 'model:' + modelName, description, callbacks); - _default.prototype.setupModel = function setupModel() { + this.setupSteps.push(this.setupModel); + }, + + setupModel: function() { var container = this.container; var defaultSubject = this.defaultSubject; var callbacks = this.callbacks; @@ -1316,57 +713,38 @@ define('ember-test-helpers/test-module-for-model', ['exports', './test-module', var adapterFactory = container.lookupFactory('adapter:application'); if (!adapterFactory) { - if (requirejs.entries['ember-data/adapters/json-api']) { - adapterFactory = require('ember-data/adapters/json-api')['default']; - } - - // when ember-data/adapters/json-api is provided via ember-cli shims - // using Ember Data 1.x the actual JSONAPIAdapter isn't found, but the - // above require statement returns a bizzaro object with only a `default` - // property (circular reference actually) - if (!adapterFactory || !adapterFactory.create) { - adapterFactory = DS.JSONAPIAdapter || DS.FixtureAdapter; - } + adapterFactory = DS.JSONAPIAdapter || DS.FixtureAdapter; var thingToRegisterWith = this.registry || this.container; thingToRegisterWith.register('adapter:application', adapterFactory); } - callbacks.store = function () { + callbacks.store = function(){ var container = this.container; - return container.lookup('service:store') || container.lookup('store:main'); + var store = container.lookup('service:store') || container.lookup('store:main'); + return store; }; if (callbacks.subject === defaultSubject) { - callbacks.subject = function (options) { + callbacks.subject = function(options) { var container = this.container; - return _ember['default'].run(function () { + return Ember['default'].run(function() { var store = container.lookup('service:store') || container.lookup('store:main'); return store.createRecord(modelName, options); }); }; } - }; + } + }); - return _default; - })(_testModule['default']); - - exports['default'] = _default; }); -define('ember-test-helpers/test-module', ['exports', 'ember', './abstract-test-module', './test-resolver', './build-registry', './has-ember-version'], function (exports, _ember, _abstractTestModule, _testResolver, _buildRegistry, _hasEmberVersion) { +define('ember-test-helpers/test-module', ['exports', 'ember', 'ember-test-helpers/test-context', 'klassy', 'ember-test-helpers/test-resolver', 'ember-test-helpers/build-registry', 'ember-test-helpers/has-ember-version', 'ember-test-helpers/wait'], function (exports, Ember, test_context, klassy, test_resolver, buildRegistry, hasEmberVersion, wait) { + 'use strict'; - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - - var _default = (function (_AbstractTestModule) { - _inherits(_default, _AbstractTestModule); - - function _default(subjectName, description, callbacks) { - _classCallCheck(this, _default); - + exports['default'] = klassy.Klass.extend({ + init: function(subjectName, description, callbacks) { // Allow `description` to be omitted, in which case it should // default to `subjectName` if (!callbacks && typeof description === 'object') { @@ -1374,50 +752,53 @@ define('ember-test-helpers/test-module', ['exports', 'ember', './abstract-test-m description = subjectName; } - _AbstractTestModule.call(this, description || subjectName, callbacks); - this.subjectName = subjectName; this.description = description || subjectName; - this.resolver = this.callbacks.resolver || _testResolver.getResolver(); + this.name = description || subjectName; + this.callbacks = callbacks || {}; if (this.callbacks.integration && this.callbacks.needs) { throw new Error("cannot declare 'integration: true' and 'needs' in the same module"); } if (this.callbacks.integration) { - this.initIntegration(callbacks); + if (this.isComponentTestModule) { + this.isLegacy = (callbacks.integration === 'legacy'); + this.isIntegration = (callbacks.integration !== 'legacy'); + } else { + if (callbacks.integration === 'legacy') { + throw new Error('`integration: \'legacy\'` is only valid for component tests.'); + } + this.isIntegration = true; + } + delete callbacks.integration; } this.initSubject(); this.initNeeds(); - } + this.initSetupSteps(); + this.initTeardownSteps(); + }, - _default.prototype.initIntegration = function initIntegration(options) { - if (options.integration === 'legacy') { - throw new Error('`integration: \'legacy\'` is only valid for component tests.'); - } - this.isIntegration = true; - }; - - _default.prototype.initSubject = function initSubject() { + initSubject: function() { this.callbacks.subject = this.callbacks.subject || this.defaultSubject; - }; + }, - _default.prototype.initNeeds = function initNeeds() { + initNeeds: function() { this.needs = [this.subjectName]; if (this.callbacks.needs) { this.needs = this.needs.concat(this.callbacks.needs); delete this.callbacks.needs; } - }; + }, - _default.prototype.initSetupSteps = function initSetupSteps() { + initSetupSteps: function() { this.setupSteps = []; this.contextualizedSetupSteps = []; if (this.callbacks.beforeSetup) { - this.setupSteps.push(this.callbacks.beforeSetup); + this.setupSteps.push( this.callbacks.beforeSetup ); delete this.callbacks.beforeSetup; } @@ -1427,17 +808,17 @@ define('ember-test-helpers/test-module', ['exports', 'ember', './abstract-test-m this.setupSteps.push(this.setupAJAXListeners); if (this.callbacks.setup) { - this.contextualizedSetupSteps.push(this.callbacks.setup); + this.contextualizedSetupSteps.push( this.callbacks.setup ); delete this.callbacks.setup; } - }; + }, - _default.prototype.initTeardownSteps = function initTeardownSteps() { + initTeardownSteps: function() { this.teardownSteps = []; this.contextualizedTeardownSteps = []; if (this.callbacks.teardown) { - this.contextualizedTeardownSteps.push(this.callbacks.teardown); + this.contextualizedTeardownSteps.push( this.callbacks.teardown ); delete this.callbacks.teardown; } @@ -1448,176 +829,203 @@ define('ember-test-helpers/test-module', ['exports', 'ember', './abstract-test-m this.teardownSteps.push(this.teardownAJAXListeners); if (this.callbacks.afterTeardown) { - this.teardownSteps.push(this.callbacks.afterTeardown); + this.teardownSteps.push( this.callbacks.afterTeardown ); delete this.callbacks.afterTeardown; } - }; + }, - _default.prototype.setupContainer = function setupContainer() { + setup: function() { + var self = this; + return self.invokeSteps(self.setupSteps).then(function() { + self.contextualizeCallbacks(); + return self.invokeSteps(self.contextualizedSetupSteps, self.context); + }); + }, + + teardown: function() { + var self = this; + return self.invokeSteps(self.contextualizedTeardownSteps, self.context).then(function() { + return self.invokeSteps(self.teardownSteps); + }).then(function() { + self.cache = null; + self.cachedCalls = null; + }); + }, + + invokeSteps: function(steps, _context) { + var context = _context; + if (!context) { + context = this; + } + steps = steps.slice(); + function nextStep() { + var step = steps.shift(); + if (step) { + // guard against exceptions, for example missing components referenced from needs. + return new Ember['default'].RSVP.Promise(function(ok) { + ok(step.call(context)); + }).then(nextStep); + } else { + return Ember['default'].RSVP.resolve(); + } + } + return nextStep(); + }, + + setupContainer: function() { if (this.isIntegration || this.isLegacy) { this._setupIntegratedContainer(); } else { this._setupIsolatedContainer(); } - }; + }, - _default.prototype.setupContext = function setupContext() { + setupContext: function() { var subjectName = this.subjectName; var container = this.container; - var factory = function factory() { + var factory = function() { return container.lookupFactory(subjectName); }; - _AbstractTestModule.prototype.setupContext.call(this, { - container: this.container, + test_context.setContext({ + container: this.container, registry: this.registry, - factory: factory, - register: function register() { + factory: factory, + dispatcher: null, + register: function() { var target = this.registry || this.container; return target.register.apply(target, arguments); - } + }, + inject: {} }); - if (_ember['default'].setOwner) { - _ember['default'].setOwner(this.context, this.container.owner); + var context = this.context = test_context.getContext(); + + if (Ember['default'].setOwner) { + Ember['default'].setOwner(context, this.container.owner); } - this.setupInject(); - }; - - _default.prototype.setupInject = function setupInject() { - var module = this; - var context = this.context; - - if (_ember['default'].inject) { - var keys = (Object.keys || _ember['default'].keys)(_ember['default'].inject); - - keys.forEach(function (typeName) { - context.inject[typeName] = function (name, opts) { - var alias = opts && opts.as || name; - _ember['default'].run(function () { - _ember['default'].set(context, alias, module.container.lookup(typeName + ':' + name)); - }); + if (Ember['default'].inject) { + var keys = (Object.keys || Ember['default'].keys)(Ember['default'].inject); + keys.forEach(function(typeName) { + context.inject[typeName] = function(name, opts) { + var alias = (opts && opts.as) || name; + Ember['default'].set(context, alias, context.container.lookup(typeName + ':' + name)); }; }); } - }; + }, - _default.prototype.teardownSubject = function teardownSubject() { + setupTestElements: function() { + if (Ember['default'].$('#ember-testing').length === 0) { + Ember['default'].$('
    ').appendTo(document.body); + } + }, + + setupAJAXListeners: function() { + wait._setupAJAXHooks(); + }, + + teardownSubject: function() { var subject = this.cache.subject; if (subject) { - _ember['default'].run(function () { - _ember['default'].tryInvoke(subject, 'destroy'); + Ember['default'].run(function() { + Ember['default'].tryInvoke(subject, 'destroy'); }); } - }; + }, - _default.prototype.teardownContainer = function teardownContainer() { + teardownContainer: function() { var container = this.container; - _ember['default'].run(function () { + Ember['default'].run(function() { container.destroy(); }); - }; + }, - _default.prototype.defaultSubject = function defaultSubject(options, factory) { + teardownContext: function() { + var context = this.context; + this.context = undefined; + test_context.unsetContext(); + + if (context.dispatcher && !context.dispatcher.isDestroyed) { + Ember['default'].run(function() { + context.dispatcher.destroy(); + }); + } + }, + + teardownTestElements: function() { + Ember['default'].$('#ember-testing').empty(); + + // Ember 2.0.0 removed Ember.View as public API, so only do this when + // Ember.View is present + if (Ember['default'].View && Ember['default'].View.views) { + Ember['default'].View.views = {}; + } + }, + + teardownAJAXListeners: function() { + wait._teardownAJAXHooks(); + }, + + defaultSubject: function(options, factory) { return factory.create(options); - }; + }, // allow arbitrary named factories, like rspec let - - _default.prototype.contextualizeCallbacks = function contextualizeCallbacks() { + contextualizeCallbacks: function() { + var _this = this; var callbacks = this.callbacks; - var context = this.context; + var context = this.context; + var factory = context.factory; this.cache = this.cache || {}; this.cachedCalls = this.cachedCalls || {}; - var keys = (Object.keys || _ember['default'].keys)(callbacks); - var keysLength = keys.length; + var keys = (Object.keys || Ember['default'].keys)(callbacks); - if (keysLength) { - var deprecatedContext = this._buildDeprecatedContext(this, context); - for (var i = 0; i < keysLength; i++) { - this._contextualizeCallback(context, keys[i], deprecatedContext); - } + for (var i = 0, l = keys.length; i < l; i++) { + (function(key) { + + context[key] = function(options) { + if (_this.cachedCalls[key]) { return _this.cache[key]; } + + var result = callbacks[key].call(_this, options, factory()); + + _this.cache[key] = result; + _this.cachedCalls[key] = true; + + return result; + }; + + })(keys[i]); } - }; + }, - _default.prototype._contextualizeCallback = function _contextualizeCallback(context, key, callbackContext) { - var _this = this; - var callbacks = this.callbacks; - var factory = context.factory; + _setupContainer: function(isolated) { + var resolver = test_resolver.getResolver(); - context[key] = function (options) { - if (_this.cachedCalls[key]) { - return _this.cache[key]; - } - - var result = callbacks[key].call(callbackContext, options, factory()); - - _this.cache[key] = result; - _this.cachedCalls[key] = true; - - return result; - }; - }; - - /* - Builds a version of the passed in context that contains deprecation warnings - for accessing properties that exist on the module. - */ - - _default.prototype._buildDeprecatedContext = function _buildDeprecatedContext(module, context) { - var deprecatedContext = Object.create(context); - - var keysForDeprecation = Object.keys(module); - - for (var i = 0, l = keysForDeprecation.length; i < l; i++) { - this._proxyDeprecation(module, deprecatedContext, keysForDeprecation[i]); - } - - return deprecatedContext; - }; - - /* - Defines a key on an object to act as a proxy for deprecating the original. - */ - - _default.prototype._proxyDeprecation = function _proxyDeprecation(obj, proxy, key) { - if (typeof proxy[key] === 'undefined') { - Object.defineProperty(proxy, key, { - get: function get() { - _ember['default'].deprecate('Accessing the test module property "' + key + '" from a callback is deprecated.', false, { id: 'ember-test-helpers.test-module.callback-context', until: '0.6.0' }); - return obj[key]; - } - }); - } - }; - - _default.prototype._setupContainer = function _setupContainer(isolated) { - var resolver = this.resolver; - - var items = _buildRegistry['default'](!isolated ? resolver : Object.create(resolver, { + var items = buildRegistry['default'](!isolated ? resolver : Object.create(resolver, { resolve: { - value: function value() {} + value: function() {} } })); this.container = items.container; this.registry = items.registry; - if (_hasEmberVersion['default'](1, 13)) { + if (hasEmberVersion['default'](1, 13)) { var thingToRegisterWith = this.registry || this.container; var router = resolver.resolve('router:main'); - router = router || _ember['default'].Router.extend(); + router = router || Ember['default'].Router.extend(); thingToRegisterWith.register('router:main', router); } - }; + }, - _default.prototype._setupIsolatedContainer = function _setupIsolatedContainer() { - var resolver = this.resolver; + _setupIsolatedContainer: function() { + var resolver = test_resolver.getResolver(); this._setupContainer(true); var thingToRegisterWith = this.registry || this.container; @@ -1629,24 +1037,24 @@ define('ember-test-helpers/test-module', ['exports', 'ember', './abstract-test-m } if (!this.registry) { - this.container.resolver = function () {}; + this.container.resolver = function() {}; } - }; + }, - _default.prototype._setupIntegratedContainer = function _setupIntegratedContainer() { + _setupIntegratedContainer: function() { this._setupContainer(); - }; + } - return _default; - })(_abstractTestModule['default']); + }); - exports['default'] = _default; }); define('ember-test-helpers/test-resolver', ['exports'], function (exports) { + 'use strict'; exports.setResolver = setResolver; exports.getResolver = getResolver; + var __resolver__; function setResolver(resolver) { @@ -1654,23 +1062,17 @@ define('ember-test-helpers/test-resolver', ['exports'], function (exports) { } function getResolver() { - if (__resolver__ == null) { - throw new Error('you must set a resolver with `testResolver.set(resolver)`'); - } - + if (__resolver__ == null) throw new Error('you must set a resolver with `testResolver.set(resolver)`'); return __resolver__; } + }); -define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, _ember) { - /* globals self */ +define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, Ember) { 'use strict'; exports._teardownAJAXHooks = _teardownAJAXHooks; exports._setupAJAXHooks = _setupAJAXHooks; - exports['default'] = wait; - - var jQuery = _ember['default'].$; var requests; function incrementAjaxPendingRequests(_, xhr) { @@ -1678,7 +1080,7 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, _embe } function decrementAjaxPendingRequests(_, xhr) { - for (var i = 0; i < requests.length; i++) { + for (var i = 0;i < requests.length;i++) { if (xhr === requests[i]) { requests.splice(i, 1); } @@ -1686,10 +1088,6 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, _embe } function _teardownAJAXHooks() { - if (!jQuery) { - return; - } - jQuery(document).off('ajaxSend', incrementAjaxPendingRequests); jQuery(document).off('ajaxComplete', decrementAjaxPendingRequests); } @@ -1697,44 +1095,18 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, _embe function _setupAJAXHooks() { requests = []; - if (!jQuery) { - return; - } - jQuery(document).on('ajaxSend', incrementAjaxPendingRequests); jQuery(document).on('ajaxComplete', decrementAjaxPendingRequests); } - var _internalCheckWaiters; - if (_ember['default'].__loader.registry['ember-testing/test/waiters']) { - _internalCheckWaiters = _ember['default'].__loader.require('ember-testing/test/waiters').checkWaiters; - } - - function checkWaiters() { - if (_internalCheckWaiters) { - return _internalCheckWaiters(); - } else if (_ember['default'].Test.waiters) { - if (_ember['default'].Test.waiters.any(function (_ref) { - var context = _ref[0]; - var callback = _ref[1]; - return !callback.call(context); - })) { - return true; - } - } - - return false; - } - function wait(_options) { var options = _options || {}; var waitForTimers = options.hasOwnProperty('waitForTimers') ? options.waitForTimers : true; var waitForAJAX = options.hasOwnProperty('waitForAJAX') ? options.waitForAJAX : true; - var waitForWaiters = options.hasOwnProperty('waitForWaiters') ? options.waitForWaiters : true; - return new _ember['default'].RSVP.Promise(function (resolve) { - var watcher = self.setInterval(function () { - if (waitForTimers && (_ember['default'].run.hasScheduledTimers() || _ember['default'].run.currentRunLoop)) { + return new Ember['default'].RSVP.Promise(function(resolve) { + var watcher = self.setInterval(function() { + if (waitForTimers && (Ember['default'].run.hasScheduledTimers() || Ember['default'].run.currentRunLoop)) { return; } @@ -1742,34 +1114,188 @@ define('ember-test-helpers/wait', ['exports', 'ember'], function (exports, _embe return; } - if (waitForWaiters && checkWaiters()) { - return; - } - // Stop polling self.clearInterval(watcher); // Synchronously resolve the promise - _ember['default'].run(null, resolve); + Ember['default'].run(null, resolve); }, 10); }); } + exports['default'] = wait; + }); -define("qunit", ["exports"], function (exports) { - /* globals QUnit */ +define('klassy', ['exports'], function (exports) { - "use strict"; + 'use strict'; - var _module = QUnit.module; - exports.module = _module; - var test = QUnit.test; - exports.test = test; - var skip = QUnit.skip; - exports.skip = skip; - var only = QUnit.only; + /** + Extend a class with the properties and methods of one or more other classes. + + When a method is replaced with another method, it will be wrapped in a + function that makes the replaced method accessible via `this._super`. + + @method extendClass + @param {Object} destination The class to merge into + @param {Object} source One or more source classes + */ + var extendClass = function(destination) { + var sources = Array.prototype.slice.call(arguments, 1); + var source; + + for (var i = 0, l = sources.length; i < l; i++) { + source = sources[i]; + + for (var p in source) { + if (source.hasOwnProperty(p) && + destination[p] && + typeof destination[p] === 'function' && + typeof source[p] === 'function') { + + /* jshint loopfunc:true */ + destination[p] = + (function(destinationFn, sourceFn) { + var wrapper = function() { + var prevSuper = this._super; + this._super = destinationFn; + + var ret = sourceFn.apply(this, arguments); + + this._super = prevSuper; + + return ret; + }; + wrapper.wrappedFunction = sourceFn; + return wrapper; + })(destination[p], source[p]); + + } else { + destination[p] = source[p]; + } + } + } + }; + + // `subclassing` is a state flag used by `defineClass` to track when a class is + // being subclassed. It allows constructors to avoid calling `init`, which can + // be expensive and cause undesirable side effects. + var subclassing = false; + + /** + Define a new class with the properties and methods of one or more other classes. + + The new class can be based on a `SuperClass`, which will be inserted into its + prototype chain. + + Furthermore, one or more mixins (object that contain properties and/or methods) + may be specified, which will be applied in order. When a method is replaced + with another method, it will be wrapped in a function that makes the previous + method accessible via `this._super`. + + @method defineClass + @param {Object} SuperClass A base class to extend. If `mixins` are to be included + without a `SuperClass`, pass `null` for SuperClass. + @param {Object} mixins One or more objects that contain properties and methods + to apply to the new class. + */ + var defineClass = function(SuperClass) { + var Klass = function() { + if (!subclassing && this.init) { + this.init.apply(this, arguments); + } + }; + + if (SuperClass) { + subclassing = true; + Klass.prototype = new SuperClass(); + subclassing = false; + } + + if (arguments.length > 1) { + var extendArgs = Array.prototype.slice.call(arguments, 1); + extendArgs.unshift(Klass.prototype); + extendClass.apply(Klass.prototype, extendArgs); + } + + Klass.constructor = Klass; + + Klass.extend = function() { + var args = Array.prototype.slice.call(arguments, 0); + args.unshift(Klass); + return defineClass.apply(Klass, args); + }; + + return Klass; + }; + + /** + A base class that can be extended. + + @example + + ```javascript + var CelestialObject = Klass.extend({ + init: function(name) { + this._super(); + this.name = name; + this.isCelestialObject = true; + }, + greeting: function() { + return 'Hello from ' + this.name; + } + }); + + var Planet = CelestialObject.extend({ + init: function(name) { + this._super.apply(this, arguments); + this.isPlanet = true; + }, + greeting: function() { + return this._super() + '!'; + }, + }); + + var earth = new Planet('Earth'); + + console.log(earth instanceof Klass); // true + console.log(earth instanceof CelestialObject); // true + console.log(earth instanceof Planet); // true + + console.log(earth.isCelestialObject); // true + console.log(earth.isPlanet); // true + + console.log(earth.greeting()); // 'Hello from Earth!' + ``` + + @class Klass + */ + var Klass = defineClass(null, { + init: function() {} + }); + + exports.Klass = Klass; + exports.defineClass = defineClass; + exports.extendClass = extendClass; + +}); +define('qunit', ['exports'], function (exports) { + + 'use strict'; + + /* globals test:true */ + + var module = QUnit.module; + var test = QUnit.test; + var skip = QUnit.skip; + var only = QUnit.only; + + exports['default'] = QUnit; + + exports.module = module; + exports.test = test; + exports.skip = skip; + exports.only = only; - exports.only = only; - exports["default"] = QUnit; }); define("ember", ["exports"], function(__exports__) { __exports__["default"] = window.Ember;