diff --git a/app/assets/javascripts/discourse/views/post_menu_view.js b/app/assets/javascripts/discourse/views/post_menu_view.js index 0cbd8c27a..5c438b377 100644 --- a/app/assets/javascripts/discourse/views/post_menu_view.js +++ b/app/assets/javascripts/discourse/views/post_menu_view.js @@ -13,13 +13,12 @@ Discourse.PostMenuView = Discourse.View.extend({ shouldRerender: Discourse.View.renderIfChanged( 'post.deleted_at', 'post.flagsAvailable.@each', - 'post.url', - 'post.bookmarked', 'post.reply_count', 'post.showRepliesBelow', 'post.can_delete', - 'post.read', - 'post.topic.last_read_post_number', + 'bookmarkClass', + 'bookmarkTooltip', + 'shareUrl', 'post.topic.deleted_at'), render: function(buffer) { @@ -163,7 +162,7 @@ Discourse.PostMenuView = Discourse.View.extend({ renderShare: function(post, buffer) { buffer.push("<button title=\"" + (I18n.t("post.controls.share")) + - "\" data-share-url=\"" + (post.get('shareUrl')) + "\" class='share'><i class=\"icon-link\"></i></button>"); + "\" data-share-url=\"" + post.get('shareUrl') + "\" class='share'><i class=\"icon-link\"></i></button>"); }, // Reply button diff --git a/app/assets/javascripts/discourse/views/topic_view.js b/app/assets/javascripts/discourse/views/topic_view.js index 14f084683..90da10b87 100644 --- a/app/assets/javascripts/discourse/views/topic_view.js +++ b/app/assets/javascripts/discourse/views/topic_view.js @@ -21,6 +21,10 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, { postStream: Em.computed.alias('controller.postStream'), updateBar: function() { + Em.run.scheduleOnce('afterRender', this, 'updateProgressBar'); + }.observes('controller.streamPercentage'), + + updateProgressBar: function() { var $topicProgress = $('#topic-progress'); if (!$topicProgress.length) return; @@ -30,8 +34,7 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, { $topicProgress.find('.bg') .css("border-right-width", (progressWidth === totalWidth) ? "0px" : "1px") .width(progressWidth); - - }.observes('controller.streamPercentage'), + }, updateTitle: function() { var title = this.get('topic.title'); @@ -79,7 +82,6 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, { if (this.present('controller.enteredAt')) { var topicView = this; Em.run.schedule('afterRender', function() { - topicView.updateBar(); topicView.updatePosition(); }); } @@ -337,7 +339,6 @@ Discourse.TopicView.reopenClass({ // Scroll to a given post, if in the DOM. Returns whether it was in the DOM or not. jumpToPost: function(topicId, postNumber, avoidScrollIfPossible) { Em.run.scheduleOnce('afterRender', function() { - var rows = $('.topic-post.ready'); // Make sure we're looking at the topic we want to scroll to diff --git a/app/assets/javascripts/external/ember-renderspeed.js b/app/assets/javascripts/external/ember-renderspeed.js index 8df4fa4a9..1f3154857 100644 --- a/app/assets/javascripts/external/ember-renderspeed.js +++ b/app/assets/javascripts/external/ember-renderspeed.js @@ -27,7 +27,7 @@ @property description **/ description: function() { - var result = "Rendered "; + var result = ""; if (this.get('payload.template')) { result += "'" + this.get('payload.template') + "' "; } @@ -61,15 +61,15 @@ @method log **/ - log: function() { - if ((!console) || (!console.groupCollapsed)) { return; } + log: function(type) { + if ((typeof console === 'undefined') || (!console.groupCollapsed)) { return; } // We don't care about really fast renders if (this.get('time') < 1) { return; } - console.groupCollapsed(this.get('description')); + console.groupCollapsed(type + ": " + this.get('description')); this.get('children').forEach(function (c) { - c.log(); + c.log(type); }); console.groupEnd(); } @@ -94,7 +94,7 @@ profileNode.set('end', timestamp); if (!this.depth) { - profileNode.log(); + profileNode.log("Render"); } } }); diff --git a/app/assets/javascripts/external_development/ember.js b/app/assets/javascripts/external_development/ember.js index ba60c0b85..2c6fd9add 100755 --- a/app/assets/javascripts/external_development/ember.js +++ b/app/assets/javascripts/external_development/ember.js @@ -1,5 +1,5 @@ -// Version: v1.0.0-pre.2-1804-g79d5a07 -// Last commit: 79d5a07 (2013-07-26 08:48:32 -0700) +// Version: v1.0.0-pre.2-1839-ge87d164 +// Last commit: e87d164 (2013-07-29 18:30:35 -0400) (function() { @@ -156,8 +156,8 @@ Ember.deprecateFunc = function(message, func) { })(); -// Version: v1.0.0-pre.2-1804-g79d5a07 -// Last commit: 79d5a07 (2013-07-26 08:48:32 -0700) +// Version: v1.0.0-pre.2-1839-ge87d164 +// Last commit: e87d164 (2013-07-29 18:30:35 -0400) (function() { @@ -251,10 +251,10 @@ Ember.toString = function() { return "Ember"; }; /** @property VERSION @type String - @default '1.0.0-rc.6' + @default '1.0.0-rc.6.1' @final */ -Ember.VERSION = '1.0.0-rc.6'; +Ember.VERSION = '1.0.0-rc.6.1'; /** Standard environmental variables. You can define these in a global `ENV` @@ -4844,6 +4844,9 @@ define("backburner", run: function(target, method /*, args */) { var ret; + + var t2 = new Date().getTime(); + this.begin(); if (!method) { @@ -4869,6 +4872,15 @@ define("backburner", this.end(); } } + + var diff = new Date().getTime() - t2; + + if ((typeof console !== 'undefined') && console.log && diff > 1) { + console.log("Backburner: " + (new Date() - t2) + "ms"); + } + + + return ret; }, @@ -6136,7 +6148,8 @@ Ember.oneWay = function(obj, to, from) { (function() { /** -@module ember-metal +@module ember +@submodule ember-metal */ var Mixin, REQUIRED, Alias, @@ -6512,38 +6525,6 @@ Mixin.finishPartial = finishPartial; Ember.anyUnprocessedMixins = false; /** - Creates an instance of a class. Accepts either no arguments, or an object - containing values to initialize the newly instantiated object with. - - ```javascript - App.Person = Ember.Object.extend({ - helloWorld: function() { - alert("Hi, my name is " + this.get('name')); - } - }); - - var tom = App.Person.create({ - name: 'Tom Dale' - }); - - tom.helloWorld(); // alerts "Hi, my name is Tom Dale". - ``` - - `create` will call the `init` function if defined during - `Ember.AnyObject.extend` - - If no arguments are passed to `create`, it will not set values to the new - instance during initialization: - - ```javascript - var noName = App.Person.create(); - noName.helloWorld(); // alerts undefined - ``` - - NOTE: For performance reasons, you cannot declare methods or computed - properties during `create`. You should instead declare methods and computed - properties when using `extend`. - @method create @static @param arguments* @@ -9074,7 +9055,6 @@ function iter(key, value) { @class Enumerable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Enumerable = Ember.Mixin.create({ @@ -9550,7 +9530,7 @@ Ember.Enumerable = Ember.Mixin.create({ @method some @param {Function} callback The callback to execute @param {Object} [target] The target object to use - @return {Array} A filtered array. + @return {Boolean} `true` if the passed function returns `true` for any item */ some: function(callback, target) { return !!this.find(function(x, idx, i) { @@ -9565,7 +9545,7 @@ Ember.Enumerable = Ember.Mixin.create({ @method someProperty @param {String} key the property to test @param {String} [value] optional value to test against. - @return {Boolean} `true` + @return {Boolean} `true` if the passed function returns `true` for any item */ someProperty: function(key, value) { return this.some(iter.apply(this, arguments)); @@ -9909,7 +9889,6 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone, map = Ember.Enumera @class Array @namespace Ember - @extends Ember.Mixin @uses Ember.Enumerable @since Ember 0.9.0 */ @@ -10307,7 +10286,6 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot @class Comparable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Comparable = Ember.Mixin.create( /** @scope Ember.Comparable.prototype */{ @@ -10359,7 +10337,6 @@ var get = Ember.get, set = Ember.set; @class Copyable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Copyable = Ember.Mixin.create(/** @scope Ember.Copyable.prototype */ { @@ -10464,7 +10441,6 @@ var get = Ember.get, set = Ember.set; @class Freezable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Freezable = Ember.Mixin.create(/** @scope Ember.Freezable.prototype */ { @@ -10544,7 +10520,6 @@ var forEach = Ember.EnumerableUtils.forEach; @class MutableEnumerable @namespace Ember - @extends Ember.Mixin @uses Ember.Enumerable */ Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable, { @@ -10644,7 +10619,6 @@ var get = Ember.get, set = Ember.set; @class MutableArray @namespace Ember - @extends Ember.Mixin @uses Ember.Array @uses Ember.MutableEnumerable */ @@ -10998,9 +10972,8 @@ var get = Ember.get, set = Ember.set; @class Observable @namespace Ember - @extends Ember.Mixin */ -Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { +Ember.Observable = Ember.Mixin.create({ /** Retrieves the value of a property from the object. @@ -11380,7 +11353,8 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { */ incrementProperty: function(keyName, increment) { if (Ember.isNone(increment)) { increment = 1; } - set(this, keyName, (get(this, keyName) || 0)+increment); + Ember.assert("Must pass a numeric value to incrementProperty", (!isNaN(parseFloat(increment)) && isFinite(increment))); + set(this, keyName, (get(this, keyName) || 0) + increment); return get(this, keyName); }, @@ -11399,7 +11373,8 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { */ decrementProperty: function(keyName, decrement) { if (Ember.isNone(decrement)) { decrement = 1; } - set(this, keyName, (get(this, keyName) || 0)-decrement); + Ember.assert("Must pass a numeric value to decrementProperty", (!isNaN(parseFloat(decrement)) && isFinite(decrement))); + set(this, keyName, (get(this, keyName) || 0) - decrement); return get(this, keyName); }, @@ -11616,7 +11591,6 @@ Ember.TargetActionSupport = Ember.Mixin.create({ @class Evented @namespace Ember - @extends Ember.Mixin */ Ember.Evented = Ember.Mixin.create({ @@ -11748,7 +11722,6 @@ var get = Ember.get; /** @class Deferred @namespace Ember - @extends Ember.Mixin */ Ember.DeferredMixin = Ember.Mixin.create({ /** @@ -11980,6 +11953,10 @@ function makeCtor() { } +/** + @class CoreObject + @namespace Ember +*/ var CoreObject = makeCtor(); CoreObject.toString = function() { return "Ember.CoreObject"; }; @@ -12239,12 +12216,57 @@ var ClassMixin = Mixin.create({ return Class; }, + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ createWithMixins: function() { var C = this; if (arguments.length>0) { this._initMixins(arguments); } return new C(); }, + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ create: function() { var C = this; if (arguments.length>0) { this._initProperties(arguments); } @@ -12344,10 +12366,6 @@ if (Ember.config.overrideClassMixin) { CoreObject.ClassMixin = ClassMixin; ClassMixin.apply(CoreObject); -/** - @class CoreObject - @namespace Ember -*/ Ember.CoreObject = CoreObject; })(); @@ -13122,6 +13140,7 @@ function addObserverForContentKey(content, keyName, proxy, idx, loc) { while(--loc>=idx) { var item = content.objectAt(loc); if (item) { + Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', Ember.typeOf(item) === 'instance' || Ember.typeOf(item) === 'object'); Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange'); @@ -13205,7 +13224,7 @@ Ember.EachProxy = Ember.Object.extend({ for(key in keys) { if (!keys.hasOwnProperty(key)) { continue; } - if (lim>0) removeObserverForContentKey(content, key, this, idx, lim); + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } Ember.propertyWillChange(this, key); } @@ -13215,21 +13234,20 @@ Ember.EachProxy = Ember.Object.extend({ }, arrayDidChange: function(content, idx, removedCnt, addedCnt) { - var keys = this._keys, key, lim; + var keys = this._keys, lim; lim = addedCnt>0 ? idx+addedCnt : -1; - Ember.beginPropertyChanges(this); + Ember.changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } - for(key in keys) { - if (!keys.hasOwnProperty(key)) { continue; } + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } - if (lim>0) addObserverForContentKey(content, key, this, idx, lim); + Ember.propertyDidChange(this, key); + } - Ember.propertyDidChange(this, key); - } - - Ember.propertyDidChange(this._content, '@each'); - Ember.endPropertyChanges(this); + Ember.propertyDidChange(this._content, '@each'); + }, this); }, // .......................................................... @@ -13404,7 +13422,6 @@ if (ignore.length>0) { @class NativeArray @namespace Ember - @extends Ember.Mixin @uses Ember.MutableArray @uses Ember.Observable @uses Ember.Copyable @@ -14015,7 +14032,6 @@ var get = Ember.get; @class ControllerMixin @namespace Ember - @extends Ember.Mixin */ Ember.ControllerMixin = Ember.Mixin.create({ /* ducktype as a controller */ @@ -14103,7 +14119,6 @@ var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach; @class SortableMixin @namespace Ember - @extends Ember.Mixin @uses Ember.MutableEnumerable */ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { @@ -14121,7 +14136,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { @property {Boolean} sortAscending */ sortAscending: true, - + /** The function used to compare two values. You can override this if you want to do custom comparisons.Functions must be of the type expected by @@ -14143,7 +14158,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { @default Ember.compare */ sortFunction: Ember.compare, - + orderBy: function(item1, item2) { var result = 0, sortProperties = get(this, 'sortProperties'), @@ -19216,7 +19231,7 @@ Ember.CollectionView.CONTAINER_MAP = { (function() { -var set = Ember.set; +var get = Ember.get, set = Ember.set, isNone = Ember.isNone; /** @module ember @@ -19301,12 +19316,66 @@ var set = Ember.set; @namespace Ember @extends Ember.View */ -Ember.Component = Ember.View.extend({ +Ember.Component = Ember.View.extend(Ember.TargetActionSupport, { init: function() { this._super(); set(this, 'context', this); set(this, 'controller', this); set(this, 'templateData', {keywords: {}}); + }, + + targetObject: Ember.computed(function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }).property('_parentView'), + + /** + Sends an action to component's controller. A component inherits its + controller from the context in which it is used. + + By default, calling `sendAction()` will send an action with the name + of the component's `action` property. + + For example, if the component had a property `action` with the value + `"addItem"`, calling `sendAction()` would send the `addItem` action + to the component's controller. + + If you provide an argument to `sendAction()`, that key will be used to look + up the action name. + + For example, if the component had a property `playing` with the value + `didStartPlaying`, calling `sendAction('playing')` would send the + `didStartPlaying` action to the component's controller. + + Whether or not you are using the default action or a named action, if + the action name is not defined on the component, calling `sendAction()` + does not have any effect. + + For example, if you call `sendAction()` on a component that does not have + an `action` property defined, no action will be sent to the controller, + nor will an exception be raised. + + @param [action] {String} the action to trigger + */ + sendAction: function(action) { + var actionName; + + // Send the default action + if (action === undefined) { + actionName = get(this, 'action'); + Ember.assert("The default action was triggered on the component " + this.toString() + ", but the action name (" + actionName + ") was not a string.", isNone(actionName) || typeof actionName === 'string'); + } else { + actionName = get(this, action); + Ember.assert("The " + action + " action was triggered on the component " + this.toString() + ", but the action name (" + actionName + ") was not a string.", isNone(actionName) || typeof actionName === 'string'); + } + + + // If no action name for that action could be found, just abort. + if (actionName === undefined) { return; } + + this.triggerAction({ + action: actionName + }); } }); @@ -19410,7 +19479,7 @@ define("metamorph", document = this.document, // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges - supportsRange = document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, + supportsRange = false, // Internet Explorer prior to 9 does not allow setting innerHTML if the first element // is a "zero-scope" element. This problem can be worked around by making @@ -20394,7 +20463,7 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { view = data.view, currentContext = (options.contexts && options.contexts[0]) || this, normalized, - pathRoot, path, + pathRoot, path, prefixPathForDependentKeys = '', loc, hashOption; Ember.assert("registerBoundHelper-generated helpers do not support use with Handlebars blocks.", !options.fn); @@ -20445,8 +20514,11 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { view.registerObserver(pathRoot, path, bindView, bindView.rerender); + if(!Ember.isEmpty(path)) { + prefixPathForDependentKeys = path + '.'; + } for (var i=0, l=dependentKeys.length; i<l; i++) { - view.registerObserver(pathRoot, path + '.' + dependentKeys[i], bindView, bindView.rerender); + view.registerObserver(pathRoot, prefixPathForDependentKeys + dependentKeys[i], bindView, bindView.rerender); } } @@ -20674,21 +20746,23 @@ var DOMManager = { view.clearRenderedChildren(); var buffer = view.renderToBuffer(); - view.invokeRecursively(function(view) { - view.propertyWillChange('element'); - }); + // view.invokeRecursively(function(view) { + // view.propertyWillChange('element'); + // }); view.triggerRecursively('willInsertElement'); morph.replaceWith(buffer.string()); view.transitionTo('inDOM'); - view.invokeRecursively(function(view) { - view.propertyDidChange('element'); - }); + // view.invokeRecursively(function(view) { + // view.propertyDidChange('element'); + // }); view.triggerRecursively('didInsertElement'); notifyMutationListeners(); }); + + }, empty: function(view) { @@ -20703,7 +20777,6 @@ var DOMManager = { /** @class _Metamorph @namespace Ember - @extends Ember.Mixin @private */ Ember._Metamorph = Ember.Mixin.create({ @@ -22788,18 +22861,15 @@ Ember.Handlebars.registerHelper('each', function(path, options) { Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('<b>{{user}}</b>'); ``` + @deprecated @method template @for Ember.Handlebars.helpers @param {String} templateName the template to render */ Ember.Handlebars.registerHelper('template', function(name, options) { - var view = options.data.view, - template = view.templateForName(name); - - Ember.assert("Unable to find template with name '"+name+"'.", !!template); - - template(this, { data: options.data }); + Ember.deprecate("The `template` helper has been deprecated in favor of the `partial` helper. Please use `partial` instead, which will work the same way."); + return Ember.Handlebars.helpers.partial.apply(this, arguments); }); })(); @@ -22849,7 +22919,6 @@ Ember.Handlebars.registerHelper('partial', function(name, options) { template = view.templateForName(underscoredName), deprecatedTemplate = !template && view.templateForName(name); - Ember.deprecate("You tried to render the partial " + name + ", which should be at '" + underscoredName + "', but Ember found '" + name + "'. Please use a leading underscore in your partials", template); Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate); template = template || deprecatedTemplate; @@ -22934,6 +23003,7 @@ Ember.Handlebars.registerHelper('yield', function(options) { var keywords = view._parentView.cloneKeywords(); currentView.appendChild(Ember.View, { + isVirtual: true, tagName: '', template: template, context: get(view._parentView, 'context'), @@ -23080,7 +23150,6 @@ var get = Ember.get, set = Ember.set; @class TextSupport @namespace Ember - @extends Ember.Mixin @private */ Ember.TextSupport = Ember.Mixin.create({ @@ -25288,7 +25357,7 @@ define("router", } function isParam(object) { - return object && (typeof object === "string" || object instanceof String || !isNaN(object)); + return (typeof object === "string" || object instanceof String || !isNaN(object)); } /** @@ -25763,8 +25832,7 @@ define("router", handlerInfo = handlerInfos[index], handler = handlerInfo.handler, handlerName = handlerInfo.name, - seq = transition.sequence, - errorAlreadyHandled = false; + seq = transition.sequence; if (index < matchPoint) { log(router, seq, handlerName + ": using context from already-active handler"); @@ -25777,21 +25845,17 @@ define("router", return RSVP.resolve().then(handleAbort) .then(beforeModel) - .then(null, handleError) .then(handleAbort) .then(model) - .then(null, handleError) .then(handleAbort) .then(afterModel) - .then(null, handleError) .then(handleAbort) - .then(proceed); + .then(proceed) + .then(null, handleError); function handleAbort(result) { - - if (transition.isAborted) { + if (transition.isAborted) { log(transition.router, transition.sequence, "detected abort."); - errorAlreadyHandled = true; return RSVP.reject(new Router.TransitionAborted()); } @@ -25799,9 +25863,13 @@ define("router", } function handleError(reason) { + if (reason instanceof Router.TransitionAborted) { + // if the transition was aborted and *no additional* error was thrown, + // reject with the Router.TransitionAborted instance + return RSVP.reject(reason); + } - if (errorAlreadyHandled) { return RSVP.reject(reason); } - errorAlreadyHandled = true; + // otherwise, we're here because of a different error transition.abort(); log(router, seq, handlerName + ": handling error: " + reason); @@ -26066,9 +26134,8 @@ var get = Ember.get; @submodule ember-routing */ -Ember.controllerFor = function(container, controllerName, context, lookupOptions) { - return container.lookup('controller:' + controllerName, lookupOptions) || - Ember.generateController(container, controllerName, context); +Ember.controllerFor = function(container, controllerName, lookupOptions) { + return container.lookup('controller:' + controllerName, lookupOptions); }; /* Generates a controller automatically if none was provided. @@ -26082,14 +26149,12 @@ Ember.generateController = function(container, controllerName, context) { if (context && Ember.isArray(context)) { DefaultController = container.resolve('controller:array'); controller = DefaultController.extend({ - isGenerated: true, - content: context + isGenerated: true }); } else if (context) { DefaultController = container.resolve('controller:object'); controller = DefaultController.extend({ - isGenerated: true, - content: context + isGenerated: true }); } else { DefaultController = container.resolve('controller:basic'); @@ -26204,9 +26269,7 @@ Ember.Router = Ember.Object.extend({ }, handleURL: function(url) { - scheduleLoadingStateEntry(this); - - return this.router.handleURL(url).then(transitionCompleted); + return doTransition(this, 'handleURL', [url]); }, transitionTo: function() { @@ -26372,9 +26435,13 @@ function doTransition(router, method, args) { Ember.assert("The route " + passedName + " was not found", router.router.hasRoute(name)); } - scheduleLoadingStateEntry(router); - var transitionPromise = router.router[method].apply(router.router, args); + + // Don't schedule loading state entry if user has already aborted the transition. + if (router.router.activeTransition) { + scheduleLoadingStateEntry(router); + } + transitionPromise.then(transitionCompleted); // We want to return the configurable promise object @@ -26534,7 +26601,7 @@ Ember.Route = Ember.Object.extend({ }); ``` - You can also redirect elsewhere by calling + You can also redirect elsewhere by calling `this.transitionTo('elsewhere')` from within `willTransition`. Note that `willTransition` will not be fired for the redirecting `transitionTo`, since `willTransition` doesn't @@ -26549,8 +26616,8 @@ Ember.Route = Ember.Object.extend({ may throw an error, or return a promise that rejects, at which point an `error` event will be fired on the partially-entered routes, allowing for per-route error handling logic, or shared - error handling logic defined on a parent route. - + error handling logic defined on a parent route. + Here is an example of an error handler that will be invoked for rejected promises / thrown errors from the various hooks on the route, as well as any unhandled errors from child @@ -26568,9 +26635,9 @@ Ember.Route = Ember.Object.extend({ error: function(error, transition) { // Assuming we got here due to the error in `beforeModel`, // we can expect that error === "bad things!", - // but a promise model rejecting would also + // but a promise model rejecting would also // call this hook, as would any errors encountered - // in `afterModel`. + // in `afterModel`. // The `error` hook is also provided the failed // `transition`, which can be stored and later @@ -26582,9 +26649,9 @@ Ember.Route = Ember.Object.extend({ }); ``` - `error` events that bubble up all the way to `ApplicationRoute` + `error` events that bubble up all the way to `ApplicationRoute` will fire a default error handler that logs the error. You can - specify your own global default error handler by overriding the + specify your own global default error handler by overriding the `error` handler on `ApplicationRoute`: ```js @@ -26664,7 +26731,11 @@ Ember.Route = Ember.Object.extend({ @method setup */ setup: function(context) { - var controller = this.controllerFor(this.controllerName || this.routeName, context); + var controllerName = this.controllerName || this.routeName, + controller = this.controllerFor(controllerName, true); + if (!controller) { + controller = this.generateController(controllerName, context); + } // Assign the route's controller so that it can more easily be // referenced in event handlers @@ -26709,20 +26780,20 @@ Ember.Route = Ember.Object.extend({ 1) A decision can be made to redirect elsewhere without needing to resolve the model first. - 2) Any async operations need to occur first before the + 2) Any async operations need to occur first before the model is attempted to be resolved. This hook is provided the current `transition` attempt as a parameter, which can be used to `.abort()` the transition, save it for a later `.retry()`, or retrieve values set on it from a previous hook. You can also just call - `this.transitionTo` to another route to implicitly - abort the `transition`. + `this.transitionTo` to another route to implicitly + abort the `transition`. You can return a promise from this hook to pause the transition until the promise resolves (or rejects). This could - be useful, for instance, for retrieving async code from - the server that is required to enter a route. + be useful, for instance, for retrieving async code from + the server that is required to enter a route. ```js App.PostRoute = Ember.Route.extend({ @@ -26734,13 +26805,13 @@ Ember.Route = Ember.Object.extend({ }); ``` - If `App.Post` doesn't exist in the above example, + If `App.Post` doesn't exist in the above example, `beforeModel` will use jQuery's `getScript`, which returns a promise that resolves after the server has successfully retrieved and executed the code from the - server. Note that if an error were to occur, it would - be passed to the `error` hook on `Ember.Route`, but - it's also possible to handle errors specific to + server. Note that if an error were to occur, it would + be passed to the `error` hook on `Ember.Route`, but + it's also possible to handle errors specific to `beforeModel` right from within the hook (to distinguish from the shared error handling behavior of the `error` hook): @@ -26755,11 +26826,11 @@ Ember.Route = Ember.Object.extend({ // Note that the above transitionTo will implicitly // halt the transition. If you were to return - // nothing from this promise reject handler, + // nothing from this promise reject handler, // according to promise semantics, that would - // convert the reject into a resolve and the + // convert the reject into a resolve and the // transition would continue. To propagate the - // error so that it'd be handled by the `error` + // error so that it'd be handled by the `error` // hook, you would have to either return Ember.RSVP.reject(e); // or @@ -26771,18 +26842,18 @@ Ember.Route = Ember.Object.extend({ ``` @method beforeModel - @param {Transition} transition + @param {Transition} transition @return {Promise} if the value returned from this hook is a promise, the transition will pause until the transition - resolves. Otherwise, non-promise return values are not + resolves. Otherwise, non-promise return values are not utilized in any way. */ beforeModel: Ember.K, /** This hook is called after this route's model has resolved. - It follows identical async/promise semantics to `beforeModel` - but is provided the route's resolved model in addition to + It follows identical async/promise semantics to `beforeModel` + but is provided the route's resolved model in addition to the `transition`, and is therefore suited to performing logic that can only take place after the model has already resolved. @@ -26799,13 +26870,13 @@ Ember.Route = Ember.Object.extend({ Refer to documentation for `beforeModel` for a description of transition-pausing semantics when a promise is returned - from this hook. + from this hook. @method afterModel - @param {Transition} transition + @param {Transition} transition @return {Promise} if the value returned from this hook is a promise, the transition will pause until the transition - resolves. Otherwise, non-promise return values are not + resolves. Otherwise, non-promise return values are not utilized in any way. */ afterModel: function(resolvedModel, transition) { @@ -26852,7 +26923,7 @@ Ember.Route = Ember.Object.extend({ This hook follows the asynchronous/promise semantics described in the documentation for `beforeModel`. In particular, - if a promise returned from `model` fails, the error will be + if a promise returned from `model` fails, the error will be handled by the `error` hook on `Ember.Route`. @method model @@ -26981,29 +27052,42 @@ Ember.Route = Ember.Object.extend({ }); ``` - By default, the controller for `post` is the shared instance of - `App.PostController`. - @method controllerFor @param {String} name the name of the route - @param {Object} model the model associated with the route (optional) @return {Ember.Controller} */ - controllerFor: function(name, model) { + controllerFor: function(name, _skipAssert) { var container = this.router.container, controller = container.lookup('controller:' + name); - if (!controller) { - model = model || this.modelFor(name); - - Ember.assert("You are trying to look up a controller that you did not define, and for which Ember does not know the model.\n\nThis is not a controller for a route, so you must explicitly define the controller ("+this.router.namespace.toString() + "." + Ember.String.capitalize(Ember.String.camelize(name))+"Controller) or pass a model as the second parameter to `controllerFor`, so that Ember knows which type of controller to create for you.", model || this.container.lookup('route:' + name)); - - controller = Ember.generateController(container, name, model); - } + // NOTE: We're specifically checking that skipAssert is true, because according + // to the old API the second parameter was model. We do not want people who + // passed a model to skip the assertion. + Ember.assert("The controller "+name+" could not be found. Make sure the controller has been generated first. This will happen the first time the associated route is entered.", controller || _skipAssert === true); return controller; }, + /** + Generates a controller for a route. + + If the optional model is passed then the controller type is determined automatically, + e.g., an ArrayController for arrays. + + @method generateController + @param {String} name the name of the controller + @param {Object} model the model to infer the type of the controller (optional) + */ + generateController: function(name, model) { + var container = this.router.container; + + model = model || this.modelFor(name); + + Ember.assert("You are trying to look up a controller that you did not define, and for which Ember does not know the model.\n\nThis is not a controller for a route, so you must explicitly define the controller ("+this.router.namespace.toString() + "." + Ember.String.capitalize(Ember.String.camelize(name))+"Controller) or pass a model as the second parameter to `controllerFor`, so that Ember knows which type of controller to create for you.", model || this.container.lookup('route:' + name)); + + return Ember.generateController(container, name, model); + }, + /** Returns the current model for a given route. @@ -27103,6 +27187,8 @@ Ember.Route = Ember.Object.extend({ render: function(name, options) { Ember.assert("The name in the given arguments is undefined", arguments.length > 0 ? !Ember.isNone(arguments[0]) : true); + var namePassed = !!name; + if (typeof name === 'object' && !options) { options = name; name = this.routeName; @@ -27115,6 +27201,7 @@ Ember.Route = Ember.Object.extend({ template = container.lookup('template:' + name); if (!view && !template) { + Ember.assert("Could not find \"" + name + "\" template or view.", !namePassed); if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); } @@ -27174,17 +27261,17 @@ Ember.Route = Ember.Object.extend({ willDestroy: function() { this.teardownViews(); }, - + teardownViews: function() { // Tear down the top level view if (this.teardownTopLevelView) { this.teardownTopLevelView(); } - + // Tear down any outlets rendered with 'into' var teardownOutletViews = this.teardownOutletViews || []; - a_forEach(teardownOutletViews, function(teardownOutletView) { + a_forEach(teardownOutletViews, function(teardownOutletView) { teardownOutletView(); }); - + delete this.teardownTopLevelView; delete this.teardownOutletViews; delete this.lastRenderedTemplate; @@ -27205,17 +27292,15 @@ function parentRoute(route) { } } -function parentTemplate(route, isRecursive) { +function parentTemplate(route) { var parent = parentRoute(route), template; if (!parent) { return; } - Ember.warn(fmt("The immediate parent route ('%@') did not render into the main outlet and the default 'into' option ('%@') may not be expected", [get(parent, 'routeName'), get(route, 'routeName')]), !isRecursive); - if (template = parent.lastRenderedTemplate) { return template; } else { - return parentTemplate(parent, true); + return parentTemplate(parent); } } @@ -27227,7 +27312,7 @@ function normalizeOptions(route, name, template, options) { options.template = template; options.LOG_VIEW_LOOKUPS = get(route.router, 'namespace.LOG_VIEW_LOOKUPS'); - Ember.assert("An outlet ("+options.outlet+") was specified but this view will render at the root level.", options.outlet === 'main' || options.into); + Ember.assert("An outlet ("+options.outlet+") was specified but was not found.", options.outlet === 'main' || options.into); var controller = options.controller, namedController; @@ -27377,7 +27462,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { `Ember.LinkView` renders an element whose `click` event triggers a transition of the application's instance of `Ember.Router` to a supplied route by name. - + Instances of `LinkView` will most likely be created through the `linkTo` Handlebars helper, but properties of this class can be overridden to customize application-wide behavior. @@ -27423,7 +27508,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** The CSS class to apply to a `LinkView`'s element when its `disabled` property is `true`. - + @property disabledClass @type String @default disabled @@ -27433,8 +27518,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** Determines whether the `LinkView` will trigger routing via - the `replaceWith` routing strategy. + the `replaceWith` routing strategy. + @property replace @type Boolean @default false **/ @@ -27445,7 +27531,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** By default the `{{linkTo}}` helper responds to the `click` event. You can override this globally by setting this property to your custom - event name. + event name. This is particularly useful on mobile when one wants to avoid the 300ms click delay using some sort of custom `tap` event. @@ -27488,15 +27574,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { } var observer = function(object, path) { - var notify = true, i; - for(i=0; i < paths.length; i++) { - if (!get(this, paths[i])) { - notify = false; - } - } - if (notify) { - this.notifyPropertyChange('routeArgs'); - } + this.notifyPropertyChange('routeArgs'); }; for(i=0; i < length; i++) { @@ -27506,10 +27584,10 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** @private - + Even though this isn't a virtual view, we want to treat it as if it is so that you can access the parent with {{view.prop}} - + @method concreteView **/ concreteView: Ember.computed(function() { @@ -27517,16 +27595,16 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { }).property('parentView'), /** - + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` CSS `class` to the element when the link is disabled. - + When `true` interactions with the element will not trigger route changes. @property disabled */ disabled: Ember.computed(function(key, value) { if (value !== undefined) { this.set('_isDisabled', value); } - + return value ? this.get('disabledClass') : false; }), @@ -27583,12 +27661,12 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { event.preventDefault(); if (this.bubbles === false) { event.stopPropagation(); } - + if (get(this, '_isDisabled')) { return false; } - if (get(this, 'loading')) { - Ember.Logger.warn("This linkTo's parameters are either not yet loaded or point to an invalid route."); - return false; + if (get(this, 'loading')) { + Ember.Logger.warn("This linkTo is in an inactive loading state because at least one of its parameters' presently has a null/undefined value, or the provided route name is invalid."); + return false; } var router = get(this, 'router'), @@ -27603,7 +27681,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { routeArgs: Ember.computed(function() { - var router = get(this, 'router'), + var router = get(this, 'router'), namedRoute = get(this, 'namedRoute'), routeName; if (!namedRoute && this.namedRouteBinding) { @@ -27693,7 +27771,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { </li> ``` - To override this option for your entire application, see + To override this option for your entire application, see "Overriding Application-wide Defaults". ### Handling `href` @@ -27740,7 +27818,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { </a> ``` - To override this option for your entire application, see + To override this option for your entire application, see "Overriding Application-wide Defaults". ### Supplying a model @@ -27827,7 +27905,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { params = [].slice.call(arguments, 1, -1); var hash = options.hash; - + if (options.types[0] === "ID") { if (Ember.ENV.HELPER_PARAM_LOOKUPS) { hash.namedRouteBinding = name; @@ -28023,7 +28101,8 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { controller = container.lookup('controller:' + controllerName, lookupOptions); Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", !!controller); } else { - controller = Ember.controllerFor(container, name, context, lookupOptions); + controller = container.lookup('controller:' + name, lookupOptions) || + Ember.generateController(container, name, context); } if (controller && context) { @@ -30260,11 +30339,11 @@ Ember.ControllerMixin.reopen({ needs: ['post'] }); ``` - + The application's single instance of these other controllers are accessible by name through the `controllers` property: - + ```javascript this.get('controllers.post'); // instance of App.PostController ``` @@ -30287,8 +30366,7 @@ Ember.ControllerMixin.reopen({ controllerFor: function(controllerName) { Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead"); - var container = get(this, 'container'); - return container.lookup('controller:' + controllerName); + return Ember.controllerFor(get(this, 'container'), controllerName); }, controllers: Ember.computed(function() { @@ -31906,7 +31984,7 @@ Test.QUnitAdapter = Test.Adapter.extend({ start(); }, exception: function(error) { - ok(false, error); + ok(false, Ember.inspect(error)); } }); @@ -31990,7 +32068,7 @@ function fillIn(app, selector, context, text) { function findWithAssert(app, selector, context) { var $el = find(app, selector, context); if ($el.length === 0) { - throw("Element " + selector + " not found."); + throw new Error("Element " + selector + " not found."); } return $el; } diff --git a/app/assets/javascripts/external_production/ember.js b/app/assets/javascripts/external_production/ember.js index d2039e014..142737f9a 100644 --- a/app/assets/javascripts/external_production/ember.js +++ b/app/assets/javascripts/external_production/ember.js @@ -89,10 +89,10 @@ Ember.toString = function() { return "Ember"; }; /** @property VERSION @type String - @default '1.0.0-rc.6' + @default '1.0.0-rc.6.1' @final */ -Ember.VERSION = '1.0.0-rc.6'; +Ember.VERSION = '1.0.0-rc.6.1'; /** Standard environmental variables. You can define these in a global `ENV` @@ -4678,6 +4678,9 @@ define("backburner", run: function(target, method /*, args */) { var ret; + + var t2 = new Date().getTime(); + this.begin(); if (!method) { @@ -4703,6 +4706,15 @@ define("backburner", this.end(); } } + + var diff = new Date().getTime() - t2; + + if ((typeof console !== 'undefined') && console.log && diff > 1) { + console.log("Backburner: " + (new Date() - t2) + "ms"); + } + + + return ret; }, @@ -5970,7 +5982,8 @@ Ember.oneWay = function(obj, to, from) { (function() { /** -@module ember-metal +@module ember +@submodule ember-metal */ var Mixin, REQUIRED, Alias, @@ -6346,38 +6359,6 @@ Mixin.finishPartial = finishPartial; Ember.anyUnprocessedMixins = false; /** - Creates an instance of a class. Accepts either no arguments, or an object - containing values to initialize the newly instantiated object with. - - ```javascript - App.Person = Ember.Object.extend({ - helloWorld: function() { - alert("Hi, my name is " + this.get('name')); - } - }); - - var tom = App.Person.create({ - name: 'Tom Dale' - }); - - tom.helloWorld(); // alerts "Hi, my name is Tom Dale". - ``` - - `create` will call the `init` function if defined during - `Ember.AnyObject.extend` - - If no arguments are passed to `create`, it will not set values to the new - instance during initialization: - - ```javascript - var noName = App.Person.create(); - noName.helloWorld(); // alerts undefined - ``` - - NOTE: For performance reasons, you cannot declare methods or computed - properties during `create`. You should instead declare methods and computed - properties when using `extend`. - @method create @static @param arguments* @@ -8907,7 +8888,6 @@ function iter(key, value) { @class Enumerable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Enumerable = Ember.Mixin.create({ @@ -9383,7 +9363,7 @@ Ember.Enumerable = Ember.Mixin.create({ @method some @param {Function} callback The callback to execute @param {Object} [target] The target object to use - @return {Array} A filtered array. + @return {Boolean} `true` if the passed function returns `true` for any item */ some: function(callback, target) { return !!this.find(function(x, idx, i) { @@ -9398,7 +9378,7 @@ Ember.Enumerable = Ember.Mixin.create({ @method someProperty @param {String} key the property to test @param {String} [value] optional value to test against. - @return {Boolean} `true` + @return {Boolean} `true` if the passed function returns `true` for any item */ someProperty: function(key, value) { return this.some(iter.apply(this, arguments)); @@ -9742,7 +9722,6 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone, map = Ember.Enumera @class Array @namespace Ember - @extends Ember.Mixin @uses Ember.Enumerable @since Ember 0.9.0 */ @@ -10140,7 +10119,6 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot @class Comparable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Comparable = Ember.Mixin.create( /** @scope Ember.Comparable.prototype */{ @@ -10192,7 +10170,6 @@ var get = Ember.get, set = Ember.set; @class Copyable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Copyable = Ember.Mixin.create(/** @scope Ember.Copyable.prototype */ { @@ -10297,7 +10274,6 @@ var get = Ember.get, set = Ember.set; @class Freezable @namespace Ember - @extends Ember.Mixin @since Ember 0.9 */ Ember.Freezable = Ember.Mixin.create(/** @scope Ember.Freezable.prototype */ { @@ -10377,7 +10353,6 @@ var forEach = Ember.EnumerableUtils.forEach; @class MutableEnumerable @namespace Ember - @extends Ember.Mixin @uses Ember.Enumerable */ Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable, { @@ -10477,7 +10452,6 @@ var get = Ember.get, set = Ember.set; @class MutableArray @namespace Ember - @extends Ember.Mixin @uses Ember.Array @uses Ember.MutableEnumerable */ @@ -10831,9 +10805,8 @@ var get = Ember.get, set = Ember.set; @class Observable @namespace Ember - @extends Ember.Mixin */ -Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { +Ember.Observable = Ember.Mixin.create({ /** Retrieves the value of a property from the object. @@ -11213,7 +11186,8 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { */ incrementProperty: function(keyName, increment) { if (Ember.isNone(increment)) { increment = 1; } - set(this, keyName, (get(this, keyName) || 0)+increment); + + set(this, keyName, (get(this, keyName) || 0) + increment); return get(this, keyName); }, @@ -11232,7 +11206,8 @@ Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ { */ decrementProperty: function(keyName, decrement) { if (Ember.isNone(decrement)) { decrement = 1; } - set(this, keyName, (get(this, keyName) || 0)-decrement); + + set(this, keyName, (get(this, keyName) || 0) - decrement); return get(this, keyName); }, @@ -11449,7 +11424,6 @@ Ember.TargetActionSupport = Ember.Mixin.create({ @class Evented @namespace Ember - @extends Ember.Mixin */ Ember.Evented = Ember.Mixin.create({ @@ -11581,7 +11555,6 @@ var get = Ember.get; /** @class Deferred @namespace Ember - @extends Ember.Mixin */ Ember.DeferredMixin = Ember.Mixin.create({ /** @@ -11811,6 +11784,10 @@ function makeCtor() { } +/** + @class CoreObject + @namespace Ember +*/ var CoreObject = makeCtor(); CoreObject.toString = function() { return "Ember.CoreObject"; }; @@ -12070,12 +12047,57 @@ var ClassMixin = Mixin.create({ return Class; }, + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ createWithMixins: function() { var C = this; if (arguments.length>0) { this._initMixins(arguments); } return new C(); }, + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ create: function() { var C = this; if (arguments.length>0) { this._initProperties(arguments); } @@ -12174,10 +12196,6 @@ if (Ember.config.overrideClassMixin) { CoreObject.ClassMixin = ClassMixin; ClassMixin.apply(CoreObject); -/** - @class CoreObject - @namespace Ember -*/ Ember.CoreObject = CoreObject; })(); @@ -12950,6 +12968,7 @@ function addObserverForContentKey(content, keyName, proxy, idx, loc) { while(--loc>=idx) { var item = content.objectAt(loc); if (item) { + Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange'); @@ -13033,7 +13052,7 @@ Ember.EachProxy = Ember.Object.extend({ for(key in keys) { if (!keys.hasOwnProperty(key)) { continue; } - if (lim>0) removeObserverForContentKey(content, key, this, idx, lim); + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } Ember.propertyWillChange(this, key); } @@ -13043,21 +13062,20 @@ Ember.EachProxy = Ember.Object.extend({ }, arrayDidChange: function(content, idx, removedCnt, addedCnt) { - var keys = this._keys, key, lim; + var keys = this._keys, lim; lim = addedCnt>0 ? idx+addedCnt : -1; - Ember.beginPropertyChanges(this); + Ember.changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } - for(key in keys) { - if (!keys.hasOwnProperty(key)) { continue; } + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } - if (lim>0) addObserverForContentKey(content, key, this, idx, lim); + Ember.propertyDidChange(this, key); + } - Ember.propertyDidChange(this, key); - } - - Ember.propertyDidChange(this._content, '@each'); - Ember.endPropertyChanges(this); + Ember.propertyDidChange(this._content, '@each'); + }, this); }, // .......................................................... @@ -13232,7 +13250,6 @@ if (ignore.length>0) { @class NativeArray @namespace Ember - @extends Ember.Mixin @uses Ember.MutableArray @uses Ember.Observable @uses Ember.Copyable @@ -13843,7 +13860,6 @@ var get = Ember.get; @class ControllerMixin @namespace Ember - @extends Ember.Mixin */ Ember.ControllerMixin = Ember.Mixin.create({ /* ducktype as a controller */ @@ -13931,7 +13947,6 @@ var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach; @class SortableMixin @namespace Ember - @extends Ember.Mixin @uses Ember.MutableEnumerable */ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { @@ -13949,7 +13964,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { @property {Boolean} sortAscending */ sortAscending: true, - + /** The function used to compare two values. You can override this if you want to do custom comparisons.Functions must be of the type expected by @@ -13971,7 +13986,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { @default Ember.compare */ sortFunction: Ember.compare, - + orderBy: function(item1, item2) { var result = 0, sortProperties = get(this, 'sortProperties'), @@ -19034,7 +19049,7 @@ Ember.CollectionView.CONTAINER_MAP = { (function() { -var set = Ember.set; +var get = Ember.get, set = Ember.set, isNone = Ember.isNone; /** @module ember @@ -19119,12 +19134,66 @@ var set = Ember.set; @namespace Ember @extends Ember.View */ -Ember.Component = Ember.View.extend({ +Ember.Component = Ember.View.extend(Ember.TargetActionSupport, { init: function() { this._super(); set(this, 'context', this); set(this, 'controller', this); set(this, 'templateData', {keywords: {}}); + }, + + targetObject: Ember.computed(function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }).property('_parentView'), + + /** + Sends an action to component's controller. A component inherits its + controller from the context in which it is used. + + By default, calling `sendAction()` will send an action with the name + of the component's `action` property. + + For example, if the component had a property `action` with the value + `"addItem"`, calling `sendAction()` would send the `addItem` action + to the component's controller. + + If you provide an argument to `sendAction()`, that key will be used to look + up the action name. + + For example, if the component had a property `playing` with the value + `didStartPlaying`, calling `sendAction('playing')` would send the + `didStartPlaying` action to the component's controller. + + Whether or not you are using the default action or a named action, if + the action name is not defined on the component, calling `sendAction()` + does not have any effect. + + For example, if you call `sendAction()` on a component that does not have + an `action` property defined, no action will be sent to the controller, + nor will an exception be raised. + + @param [action] {String} the action to trigger + */ + sendAction: function(action) { + var actionName; + + // Send the default action + if (action === undefined) { + actionName = get(this, 'action'); + + } else { + actionName = get(this, action); + + } + + + // If no action name for that action could be found, just abort. + if (actionName === undefined) { return; } + + this.triggerAction({ + action: actionName + }); } }); @@ -19228,7 +19297,7 @@ define("metamorph", document = this.document, // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges - supportsRange = document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, + supportsRange = false, // Internet Explorer prior to 9 does not allow setting innerHTML if the first element // is a "zero-scope" element. This problem can be worked around by making @@ -20211,7 +20280,7 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { view = data.view, currentContext = (options.contexts && options.contexts[0]) || this, normalized, - pathRoot, path, + pathRoot, path, prefixPathForDependentKeys = '', loc, hashOption; @@ -20260,8 +20329,11 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) { view.registerObserver(pathRoot, path, bindView, bindView.rerender); + if(!Ember.isEmpty(path)) { + prefixPathForDependentKeys = path + '.'; + } for (var i=0, l=dependentKeys.length; i<l; i++) { - view.registerObserver(pathRoot, path + '.' + dependentKeys[i], bindView, bindView.rerender); + view.registerObserver(pathRoot, prefixPathForDependentKeys + dependentKeys[i], bindView, bindView.rerender); } } @@ -20489,21 +20561,23 @@ var DOMManager = { view.clearRenderedChildren(); var buffer = view.renderToBuffer(); - view.invokeRecursively(function(view) { - view.propertyWillChange('element'); - }); + // view.invokeRecursively(function(view) { + // view.propertyWillChange('element'); + // }); view.triggerRecursively('willInsertElement'); morph.replaceWith(buffer.string()); view.transitionTo('inDOM'); - view.invokeRecursively(function(view) { - view.propertyDidChange('element'); - }); + // view.invokeRecursively(function(view) { + // view.propertyDidChange('element'); + // }); view.triggerRecursively('didInsertElement'); notifyMutationListeners(); }); + + }, empty: function(view) { @@ -20518,7 +20592,6 @@ var DOMManager = { /** @class _Metamorph @namespace Ember - @extends Ember.Mixin @private */ Ember._Metamorph = Ember.Mixin.create({ @@ -22594,17 +22667,15 @@ Ember.Handlebars.registerHelper('each', function(path, options) { Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('<b>{{user}}</b>'); ``` + @deprecated @method template @for Ember.Handlebars.helpers @param {String} templateName the template to render */ Ember.Handlebars.registerHelper('template', function(name, options) { - var view = options.data.view, - template = view.templateForName(name); - - template(this, { data: options.data }); + return Ember.Handlebars.helpers.partial.apply(this, arguments); }); })(); @@ -22655,7 +22726,6 @@ Ember.Handlebars.registerHelper('partial', function(name, options) { deprecatedTemplate = !template && view.templateForName(name); - template = template || deprecatedTemplate; template(this, { data: options.data }); @@ -22737,6 +22807,7 @@ Ember.Handlebars.registerHelper('yield', function(options) { var keywords = view._parentView.cloneKeywords(); currentView.appendChild(Ember.View, { + isVirtual: true, tagName: '', template: template, context: get(view._parentView, 'context'), @@ -22883,7 +22954,6 @@ var get = Ember.get, set = Ember.set; @class TextSupport @namespace Ember - @extends Ember.Mixin @private */ Ember.TextSupport = Ember.Mixin.create({ @@ -25091,7 +25161,7 @@ define("router", } function isParam(object) { - return object && (typeof object === "string" || object instanceof String || !isNaN(object)); + return (typeof object === "string" || object instanceof String || !isNaN(object)); } /** @@ -25566,8 +25636,7 @@ define("router", handlerInfo = handlerInfos[index], handler = handlerInfo.handler, handlerName = handlerInfo.name, - seq = transition.sequence, - errorAlreadyHandled = false; + seq = transition.sequence; if (index < matchPoint) { log(router, seq, handlerName + ": using context from already-active handler"); @@ -25580,21 +25649,17 @@ define("router", return RSVP.resolve().then(handleAbort) .then(beforeModel) - .then(null, handleError) .then(handleAbort) .then(model) - .then(null, handleError) .then(handleAbort) .then(afterModel) - .then(null, handleError) .then(handleAbort) - .then(proceed); + .then(proceed) + .then(null, handleError); function handleAbort(result) { - - if (transition.isAborted) { + if (transition.isAborted) { log(transition.router, transition.sequence, "detected abort."); - errorAlreadyHandled = true; return RSVP.reject(new Router.TransitionAborted()); } @@ -25602,9 +25667,13 @@ define("router", } function handleError(reason) { + if (reason instanceof Router.TransitionAborted) { + // if the transition was aborted and *no additional* error was thrown, + // reject with the Router.TransitionAborted instance + return RSVP.reject(reason); + } - if (errorAlreadyHandled) { return RSVP.reject(reason); } - errorAlreadyHandled = true; + // otherwise, we're here because of a different error transition.abort(); log(router, seq, handlerName + ": handling error: " + reason); @@ -25869,9 +25938,8 @@ var get = Ember.get; @submodule ember-routing */ -Ember.controllerFor = function(container, controllerName, context, lookupOptions) { - return container.lookup('controller:' + controllerName, lookupOptions) || - Ember.generateController(container, controllerName, context); +Ember.controllerFor = function(container, controllerName, lookupOptions) { + return container.lookup('controller:' + controllerName, lookupOptions); }; /* Generates a controller automatically if none was provided. @@ -25885,14 +25953,12 @@ Ember.generateController = function(container, controllerName, context) { if (context && Ember.isArray(context)) { DefaultController = container.resolve('controller:array'); controller = DefaultController.extend({ - isGenerated: true, - content: context + isGenerated: true }); } else if (context) { DefaultController = container.resolve('controller:object'); controller = DefaultController.extend({ - isGenerated: true, - content: context + isGenerated: true }); } else { DefaultController = container.resolve('controller:basic'); @@ -26007,9 +26073,7 @@ Ember.Router = Ember.Object.extend({ }, handleURL: function(url) { - scheduleLoadingStateEntry(this); - - return this.router.handleURL(url).then(transitionCompleted); + return doTransition(this, 'handleURL', [url]); }, transitionTo: function() { @@ -26174,9 +26238,13 @@ function doTransition(router, method, args) { } - scheduleLoadingStateEntry(router); - var transitionPromise = router.router[method].apply(router.router, args); + + // Don't schedule loading state entry if user has already aborted the transition. + if (router.router.activeTransition) { + scheduleLoadingStateEntry(router); + } + transitionPromise.then(transitionCompleted); // We want to return the configurable promise object @@ -26336,7 +26404,7 @@ Ember.Route = Ember.Object.extend({ }); ``` - You can also redirect elsewhere by calling + You can also redirect elsewhere by calling `this.transitionTo('elsewhere')` from within `willTransition`. Note that `willTransition` will not be fired for the redirecting `transitionTo`, since `willTransition` doesn't @@ -26351,8 +26419,8 @@ Ember.Route = Ember.Object.extend({ may throw an error, or return a promise that rejects, at which point an `error` event will be fired on the partially-entered routes, allowing for per-route error handling logic, or shared - error handling logic defined on a parent route. - + error handling logic defined on a parent route. + Here is an example of an error handler that will be invoked for rejected promises / thrown errors from the various hooks on the route, as well as any unhandled errors from child @@ -26370,9 +26438,9 @@ Ember.Route = Ember.Object.extend({ error: function(error, transition) { // Assuming we got here due to the error in `beforeModel`, // we can expect that error === "bad things!", - // but a promise model rejecting would also + // but a promise model rejecting would also // call this hook, as would any errors encountered - // in `afterModel`. + // in `afterModel`. // The `error` hook is also provided the failed // `transition`, which can be stored and later @@ -26384,9 +26452,9 @@ Ember.Route = Ember.Object.extend({ }); ``` - `error` events that bubble up all the way to `ApplicationRoute` + `error` events that bubble up all the way to `ApplicationRoute` will fire a default error handler that logs the error. You can - specify your own global default error handler by overriding the + specify your own global default error handler by overriding the `error` handler on `ApplicationRoute`: ```js @@ -26466,7 +26534,11 @@ Ember.Route = Ember.Object.extend({ @method setup */ setup: function(context) { - var controller = this.controllerFor(this.controllerName || this.routeName, context); + var controllerName = this.controllerName || this.routeName, + controller = this.controllerFor(controllerName, true); + if (!controller) { + controller = this.generateController(controllerName, context); + } // Assign the route's controller so that it can more easily be // referenced in event handlers @@ -26511,20 +26583,20 @@ Ember.Route = Ember.Object.extend({ 1) A decision can be made to redirect elsewhere without needing to resolve the model first. - 2) Any async operations need to occur first before the + 2) Any async operations need to occur first before the model is attempted to be resolved. This hook is provided the current `transition` attempt as a parameter, which can be used to `.abort()` the transition, save it for a later `.retry()`, or retrieve values set on it from a previous hook. You can also just call - `this.transitionTo` to another route to implicitly - abort the `transition`. + `this.transitionTo` to another route to implicitly + abort the `transition`. You can return a promise from this hook to pause the transition until the promise resolves (or rejects). This could - be useful, for instance, for retrieving async code from - the server that is required to enter a route. + be useful, for instance, for retrieving async code from + the server that is required to enter a route. ```js App.PostRoute = Ember.Route.extend({ @@ -26536,13 +26608,13 @@ Ember.Route = Ember.Object.extend({ }); ``` - If `App.Post` doesn't exist in the above example, + If `App.Post` doesn't exist in the above example, `beforeModel` will use jQuery's `getScript`, which returns a promise that resolves after the server has successfully retrieved and executed the code from the - server. Note that if an error were to occur, it would - be passed to the `error` hook on `Ember.Route`, but - it's also possible to handle errors specific to + server. Note that if an error were to occur, it would + be passed to the `error` hook on `Ember.Route`, but + it's also possible to handle errors specific to `beforeModel` right from within the hook (to distinguish from the shared error handling behavior of the `error` hook): @@ -26557,11 +26629,11 @@ Ember.Route = Ember.Object.extend({ // Note that the above transitionTo will implicitly // halt the transition. If you were to return - // nothing from this promise reject handler, + // nothing from this promise reject handler, // according to promise semantics, that would - // convert the reject into a resolve and the + // convert the reject into a resolve and the // transition would continue. To propagate the - // error so that it'd be handled by the `error` + // error so that it'd be handled by the `error` // hook, you would have to either return Ember.RSVP.reject(e); // or @@ -26573,18 +26645,18 @@ Ember.Route = Ember.Object.extend({ ``` @method beforeModel - @param {Transition} transition + @param {Transition} transition @return {Promise} if the value returned from this hook is a promise, the transition will pause until the transition - resolves. Otherwise, non-promise return values are not + resolves. Otherwise, non-promise return values are not utilized in any way. */ beforeModel: Ember.K, /** This hook is called after this route's model has resolved. - It follows identical async/promise semantics to `beforeModel` - but is provided the route's resolved model in addition to + It follows identical async/promise semantics to `beforeModel` + but is provided the route's resolved model in addition to the `transition`, and is therefore suited to performing logic that can only take place after the model has already resolved. @@ -26601,13 +26673,13 @@ Ember.Route = Ember.Object.extend({ Refer to documentation for `beforeModel` for a description of transition-pausing semantics when a promise is returned - from this hook. + from this hook. @method afterModel - @param {Transition} transition + @param {Transition} transition @return {Promise} if the value returned from this hook is a promise, the transition will pause until the transition - resolves. Otherwise, non-promise return values are not + resolves. Otherwise, non-promise return values are not utilized in any way. */ afterModel: function(resolvedModel, transition) { @@ -26654,7 +26726,7 @@ Ember.Route = Ember.Object.extend({ This hook follows the asynchronous/promise semantics described in the documentation for `beforeModel`. In particular, - if a promise returned from `model` fails, the error will be + if a promise returned from `model` fails, the error will be handled by the `error` hook on `Ember.Route`. @method model @@ -26782,28 +26854,41 @@ Ember.Route = Ember.Object.extend({ }); ``` - By default, the controller for `post` is the shared instance of - `App.PostController`. - @method controllerFor @param {String} name the name of the route - @param {Object} model the model associated with the route (optional) @return {Ember.Controller} */ - controllerFor: function(name, model) { + controllerFor: function(name, _skipAssert) { var container = this.router.container, controller = container.lookup('controller:' + name); - if (!controller) { - model = model || this.modelFor(name); + // NOTE: We're specifically checking that skipAssert is true, because according + // to the old API the second parameter was model. We do not want people who + // passed a model to skip the assertion. - controller = Ember.generateController(container, name, model); - } - return controller; }, + /** + Generates a controller for a route. + + If the optional model is passed then the controller type is determined automatically, + e.g., an ArrayController for arrays. + + @method generateController + @param {String} name the name of the controller + @param {Object} model the model to infer the type of the controller (optional) + */ + generateController: function(name, model) { + var container = this.router.container; + + model = model || this.modelFor(name); + + + return Ember.generateController(container, name, model); + }, + /** Returns the current model for a given route. @@ -26903,6 +26988,8 @@ Ember.Route = Ember.Object.extend({ render: function(name, options) { + var namePassed = !!name; + if (typeof name === 'object' && !options) { options = name; name = this.routeName; @@ -26915,6 +27002,7 @@ Ember.Route = Ember.Object.extend({ template = container.lookup('template:' + name); if (!view && !template) { + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); } @@ -26974,17 +27062,17 @@ Ember.Route = Ember.Object.extend({ willDestroy: function() { this.teardownViews(); }, - + teardownViews: function() { // Tear down the top level view if (this.teardownTopLevelView) { this.teardownTopLevelView(); } - + // Tear down any outlets rendered with 'into' var teardownOutletViews = this.teardownOutletViews || []; - a_forEach(teardownOutletViews, function(teardownOutletView) { + a_forEach(teardownOutletViews, function(teardownOutletView) { teardownOutletView(); }); - + delete this.teardownTopLevelView; delete this.teardownOutletViews; delete this.lastRenderedTemplate; @@ -27005,16 +27093,15 @@ function parentRoute(route) { } } -function parentTemplate(route, isRecursive) { +function parentTemplate(route) { var parent = parentRoute(route), template; if (!parent) { return; } - if (template = parent.lastRenderedTemplate) { return template; } else { - return parentTemplate(parent, true); + return parentTemplate(parent); } } @@ -27175,7 +27262,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { `Ember.LinkView` renders an element whose `click` event triggers a transition of the application's instance of `Ember.Router` to a supplied route by name. - + Instances of `LinkView` will most likely be created through the `linkTo` Handlebars helper, but properties of this class can be overridden to customize application-wide behavior. @@ -27221,7 +27308,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** The CSS class to apply to a `LinkView`'s element when its `disabled` property is `true`. - + @property disabledClass @type String @default disabled @@ -27231,8 +27318,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** Determines whether the `LinkView` will trigger routing via - the `replaceWith` routing strategy. + the `replaceWith` routing strategy. + @property replace @type Boolean @default false **/ @@ -27243,7 +27331,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** By default the `{{linkTo}}` helper responds to the `click` event. You can override this globally by setting this property to your custom - event name. + event name. This is particularly useful on mobile when one wants to avoid the 300ms click delay using some sort of custom `tap` event. @@ -27286,15 +27374,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { } var observer = function(object, path) { - var notify = true, i; - for(i=0; i < paths.length; i++) { - if (!get(this, paths[i])) { - notify = false; - } - } - if (notify) { - this.notifyPropertyChange('routeArgs'); - } + this.notifyPropertyChange('routeArgs'); }; for(i=0; i < length; i++) { @@ -27304,10 +27384,10 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** @private - + Even though this isn't a virtual view, we want to treat it as if it is so that you can access the parent with {{view.prop}} - + @method concreteView **/ concreteView: Ember.computed(function() { @@ -27315,16 +27395,16 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { }).property('parentView'), /** - + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` CSS `class` to the element when the link is disabled. - + When `true` interactions with the element will not trigger route changes. @property disabled */ disabled: Ember.computed(function(key, value) { if (value !== undefined) { this.set('_isDisabled', value); } - + return value ? this.get('disabledClass') : false; }), @@ -27381,12 +27461,12 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { event.preventDefault(); if (this.bubbles === false) { event.stopPropagation(); } - + if (get(this, '_isDisabled')) { return false; } - if (get(this, 'loading')) { - Ember.Logger.warn("This linkTo's parameters are either not yet loaded or point to an invalid route."); - return false; + if (get(this, 'loading')) { + Ember.Logger.warn("This linkTo is in an inactive loading state because at least one of its parameters' presently has a null/undefined value, or the provided route name is invalid."); + return false; } var router = get(this, 'router'), @@ -27401,7 +27481,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { routeArgs: Ember.computed(function() { - var router = get(this, 'router'), + var router = get(this, 'router'), namedRoute = get(this, 'namedRoute'), routeName; if (!namedRoute && this.namedRouteBinding) { @@ -27490,7 +27570,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { </li> ``` - To override this option for your entire application, see + To override this option for your entire application, see "Overriding Application-wide Defaults". ### Handling `href` @@ -27537,7 +27617,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { </a> ``` - To override this option for your entire application, see + To override this option for your entire application, see "Overriding Application-wide Defaults". ### Supplying a model @@ -27624,7 +27704,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { params = [].slice.call(arguments, 1, -1); var hash = options.hash; - + if (options.types[0] === "ID") { if (Ember.ENV.HELPER_PARAM_LOOKUPS) { hash.namedRouteBinding = name; @@ -27819,7 +27899,8 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { controller = container.lookup('controller:' + controllerName, lookupOptions); } else { - controller = Ember.controllerFor(container, name, context, lookupOptions); + controller = container.lookup('controller:' + name, lookupOptions) || + Ember.generateController(container, name, context); } if (controller && context) { @@ -30051,11 +30132,11 @@ Ember.ControllerMixin.reopen({ needs: ['post'] }); ``` - + The application's single instance of these other controllers are accessible by name through the `controllers` property: - + ```javascript this.get('controllers.post'); // instance of App.PostController ``` @@ -30078,8 +30159,7 @@ Ember.ControllerMixin.reopen({ controllerFor: function(controllerName) { - var container = get(this, 'container'); - return container.lookup('controller:' + controllerName); + return Ember.controllerFor(get(this, 'container'), controllerName); }, controllers: Ember.computed(function() {