Final set of backwards compatible fixes for Ember 1.13

This commit is contained in:
Robin Ward 2016-10-28 15:51:19 -04:00
parent 8c9d390cac
commit a319cfe77a
26 changed files with 103 additions and 175 deletions

View File

@ -81,7 +81,11 @@ export default Ember.Component.extend(bufferedRender({
}
this.set('value', val);
});
$elem.trigger('change');
Ember.run.scheduleOnce('afterRender', this, this._triggerChange);
},
_triggerChange() {
this.$().trigger('change');
},
@on('willDestroyElement')

View File

@ -1,14 +1,11 @@
import { get } from 'discourse-common/lib/raw-handlebars';
function fixArgs(args) {
return (args.length > 1) ? args[0].concat(args[args.length-1]) : args;
}
// `Ember.Helper` is only available in versions after 1.12
export function htmlHelper(fn) {
if (Ember.Helper) {
return Ember.Helper.helper(function(...args) {
return new Handlebars.SafeString(fn.apply(this, fixArgs(args)) || '');
args = (args.length > 1) ? args[0].concat({ hash: args[args.length-1] }) : args;
return new Handlebars.SafeString(fn.apply(this, args) || '');
});
} else {
return Ember.Handlebars.makeBoundHelper(function() {

View File

@ -0,0 +1,27 @@
import computed from 'ember-addons/ember-computed-decorators';
export default Ember.Component.extend({
tagName: 'button',
attributeBindings: ['style', 'title'],
classNameBindings: [':colorpicker', 'isUsed:used-color:unused-color'],
@computed('color', 'usedColors')
isUsed(color, usedColors) {
return (usedColors || []).indexOf(color.toUpperCase()) >= 0;
},
@computed('isUsed')
title(isUsed) {
return isUsed ? I18n.t("category.already_used") : null;
},
@computed('color')
style(color) {
return `background-color: #${color};`.htmlSafe();
},
click(e) {
e.preventDefault();
this.sendAction('selectColor', this.get('color'));
}
});

View File

@ -1,30 +1,9 @@
import DiscourseContainerView from 'discourse/views/container';
export default DiscourseContainerView.extend({
export default Ember.Component.extend({
classNames: 'colors-container',
_createButtons: function() {
var colors = this.get('colors'),
isUsed, usedColors = this.get('usedColors') || [];
if (!colors) return;
var self = this;
colors.forEach(function(color) {
isUsed = usedColors.indexOf(color.toUpperCase()) >= 0;
self.attachViewWithArgs({
tagName: 'button',
attributeBindings: ['style', 'title'],
classNames: ['colorpicker'].concat( isUsed ? ['used-color'] : ['unused-color'] ),
style: ('background-color: #' + color + ';').htmlSafe(),
title: isUsed ? I18n.t("category.already_used") : null,
click: function() {
self.set("value", color);
return false;
}
});
});
}.on('init')
actions: {
selectColor(color) {
this.set('value', color);
}
}
});

View File

@ -15,12 +15,12 @@ export default Ember.Component.extend({
didInsertElement() {
this._super();
this.reset();
this.appEvents.on('composer:typed-reply', this, this._typedReply);
this.appEvents.on('composer:opened', this, this._findMessages);
this.appEvents.on('composer:find-similar', this, this._findSimilar);
this.appEvents.on('composer-messages:close', this, this._closeTop);
this.appEvents.on('composer-messages:create', this, this._create);
Ember.run.scheduleOnce('afterRender', this, this.reset);
},
willDestroyElement() {

View File

@ -201,18 +201,23 @@ export default Ember.Component.extend({
return null;
},
@on('didInsertElement')
_startUp() {
_readyNow() {
this.set('ready', true);
},
didInsertElement() {
this._super();
const container = this.get('container'),
$editorInput = this.$('.d-editor-input');
this._applyEmojiAutocomplete(container, $editorInput);
this._applyCategoryHashtagAutocomplete(container, $editorInput);
this.set('ready', true);
Ember.run.scheduleOnce('afterRender', this, this._readyNow);
const mouseTrap = Mousetrap(this.$('.d-editor-input')[0]);
const shortcuts = this.get('toolbar.shortcuts');
Object.keys(shortcuts).forEach(sc => {
const button = shortcuts[sc];
@ -232,7 +237,6 @@ export default Ember.Component.extend({
this.appEvents.on('composer:insert-text', text => this._addText(this._getSelected(), text));
this.appEvents.on('composer:replace-text', (oldVal, newVal) => this._replaceText(oldVal, newVal));
this._mouseTrap = mouseTrap;
},
@ -263,11 +267,10 @@ export default Ember.Component.extend({
markdownOptions.siteSettings = this.siteSettings;
this.set('preview', cook(value));
Ember.run.scheduleOnce('afterRender', () => {
Ember.run.next(() => {
if (this._state !== "inDOM") { return; }
const $preview = this.$('.d-editor-preview');
if ($preview.length === 0) return;
this.sendAction('previewUpdated', $preview);
});
},

View File

@ -14,9 +14,14 @@ export default Em.Component.extend({
return I18n.t('category.' + this.get('tab').replace('-', '_'));
}.property('tab'),
didInsertElement() {
this._super();
Ember.run.scheduleOnce('afterRender', this, this._addToCollection);
},
_addToCollection: function() {
this.get('panels').addObject(this.get('tabClassName'));
}.on('didInsertElement'),
},
actions: {
select: function() {

View File

@ -6,7 +6,7 @@ export default Em.Component.extend(UploadMixin, {
@computed('imageUrl')
backgroundStyle(imageUrl) {
if (Em.isNone(imageUrl)) { return; }
if (Em.isNone(imageUrl)) { return "".htmlSafe(); }
return `background-image: url(${imageUrl})`.htmlSafe();
},

View File

@ -5,6 +5,8 @@ export default Ember.Component.extend({
info: Em.Object.create(),
_checkSize() {
if (!this.element || this.isDestroying || this.isDestroyed) { return; }
let info = this.get('info');
if (info.get('topicProgressExpanded')) {
@ -110,7 +112,7 @@ export default Ember.Component.extend({
$('#reply-control').on('div-resized.discourse-topic-navigation', () => this._checkSize());
}
this._checkSize();
Ember.run.scheduleOnce('afterRender', this, this._checkSize);
},
willDestroyElement() {

View File

@ -1,8 +1,12 @@
import { registerHelper } from 'discourse-common/lib/helpers';
// Note: Later versions of ember include `hash`
export default function hashHelper(params) {
registerHelper('as-hash', function(_, params) {
if (Ember.Helper) { return params; }
const hash = {};
Object.keys(params.hash).forEach(k => {
hash[k] = params.data.view.getStream(params.hash[k]).value();
});
return hash;
}
});

View File

@ -144,21 +144,24 @@ registerHelper('plugin-outlet', function([connectionName], hash, options, env) {
// just shove it in.
const viewClass = (childViews.length > 1) ? Ember.ContainerView : childViews[0];
const newHash = $.extend({}, viewInjections(env.data.view.container));
if (hash.tagName) { newHash.tagName = hash.tagName; }
// TODO: Figure out how to do this without a container view
if (env) {
const newHash = $.extend({}, viewInjections(env.data.view.container));
if (hash.tagName) { newHash.tagName = hash.tagName; }
// we don't need the default template since we have a connector
delete options.fn;
delete options.template;
env.helpers.view.helperFunction.call(this, [viewClass], newHash, options, env);
// we don't need the default template since we have a connector
delete options.fn;
delete options.template;
env.helpers.view.helperFunction.call(this, [viewClass], newHash, options, env);
const cvs = env.data.view._childViews;
if (childViews.length > 1 && cvs && cvs.length) {
const inserted = cvs[cvs.length-1];
if (inserted) {
childViews.forEach(function(cv) {
inserted.pushObject(cv.create());
});
const cvs = env.data.view._childViews;
if (childViews.length > 1 && cvs && cvs.length) {
const inserted = cvs[cvs.length-1];
if (inserted) {
childViews.forEach(function(cv) {
inserted.pushObject(cv.create());
});
}
}
}
}

View File

@ -9,7 +9,7 @@ export default Post.extend({
}
}.on("init"),
presentName: Em.computed.any('name', 'username'),
presentName: Ember.computed.or('name', 'username'),
sameUser: function() {
return this.get("username") === Discourse.User.currentProp("username");

View File

@ -76,9 +76,9 @@ const UserAction = RestModel.extend({
return targetUsername === Discourse.User.currentProp('username');
},
presentName: Em.computed.any('name', 'username'),
targetDisplayName: Em.computed.any('target_name', 'target_username'),
actingDisplayName: Em.computed.any('acting_name', 'acting_username'),
presentName: Ember.computed.or('name', 'username'),
targetDisplayName: Ember.computed.or('target_name', 'target_username'),
actingDisplayName: Ember.computed.or('acting_name', 'acting_username'),
targetUserUrl: url('target_username', '/users/%@'),
@computed("username")

View File

@ -64,7 +64,7 @@ const User = RestModel.extend({
@computed('profile_background')
profileBackground(bgUrl) {
if (Em.isEmpty(bgUrl) || !Discourse.SiteSettings.allow_profile_backgrounds) { return; }
if (Em.isEmpty(bgUrl) || !Discourse.SiteSettings.allow_profile_backgrounds) { return "".htmlSafe(); }
return ('background-image: url(' + Discourse.getURLWithCDN(bgUrl) + ')').htmlSafe();
},
@ -322,7 +322,7 @@ const User = RestModel.extend({
@computed("stats.@each.isPM")
statsExcludingPms() {
if (Ember.isEmpty(this.get('stats'))) return [];
return this.get('stats').rejectProperty('isPM');
return this.get('stats').rejectBy('isPM');
},
findDetails(options) {
@ -530,7 +530,7 @@ User.reopenClass(Singleton, {
});
const result = Em.A();
result.pushObjects(stats.rejectProperty('isResponse'));
result.pushObjects(stats.rejectBy('isResponse'));
let insertAt = 0;
result.forEach((item, index) => {

View File

@ -0,0 +1 @@
{{#each colors as |c|}}{{color-picker-choice color=c usedColors=usedColors selectColor="selectColor"}}{{/each}}

View File

@ -1,5 +1,5 @@
{{#each model.categories as |c|}}
<div class='category-list-item category' style="border-color: #{{unbound c.color}}">
<div class='category-list-item category' style={{border-color c.color}}>
<table class='topic-list'>
<tr>
<th class="main-link">

View File

@ -1,16 +0,0 @@
export default Ember.ContainerView.extend({
attachViewWithArgs(viewArgs, viewClass) {
if (typeof viewClass === "string") {
viewClass = this.container.lookupFactory("view:" + viewClass) ||
this.container.lookupFactory("component:" + viewClass);
}
if (!viewClass) { viewClass = Ember.View.extend(); }
this.pushObject(this.createChildView(viewClass, viewArgs));
},
attachViewClass(viewClass) {
this.attachViewWithArgs(null, viewClass);
}
});

View File

@ -7,10 +7,12 @@ export default Ember.View.extend({
_setupModal() {
$('#modal-alert').hide();
$('#discourse-modal').modal('show');
Ember.run.scheduleOnce('afterRender', this, this._afterFirstRender);
},
// Focus on first element
_afterFirstRender() {
if (!this.site.mobileView && this.get('focusInput')) {
Em.run.schedule('afterRender', () => this.$('input:first').focus());
this.$('input:first').focus();
}
const title = this.get('title');

View File

@ -1,3 +1,4 @@
import ScrollTop from 'discourse/mixins/scroll-top';
export default Ember.View.extend(ScrollTop);
export default Ember.View.extend(ScrollTop, {
});

View File

@ -71,7 +71,7 @@ export default createWidget('search-menu', {
const contextEnabled = searchData.contextEnabled;
const ctx = contextEnabled ? this.searchContext() : null;
const type = Ember.get(ctx, 'type');
const type = ctx ? Ember.get(ctx, 'type') : null;
if (contextEnabled && type === 'topic') {
return;

View File

@ -57,7 +57,6 @@
//= require ./discourse/models/user-badge
//= require ./discourse/controllers/discovery-sortable
//= require ./discourse/controllers/navigation/default
//= require ./discourse/views/container
//= require ./discourse/views/modal-body
//= require ./discourse/views/flag
//= require ./discourse/components/edit-category-panel

View File

@ -4,7 +4,7 @@ export function componentTest(name, opts) {
opts = opts || {};
test(name, function(assert) {
initializer.initialize();
initializer.initialize(this.container, this.registry);
if (opts.setup) {
opts.setup.call(this);

View File

@ -8,7 +8,7 @@ export default function() {
Ember.run(() => app = Wizard.create({ rootElement: '#ember-testing' }));
if (!started) {
initializer.initialize();
initializer.initialize(app.__container__, app.registry);
app.start();
started = true;
}

View File

@ -9,7 +9,7 @@ export default Ember.Application.extend({
if (/\/initializers\//.test(key)) {
const module = require(key, null, null, true);
if (!module) { throw new Error(key + ' must export an initializer.'); }
this.instanceInitializer(module.default);
this.initializer(module.default);
}
});
}

View File

@ -21,7 +21,7 @@ export default function(name, opts) {
this.siteSettings = Discourse.SiteSettings;
autoLoadModules();
autoLoadModules(this.container, this.registry);
const store = createStore();
if (!opts.anonymous) {

View File

@ -1,83 +0,0 @@
var SomeViewClass = Ember.View.extend();
function containerHasOnlyOneChild(containerView, klass) {
equal(containerView.get('childViews').length, 1, "container has no other children than the one created by method");
ok(containerView.objectAt(0) instanceof klass, "container's child created by method is an instance of a correct class");
}
function containerHasTwoChildren(containerView, klass1, klass2) {
equal(containerView.get('childViews').length, 2, "container has both already existing and newly created children");
ok(containerView.objectAt(0) instanceof klass1, "already existing child's class is correct");
ok(containerView.objectAt(1) instanceof klass2, "newly created child's class is correct");
}
function childHasProperty(containerView, name) {
equal(containerView.objectAt(0).get(name), name, "method passes properties to the container's child it creates");
}
moduleFor("view:container");
test("attachViewWithArgs: creates a view of a given class with given properties and appends it to the container", function() {
var containerView = this.subject();
containerView.attachViewWithArgs({foo: "foo"}, SomeViewClass);
containerHasOnlyOneChild(containerView, SomeViewClass);
childHasProperty(containerView, "foo");
});
test("attachViewWithArgs: creates a view of a given class without any properties and appends it to the container", function() {
var containerView = this.subject();
containerView.attachViewWithArgs(null, SomeViewClass);
containerHasOnlyOneChild(containerView, SomeViewClass);
});
test("attachViewWithArgs: creates a view without class specified (Ember.View is used by default) with given properties and appends it to the container", function() {
var containerView = this.subject();
containerView.attachViewWithArgs({foo: "foo"});
containerHasOnlyOneChild(containerView, Ember.View);
childHasProperty(containerView, "foo");
});
test("attachViewWithArgs: creates a view without class specified (Ember.View is used by default) without any properties and appends it to the container", function() {
var containerView = this.subject();
containerView.attachViewWithArgs();
containerHasOnlyOneChild(containerView, Ember.View);
});
test("attachViewWithArgs: appends a view to a container already containing other views", function() {
var AlreadyContainedViewClass = Ember.View.extend();
var alreadyContainedView = AlreadyContainedViewClass.create();
var containerView = this.subject();
containerView.pushObject(alreadyContainedView);
containerView.attachViewWithArgs(null, SomeViewClass);
containerHasTwoChildren(containerView, AlreadyContainedViewClass, SomeViewClass);
});
test("attachViewClass: creates a view of a given class without any properties and appends it to the container", function() {
var containerView = this.subject();
containerView.attachViewClass(SomeViewClass);
containerHasOnlyOneChild(containerView, SomeViewClass);
});
test("attachViewClass: creates a view without class specified (Ember.View is used by default) without any properties and appends it to the container", function() {
var containerView = this.subject();
containerView.attachViewClass();
containerHasOnlyOneChild(containerView, Ember.View);
});
test("attachViewClass: appends a view to a container already containing other views", function() {
var AlreadyContainedViewClass = Ember.View.extend();
var alreadyContainedView = AlreadyContainedViewClass.create();
var containerView = this.subject();
containerView.pushObject(alreadyContainedView);
containerView.attachViewClass(SomeViewClass);
containerHasTwoChildren(containerView, AlreadyContainedViewClass, SomeViewClass);
});