dist/ember-runtime.js in ember-source-1.6.0.beta.4 vs dist/ember-runtime.js in ember-source-1.6.0.beta.5

- old
+ new

@@ -3,11 +3,11 @@ * @copyright Copyright 2011-2014 Tilde Inc. and contributors * Portions Copyright 2006-2011 Strobe Inc. * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.6.0-beta.4 + * @version 1.6.0-beta.5 */ (function() { var define, requireModule, require, requirejs, Ember; @@ -1679,10 +1679,11 @@ todoList.get('done'); // false todoList.get('todos').clear(); todoList.get('done'); // true ``` + @since 1.6.0 @method computed.empty @for Ember @param {String} dependentKey @return {Ember.ComputedProperty} computed property which negate the original value for property @@ -2170,11 +2171,11 @@ */ computed.alias = function(dependentKey) { return computed(dependentKey, function(key, value) { if (arguments.length > 1) { set(this, dependentKey, value); - return value; + return get(this, dependentKey); } else { return get(this, dependentKey); } }); }; @@ -2323,11 +2324,11 @@ The core Runtime framework is based on the jQuery API with a number of performance optimizations. @class Ember @static - @version 1.6.0-beta.4 + @version 1.6.0-beta.5 */ if ('undefined' === typeof Ember) { // Create core object. Make it act like an instance of Ember.Namespace so that // objects assigned to it are given a sane string representation. @@ -2350,14 +2351,14 @@ /** @property VERSION @type String - @default '1.6.0-beta.4' + @default '1.6.0-beta.5' @static */ - Ember.VERSION = '1.6.0-beta.4'; + Ember.VERSION = '1.6.0-beta.5'; /** Standard environmental variables. You can define these in a global `EmberENV` variable before loading Ember to control various configuration settings. @@ -2438,11 +2439,11 @@ // .......................................................... // BOOTSTRAP // /** - Determines whether Ember should enhances some built-in object prototypes to + Determines whether Ember should enhance some built-in object prototypes to provide a more friendly API. If enabled, a few methods will be added to `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, which is the one that causes most trouble for people. In general we recommend leaving this option set to true since it rarely @@ -3214,28 +3215,29 @@ __exports__.listenersFor = listenersFor; __exports__.listenersDiff = listenersDiff; __exports__.listenersUnion = listenersUnion; }); define("ember-metal/expand_properties", - ["ember-metal/enumerable_utils","exports"], - function(__dependency1__, __exports__) { + ["ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var EnumerableUtils = __dependency1__["default"]; + var EmberError = __dependency1__["default"]; + var EnumerableUtils = __dependency2__["default"]; /** @module ember-metal */ var forEach = EnumerableUtils.forEach, - BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; + BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; /** Expands `pattern`, invoking `callback` for each expansion. The only pattern supported is brace-expansion, anything else will be passed once to `callback` directly. Brace expansion can only appear at the end of a - pattern, for example as the last item in a chain. + pattern, for an example see the last call below. Example ```js function echo(arg){ console.log(arg); } @@ -3252,16 +3254,21 @@ expansion, and is passed the expansion. */ function expandProperties(pattern, callback) { var match, prefix, list; + if (pattern.indexOf(' ') > -1) { + throw new EmberError('Brace expanded properties cannot contain spaces, ' + + 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); + } + if (match = BRACE_EXPANSION.exec(pattern)) { prefix = match[1]; list = match[2]; forEach(list.split(','), function (suffix) { - callback(prefix + suffix); + callback(prefix + suffix); }); } else { callback(pattern); } }; @@ -6920,38 +6927,41 @@ return apply(backburner, backburner.debounce, arguments); }; /** Ensure that the target method is never called more frequently than - the specified spacing period. + the specified spacing period. The target method is called immediately. ```javascript var myFunc = function() { console.log(this.name + ' ran.'); }; var myContext = {name: 'throttle'}; run.throttle(myContext, myFunc, 150); // myFunc is invoked with context myContext + // console logs 'throttle ran.' // 50ms passes run.throttle(myContext, myFunc, 150); // 50ms passes run.throttle(myContext, myFunc, 150); // 150ms passes run.throttle(myContext, myFunc, 150); // myFunc is invoked with context myContext - // console logs 'throttle ran.' twice, 250ms apart. + // console logs 'throttle ran.' ``` @method throttle @param {Object} [target] target of method to invoke @param {Function|String} method The method to invoke. May be a function or a string. If you pass a string then it will be looked up on the passed target. @param {Object} [args*] Optional arguments to pass to the timeout. @param {Number} spacing Number of milliseconds to space out requests. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to true. @return {Array} Timer information for use in cancelling, see `run.cancel`. */ run.throttle = function() { return apply(backburner, backburner.throttle, arguments); }; @@ -7398,11 +7408,11 @@ @param {Object} obj The object to test @return {Boolean} true if the passed object is an array or Array-like */ // ES6TODO: Move up to runtime? This is only use in ember-metal by concatenatedProperties function isArray(obj) { - var modulePath; + var modulePath, type; if (typeof EmberArray === "undefined") { modulePath = 'ember-runtime/mixins/array'; if (requirejs._eak_seen[modulePath]) { EmberArray = requireModule(modulePath)['default']; @@ -7410,11 +7420,14 @@ } if (!obj || obj.setInterval) { return false; } if (Array.isArray && Array.isArray(obj)) { return true; } if (EmberArray && EmberArray.detect(obj)) { return true; } - if ((obj.length !== undefined) && 'object'=== typeOf(obj)) { return true; } + + type = typeOf(obj); + if ('array' === type) { return true; } + if ((obj.length !== undefined) && 'object' === type) { return true; } return false; }; /** Forces the passed object to be part of an array. If the object is already @@ -7815,22 +7828,24 @@ __exports__.tryFinally = tryFinally; __exports__.wrap = wrap; __exports__.applyStr = applyStr; __exports__.apply = apply; }); -define("backburner", - ["backburner/deferred_action_queues","exports"], - function(__dependency1__, __exports__) { +define("backburner", + ["backburner/utils","backburner/deferred_action_queues","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var DeferredActionQueues = __dependency1__.DeferredActionQueues; + var Utils = __dependency1__["default"]; + var DeferredActionQueues = __dependency2__.DeferredActionQueues; var slice = [].slice, pop = [].pop, - throttlers = [], - debouncees = [], + each = Utils.each, + isString = Utils.isString, + isFunction = Utils.isFunction, + isNumber = Utils.isNumber, timers = [], - autorun, laterTimer, laterTimerExpiresAt, global = this, NUMBER = /\d+/; // In IE 6-8, try/finally doesn't work without a catch. // Unfortunately, this is impossible to test for since wrapping it in a parent try/catch doesn't trigger the bug. @@ -7840,20 +7855,22 @@ catch(e) { } // jshint ignore:line return !!e; })(); function isCoercableNumber(number) { - return typeof number === 'number' || NUMBER.test(number); + return isNumber(number) || NUMBER.test(number); } function Backburner(queueNames, options) { this.queueNames = queueNames; this.options = options || {}; if (!this.options.defaultQueue) { this.options.defaultQueue = queueNames[0]; } this.instanceStack = []; + this._debouncees = []; + this._throttlers = []; } Backburner.prototype = { queueNames: null, options: null, @@ -7903,25 +7920,23 @@ } } }, run: function(target, method /*, args */) { - var options = this.options, - ret, length = arguments.length; + var onError = getOnError(this.options); this.begin(); if (!method) { method = target; target = null; } - if (typeof method === 'string') { + if (isString(method)) { method = target[method]; } - var onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); var args = slice.call(arguments, 2); // guard against Safari 6's double-finally bug var didFinally = false; @@ -7952,11 +7967,11 @@ if (!method) { method = target; target = null; } - if (typeof method === 'string') { + if (isString(method)) { method = target[method]; } var stack = this.DEBUG ? new Error() : undefined, args = arguments.length > 3 ? slice.call(arguments, 3) : undefined; @@ -7968,38 +7983,36 @@ if (!method) { method = target; target = null; } - if (typeof method === 'string') { + if (isString(method)) { method = target[method]; } var stack = this.DEBUG ? new Error() : undefined, args = arguments.length > 3 ? slice.call(arguments, 3) : undefined; if (!this.currentInstance) { createAutorun(this); } return this.currentInstance.schedule(queueName, target, method, args, true, stack); }, setTimeout: function() { - var args = slice.call(arguments); - var length = args.length; - var method, wait, target; - var self = this; - var methodOrTarget, methodOrWait, methodOrArgs; - var options = this.options; + var args = slice.call(arguments), + length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; if (length === 0) { return; } else if (length === 1) { method = args.shift(); wait = 0; } else if (length === 2) { methodOrTarget = args[0]; methodOrWait = args[1]; - if (typeof methodOrWait === 'function' || typeof methodOrTarget[methodOrWait] === 'function') { + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { target = args.shift(); method = args.shift(); wait = 0; } else if (isCoercableNumber(methodOrWait)) { method = args.shift(); @@ -8018,27 +8031,27 @@ } methodOrTarget = args[0]; methodOrArgs = args[1]; - if (typeof methodOrArgs === 'function' || (typeof methodOrArgs === 'string' && - methodOrTarget !== null && - methodOrArgs in methodOrTarget)) { + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { target = args.shift(); method = args.shift(); } else { method = args.shift(); } } var executeAt = (+new Date()) + parseInt(wait, 10); - if (typeof method === 'string') { + if (isString(method)) { method = target[method]; } - var onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + var onError = getOnError(this.options); function fn() { if (onError) { try { method.apply(target, args); @@ -8053,11 +8066,11 @@ // find position to insert var i = searchTimer(executeAt, timers); timers.splice(i, 0, executeAt, fn); - updateLaterTimer(self, executeAt, wait); + updateLaterTimer(this, executeAt, wait); return fn; }, throttle: function(target, method /* , args, wait, [immediate] */) { @@ -8067,37 +8080,39 @@ wait, throttler, index, timer; - if (typeof immediate === "number" || typeof immediate === "string") { + if (isNumber(immediate) || isString(immediate)) { wait = immediate; immediate = true; } else { wait = pop.call(args); } wait = parseInt(wait, 10); - index = findThrottler(target, method); - if (index > -1) { return throttlers[index]; } // throttled + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled timer = global.setTimeout(function() { if (!immediate) { self.run.apply(self, args); } - var index = findThrottler(target, method); - if (index > -1) { throttlers.splice(index, 1); } + var index = findThrottler(target, method, self._throttlers); + if (index > -1) { + self._throttlers.splice(index, 1); + } }, wait); if (immediate) { self.run.apply(self, args); } throttler = [target, method, timer]; - throttlers.push(throttler); + this._throttlers.push(throttler); return throttler; }, debounce: function(target, method /* , args, wait, [immediate] */) { @@ -8107,75 +8122,73 @@ wait, index, debouncee, timer; - if (typeof immediate === "number" || typeof immediate === "string") { + if (isNumber(immediate) || isString(immediate)) { wait = immediate; immediate = false; } else { wait = pop.call(args); } wait = parseInt(wait, 10); // Remove debouncee - index = findDebouncee(target, method); + index = findDebouncee(target, method, this._debouncees); if (index > -1) { - debouncee = debouncees[index]; - debouncees.splice(index, 1); + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); clearTimeout(debouncee[2]); } timer = global.setTimeout(function() { if (!immediate) { self.run.apply(self, args); } - var index = findDebouncee(target, method); + var index = findDebouncee(target, method, self._debouncees); if (index > -1) { - debouncees.splice(index, 1); + self._debouncees.splice(index, 1); } }, wait); if (immediate && index === -1) { self.run.apply(self, args); } debouncee = [target, method, timer]; - debouncees.push(debouncee); + self._debouncees.push(debouncee); return debouncee; }, cancelTimers: function() { - var i, len; + var clearItems = function(item) { + clearTimeout(item[2]); + }; - for (i = 0, len = throttlers.length; i < len; i++) { - clearTimeout(throttlers[i][2]); - } - throttlers = []; + each(this._throttlers, clearItems); + this._throttlers = []; - for (i = 0, len = debouncees.length; i < len; i++) { - clearTimeout(debouncees[i][2]); - } - debouncees = []; + each(this._debouncees, clearItems); + this._debouncees = []; - if (laterTimer) { - clearTimeout(laterTimer); - laterTimer = null; + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; } timers = []; - if (autorun) { - clearTimeout(autorun); - autorun = null; + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; } }, hasTimers: function() { - return !!timers.length || !!debouncees.length || !!throttlers.length || autorun; + return !!timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; }, cancel: function(timer) { var timerType = typeof timer; @@ -8187,12 +8200,12 @@ timers.splice(i, 2); // remove the two elements return true; } } } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce - return this._cancelItem(findThrottler, throttlers, timer) || - this._cancelItem(findDebouncee, debouncees, timer); + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); } else { return; // timer was null or not a timer } }, @@ -8200,11 +8213,11 @@ var item, index; if (timer.length < 3) { return false; } - index = findMethod(timer[0], timer[1]); + index = findMethod(timer[0], timer[1], array); if(index > -1) { item = array[index]; @@ -8223,48 +8236,47 @@ Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; Backburner.prototype.later = Backburner.prototype.setTimeout; if (needsIETryCatchFix) { var originalRun = Backburner.prototype.run; - Backburner.prototype.run = function() { - try { - originalRun.apply(this, arguments); - } catch (e) { - throw e; - } - }; + Backburner.prototype.run = wrapInTryCatch(originalRun); var originalEnd = Backburner.prototype.end; - Backburner.prototype.end = function() { + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function wrapInTryCatch(func) { + return function () { try { - originalEnd.apply(this, arguments); + return func.apply(this, arguments); } catch (e) { throw e; } }; } + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + function createAutorun(backburner) { backburner.begin(); - autorun = global.setTimeout(function() { - autorun = null; + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; backburner.end(); }); } function updateLaterTimer(self, executeAt, wait) { - if (!laterTimer || executeAt < laterTimerExpiresAt) { - if (laterTimer) { - clearTimeout(laterTimer); - } - laterTimer = global.setTimeout(function() { - laterTimer = null; - laterTimerExpiresAt = null; + if (!self._laterTimer || executeAt < self._laterTimerExpiresAt) { + self._laterTimer = global.setTimeout(function() { + self._laterTimer = null; + self._laterTimerExpiresAt = null; executeTimers(self); }, wait); - laterTimerExpiresAt = executeAt; + self._laterTimerExpiresAt = executeAt; } } function executeTimers(self) { var now = +new Date(), @@ -8283,32 +8295,25 @@ if (timers.length) { updateLaterTimer(self, timers[0], timers[0] - now); } } - function findDebouncee(target, method) { - var debouncee, - index = -1; + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } - for (var i = 0, l = debouncees.length; i < l; i++) { - debouncee = debouncees[i]; - if (debouncee[0] === target && debouncee[1] === method) { - index = i; - break; - } - } - - return index; + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); } - function findThrottler(target, method) { - var throttler, + function findItem(target, method, collection) { + var item, index = -1; - for (var i = 0, l = throttlers.length; i < l; i++) { - throttler = throttlers[i]; - if (throttler[0] === target && throttler[1] === method) { + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { index = i; break; } } @@ -8339,27 +8344,29 @@ return (time >= timers[start]) ? start + 2 : start; } __exports__.Backburner = Backburner; }); -define("backburner/deferred_action_queues", - ["backburner/queue","exports"], - function(__dependency1__, __exports__) { +define("backburner/deferred_action_queues", + ["backburner/utils","backburner/queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var Queue = __dependency1__.Queue; + var Utils = __dependency1__["default"]; + var Queue = __dependency2__.Queue; + var each = Utils.each, + isString = Utils.isString; + function DeferredActionQueues(queueNames, options) { var queues = this.queues = {}; this.queueNames = queueNames = queueNames || []; this.options = options; - var queueName; - for (var i = 0, l = queueNames.length; i < l; i++) { - queueName = queueNames[i]; - queues[queueName] = new Queue(this, queueName, this.options); - } + each(queueNames, function(queueName) { + queues[queueName] = new Queue(this, queueName, options); + }); } DeferredActionQueues.prototype = { queueNames: null, queues: null, @@ -8426,11 +8433,11 @@ target = queueItems[queueIndex]; method = queueItems[queueIndex+1]; args = queueItems[queueIndex+2]; stack = queueItems[queueIndex+3]; // Debugging assistance - if (typeof method === 'string') { method = target[method]; } + if (isString(method)) { method = target[method]; } // method could have been nullified / canceled during flush if (method) { invoke(target, method, args, onError); } @@ -8463,11 +8470,11 @@ return -1; } __exports__.DeferredActionQueues = DeferredActionQueues; }); -define("backburner/queue", +define("backburner/queue", ["exports"], function(__exports__) { "use strict"; function Queue(daq, name, options) { this.daq = daq; @@ -8502,11 +8509,11 @@ queue[i+3] = stack; // replace stack return {queue: this, target: target, method: method}; } } - this._queue.push(target, method, args, stack); + queue.push(target, method, args, stack); return {queue: this, target: target, method: method}; }, // TODO: remove me, only being used for Ember.run.sync flush: function() { @@ -8592,10 +8599,35 @@ } }; __exports__.Queue = Queue; }); +define("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = { + each: function(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + }, + + isString: function(suspect) { + return typeof suspect === 'string'; + }, + + isFunction: function(suspect) { + return typeof suspect === 'function'; + }, + + isNumber: function(suspect) { + return typeof suspect === 'number'; + } + }; + }); + define("ember-metal/watch_key", ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var Ember = __dependency1__["default"]; @@ -14131,11 +14163,11 @@ }, init: function() { this._super(); - this.set('_subControllers', Ember.A()); + this.set('_subControllers', [ ]); }, content: computed(function () { return Ember.A(); }), @@ -14181,17 +14213,27 @@ _subControllers: null, _resetSubControllers: function() { var subControllers = get(this, '_subControllers'); - if (subControllers) { - forEach(subControllers, function(subController) { - if (subController) { subController.destroy(); } - }); + var controller; + + if (subControllers.length) { + for (var i = 0, length = subControllers.length; length > i; i++) { + controller = subControllers[i]; + if (controller) { + controller.destroy(); + } + } + + subControllers.length = 0; } + }, - this.set('_subControllers', Ember.A()); + willDestroy: function() { + this._resetSubControllers(); + this._super(); } }); __exports__["default"] = ArrayController; }); @@ -17647,10 +17689,12 @@ @param {Ember.Enumerable} objects the objects to remove @return {Object} receiver */ removeObjects: function(objects) { beginPropertyChanges(this); - forEach(objects, function(obj) { this.removeObject(obj); }, this); + for (var i = objects.length - 1; i >= 0; i--) { + this.removeObject(objects[i]); + } endPropertyChanges(this); return this; } });