dist/ember-runtime.js in ember-source-1.0.0.rc5.1 vs dist/ember-runtime.js in ember-source-1.0.0.rc6

- old
+ new

@@ -1,7 +1,7 @@ -// Version: v1.0.0-rc.5-2-g9dc4ad8 -// Last commit: 9dc4ad8 (2013-07-25 20:19:21 -0400) +// Version: v1.0.0-rc.6-1-g42f0c68 +// Last commit: 42f0c68 (2013-06-23 15:43:35 -0400) (function() { /*global __fail__*/ @@ -47,11 +47,16 @@ the text of the Error thrown if the assertion fails. @param {Boolean} test Must be truthy for the assertion to pass. If falsy, an exception will be thrown. */ Ember.assert = function(desc, test) { - if (!test) throw new Error("assertion failed: "+desc); + Ember.Logger.assert(test, desc); + + if (Ember.testing && !test) { + // when testing, ensure test failures when assertions fail + throw new Error("Assertion Failed: " + desc); + } }; /** Display a warning with the provided message. Ember build tools will @@ -93,16 +98,16 @@ @param {String} message A description of the deprecation. @param {Boolean} test An optional boolean. If falsy, the deprecation will be displayed. */ Ember.deprecate = function(message, test) { - if (Ember && Ember.TESTING_DEPRECATION) { return; } + if (Ember.TESTING_DEPRECATION) { return; } if (arguments.length === 1) { test = false; } if (test) { return; } - if (Ember && Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); } + if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); } var error; // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome try { __fail__.fail(); } catch (e) { error = e; } @@ -149,12 +154,12 @@ }; }; })(); -// Version: v1.0.0-rc.5-2-g9dc4ad8 -// Last commit: 9dc4ad8 (2013-07-25 20:19:21 -0400) +// Version: v1.0.0-rc.6-1-g42f0c68 +// Last commit: 42f0c68 (2013-06-23 15:43:35 -0400) (function() { var define, requireModule; @@ -217,11 +222,11 @@ The core Runtime framework is based on the jQuery API with a number of performance optimizations. @class Ember @static - @version 1.0.0-rc.5 + @version 1.0.0-rc.6 */ 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. @@ -244,14 +249,14 @@ /** @property VERSION @type String - @default '1.0.0-rc.5' + @default '1.0.0-rc.6' @final */ -Ember.VERSION = '1.0.0-rc.5'; +Ember.VERSION = '1.0.0-rc.6'; /** Standard environmental variables. You can define these in a global `ENV` variable before loading Ember to control various configuration settings. @@ -362,10 +367,23 @@ }; } } } +function assertPolyfill(test, message) { + if (!test) { + try { + // attempt to preserve the stack + throw new Error("assertion failed: " + message); + } catch(error) { + setTimeout(function(){ + throw error; + }, 0); + } + } +} + /** Inside Ember-Metal, simply uses the methods from `imports.console`. Override this to provide more robust logging functionality. @class Logger @@ -374,11 +392,12 @@ Ember.Logger = { log: consoleMethod('log') || Ember.K, warn: consoleMethod('warn') || Ember.K, error: consoleMethod('error') || Ember.K, info: consoleMethod('info') || Ember.K, - debug: consoleMethod('debug') || consoleMethod('info') || Ember.K + debug: consoleMethod('debug') || consoleMethod('info') || Ember.K, + assert: consoleMethod('assert') || assertPolyfill }; // .......................................................... // ERROR HANDLING @@ -1642,10 +1661,11 @@ if (!keyName && 'string'===typeof obj) { keyName = obj; obj = null; } + Ember.assert("Cannot call get with "+ keyName +" key.", !!keyName); Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined); if (obj === null || keyName.indexOf('.') !== -1) { return getPath(obj, keyName); } @@ -1674,34 +1694,43 @@ Ember.get = get; Ember.config.overrideAccessors(); get = Ember.get; } -function firstKey(path) { - return path.match(FIRST_KEY)[0]; -} +/** + @private -// assumes path is already normalized -function normalizeTuple(target, path) { + Normalizes a target/path pair to reflect that actual target/path that should + be observed, etc. This takes into account passing in global property + paths (i.e. a path beginning with a captial letter not defined on the + target) and * separators. + + @method normalizeTuple + @for Ember + @param {Object} target The current target. May be `null`. + @param {String} path A path on the target or a global property path. + @return {Array} a temporary array with the normalized target/path pair. +*/ +var normalizeTuple = Ember.normalizeTuple = function(target, path) { var hasThis = HAS_THIS.test(path), isGlobal = !hasThis && IS_GLOBAL_PATH.test(path), key; if (!target || isGlobal) target = Ember.lookup; if (hasThis) path = path.slice(5); if (target === Ember.lookup) { - key = firstKey(path); + key = path.match(FIRST_KEY)[0]; target = get(target, key); path = path.slice(key.length+1); } // must return some kind of path to be valid else other things will break. if (!path || path.length===0) throw new Error('Invalid Path'); return [ target, path ]; -} +}; var getPath = Ember._getPath = function(root, path) { var hasThis, parts, tuple, idx, len; // If there is no root and path is a key name, return that @@ -1726,28 +1755,10 @@ if (root && root.isDestroyed) { return undefined; } } return root; }; -/** - @private - - Normalizes a target/path pair to reflect that actual target/path that should - be observed, etc. This takes into account passing in global property - paths (i.e. a path beginning with a captial letter not defined on the - target) and * separators. - - @method normalizeTuple - @for Ember - @param {Object} target The current target. May be `null`. - @param {String} path A path on the target or a global property path. - @return {Array} a temporary array with the normalized target/path pair. -*/ -Ember.normalizeTuple = function(target, path) { - return normalizeTuple(target, path); -}; - Ember.getWithDefault = function(root, key, defaultValue) { var value = get(root, key); if (value === undefined) { return defaultValue; } return value; @@ -2463,10 +2474,12 @@ value = keyName; keyName = obj; obj = null; } + Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName); + if (!obj || keyName.indexOf('.') !== -1) { return setPath(obj, keyName, value, tolerant); } Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined); @@ -3114,13 +3127,13 @@ Set a list of properties on an object. These properties are set inside a single `beginPropertyChanges` and `endPropertyChanges` batch, so observers will be buffered. @method setProperties - @param target - @param {Hash} properties - @return target + @param self + @param {Object} hash + @return self */ Ember.setProperties = function(self, hash) { changeProperties(function(){ for(var prop in hash) { if (hash.hasOwnProperty(prop)) { set(self, prop, hash[prop]); } @@ -4756,19 +4769,21 @@ hasTimers: function() { return !!timers.length || autorun; }, cancel: function(timer) { - if (typeof timer === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + if (timer && typeof timer === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce return timer.queue.cancel(timer); } else if (typeof timer === 'function') { // we're cancelling a setTimeout for (var i = 0, l = timers.length; i < l; i += 2) { if (timers[i + 1] === timer) { timers.splice(i, 2); // remove the two elements return true; } } + } else { + return; // timer was null or not a timer } } }; Backburner.prototype.schedule = Backburner.prototype.defer; @@ -4857,11 +4872,11 @@ outerloop: while (queueNameIndex < numberOfQueues) { queueName = queueNames[queueNameIndex]; queue = queues[queueName]; - queueItems = queue._queue.slice(); + queueItems = queue._queueBeingFlushed = queue._queue.slice(); queue._queue = []; var options = queue.options, before = options && options.before, after = options && options.after, @@ -4875,19 +4890,23 @@ args = queueItems[queueIndex+2]; stack = queueItems[queueIndex+3]; // Debugging assistance if (typeof method === 'string') { method = target[method]; } - // TODO: error handling - if (args && args.length > 0) { - method.apply(target, args); - } else { - method.call(target); + // method could have been nullified / canceled during flush + if (method) { + // TODO: error handling + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } } queueIndex += 4; } + queue._queueBeingFlushed = null; if (numberOfQueueItems && after) { after(); } if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { queueNameIndex = priorQueueNameIndex; continue outerloop; @@ -4908,10 +4927,11 @@ } return -1; } + __exports__.DeferredActionQueues = DeferredActionQueues; }); define("backburner/queue", ["exports"], @@ -4997,16 +5017,34 @@ if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { queue.splice(i, 4); return true; } } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } } }; + __exports__.Queue = Queue; }); - })(); (function() { @@ -5110,11 +5148,11 @@ @param {Object} [target] target of method to call @param {Function|String} method 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*] Any additional arguments you wish to pass to the method. - @return {Object} return value from invoking the passed function. Please note, + @return {Object} return value from invoking the passed function. Please note, when called within an existing loop, no return value is possible. */ Ember.run.join = function(target, method) { if (!Ember.run.currentRunLoop) { return Ember.run.apply(Ember.run, arguments); @@ -5246,11 +5284,13 @@ @method sync @return {void} */ Ember.run.sync = function() { - backburner.currentInstance.queues.sync.flush(); + if (backburner.currentInstance) { + backburner.currentInstance.queues.sync.flush(); + } }; /** Invokes the passed target/method and optional arguments after a specified period if time. The last parameter of this method must always be a number @@ -5439,10 +5479,42 @@ */ Ember.run.cancel = function(timer) { return backburner.cancel(timer); }; +/** + Execute the passed method in a specified amount of time, reset timer + upon additional calls. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + Ember.run.debounce(myContext, myFunc, 150); + + // less than 150ms passes + + Ember.run.debounce(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'debounce ran.' one time. + ``` + + @method debounce + @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} wait Number of milliseconds to wait. + @return {void} +*/ +Ember.run.debounce = function() { + return backburner.debounce.apply(backburner, arguments); +}; + // Make sure it's not an autorun during testing function checkAutoRun() { if (!Ember.run.currentRunLoop) { Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run", !Ember.testing); } @@ -7228,10 +7300,12 @@ __exports__.configure = configure; __exports__.resolve = resolve; __exports__.reject = reject; }); + + })(); (function() { define("container", [], @@ -7352,10 +7426,14 @@ } return value; }, + lookupFactory: function(fullName) { + return factoryFor(this, fullName); + }, + has: function(fullName) { if (this.cache.has(fullName)) { return true; } @@ -8072,12 +8150,12 @@ 'css-class-name'.capitalize() // 'Css-class-name' 'my favorite items'.capitalize() // 'My favorite items' ``` @method capitalize - @param {String} str - @return {String} + @param {String} str The string to capitalize. + @return {String} The capitalized string. */ capitalize: function(str) { return str.charAt(0).toUpperCase() + str.substr(1); } @@ -9446,19 +9524,19 @@ /** Adds an array observer to the receiving array. The array observer object normally must implement two methods: - * `arrayWillChange(start, removeCount, addCount)` - This method will be + * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be called just before the array is modified. - * `arrayDidChange(start, removeCount, addCount)` - This method will be + * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be called just after the array is modified. - Both callbacks will be passed the starting index of the change as well a - a count of the items to be removed and added. You can use these callbacks - to optionally inspect the array during the change, clear caches, or do - any other bookkeeping necessary. + Both callbacks will be passed the observed object, starting index of the + change as well a a count of the items to be removed and added. You can use + these callbacks to optionally inspect the array during the change, clear + caches, or do any other bookkeeping necessary. In addition to passing a target, you can also include an options hash which you can use to override the method names that will be invoked on the target. @@ -13462,20 +13540,43 @@ Specifies the arrangedContent's sort direction @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 + Array#sort, i.e. + return 0 if the two parameters are equal, + return a negative value if the first parameter is smaller than the second or + return a positive value otherwise: + ```javascript + function(x,y){ // These are assumed to be integers + if(x === y) + return 0; + return x < y ? -1 : 1; + } + ``` + + @property sortFunction + @type {Function} + @default Ember.compare + */ + sortFunction: Ember.compare, + orderBy: function(item1, item2) { var result = 0, sortProperties = get(this, 'sortProperties'), - sortAscending = get(this, 'sortAscending'); + sortAscending = get(this, 'sortAscending'), + sortFunction = get(this, 'sortFunction'); Ember.assert("you need to define `sortProperties`", !!sortProperties); forEach(sortProperties, function(propertyName) { if (result === 0) { - result = Ember.compare(get(item1, propertyName), get(item2, propertyName)); + result = sortFunction(get(item1, propertyName), get(item2, propertyName)); if ((result !== 0) && !sortAscending) { result = (-1) * result; } } });