dist/ember-runtime.js in ember-source-1.9.0.beta.1.1 vs dist/ember-runtime.js in ember-source-1.9.0.beta.3

- 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.9.0-beta.1 + * @version 1.9.0-beta.3 */ (function() { var define, requireModule, require, requirejs, Ember; @@ -191,10 +191,27 @@ } } } }, + join: function(target, method /*, args */) { + if (this.currentInstance) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + return method.apply(target, slice.call(arguments, 2)); + } else { + return this.run.apply(this, arguments); + } + }, + defer: function(queueName, target, method /* , args */) { if (!method) { method = target; target = null; } @@ -1177,24 +1194,10 @@ this.children.push(container); return container; }, /** - Sets a key-value pair on the current container. If a parent container, - has the same key, once set on a child, the parent and child will diverge - as expected. - - @method set - @param {Object} object - @param {String} key - @param {any} value - */ - set: function(object, key, value) { - object[key] = value; - }, - - /** Registers a factory for later injection. Example: ```javascript @@ -1445,15 +1448,17 @@ this._typeOptions[type] = options; }, /** @method options - @param {String} type + @param {String} fullName @param {Object} options */ - options: function(type, options) { - this.optionsForType(type, options); + options: function(fullName, options) { + options = options || {}; + var normalizedName = this.normalize(fullName); + this._options[normalizedName] = options; }, /** Used only via `injection`. @@ -2666,11 +2671,13 @@ // add an observer on the object to be notified when the binding should be updated addObserver(obj, fromPath, this, this.fromDidChange); // if the binding is a two-way binding, also set up an observer on the target - if (!this._oneWay) { addObserver(obj, toPath, this, this.toDidChange); } + if (!this._oneWay) { + addObserver(obj, toPath, this, this.toDidChange); + } this._readyToSync = true; return this; }, @@ -2691,11 +2698,13 @@ // remove an observer on the object so we're no longer notified of // changes that should update bindings. removeObserver(obj, this._from, this, this.fromDidChange); // if the binding is two-way, remove the observer from the target as well - if (twoWay) { removeObserver(obj, this._to, this, this.toDidChange); } + if (twoWay) { + removeObserver(obj, this._to, this, this.toDidChange); + } this._readyToSync = false; // disable scheduled syncs... return this; }, @@ -3077,11 +3086,13 @@ if (pendingQueue.length === 0) { return; } // nothing to do var queue = pendingQueue; pendingQueue = []; - forEach.call(queue, function(q) { q[0].add(q[1]); }); + forEach.call(queue, function(q) { + q[0].add(q[1]); + }); warn('Watching an undefined global, Ember expects watched globals to be' + ' setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); } @@ -3093,11 +3104,13 @@ if (!m.hasOwnProperty('chainWatchers')) { nodes = m.chainWatchers = {}; } - if (!nodes[keyName]) { nodes[keyName] = []; } + if (!nodes[keyName]) { + nodes[keyName] = []; + } nodes[keyName].push(node); watchKey(obj, keyName, m); } function removeChainWatcher(obj, keyName, node) { @@ -3137,11 +3150,13 @@ this._value = value; this._paths = {}; if (this._watching) { this._object = parent.value(); - if (this._object) { addChainWatcher(this._object, this._key, this); } + if (this._object) { + addChainWatcher(this._object, this._key, this); + } } // Special-case: the EachProxy relies on immediate evaluation to // establish its observers. // @@ -3157,13 +3172,17 @@ function lazyGet(obj, key) { if (!obj) return undefined; var meta = obj['__ember_meta__']; // check if object meant only to be a prototype - if (meta && meta.proto === obj) return undefined; + if (meta && meta.proto === obj) { + return undefined; + } - if (key === "@each") return get(obj, key); + if (key === "@each") { + return get(obj, key); + } // if a CP only return cached value var desc = meta && meta.descs[key]; if (desc && desc._cacheable) { if (key in meta.cache) { @@ -3185,11 +3204,13 @@ }; ChainNodePrototype.destroy = function() { if (this._watching) { var obj = this._object; - if (obj) { removeChainWatcher(obj, this._key, this); } + if (obj) { + removeChainWatcher(obj, this._key, this); + } this._watching = false; // so future calls do nothing } }; // copies a top level object only @@ -3197,11 +3218,14 @@ var ret = new ChainNode(null, null, obj); var paths = this._paths; var path; for (path in paths) { - if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + // this check will also catch non-number vals. + if (paths[path] <= 0) { + continue; + } ret.add(path); } return ret; }; @@ -3244,11 +3268,13 @@ // path ChainNodePrototype.remove = function(path) { var obj, tuple, key, src, paths; paths = this._paths; - if (paths[path] > 0) { paths[path]--; } + if (paths[path] > 0) { + paths[path]--; + } obj = this.value(); tuple = normalizeTuple(obj, path); if (tuple[0] === obj) { path = tuple[1]; @@ -3267,14 +3293,18 @@ ChainNodePrototype.count = 0; ChainNodePrototype.chain = function(key, path, src) { var chains = this._chains; var node; - if (!chains) { chains = this._chains = {}; } + if (!chains) { + chains = this._chains = {}; + } node = chains[key]; - if (!node) { node = chains[key] = new ChainNode(this, key, src); } + if (!node) { + node = chains[key] = new ChainNode(this, key, src); + } node.count++; // count chains... // chain rest of path if there is one if (path) { key = firstKey(path); @@ -3286,14 +3316,14 @@ ChainNodePrototype.unchain = function(key, path) { var chains = this._chains; var node = chains[key]; // unchain rest of path first... - if (path && path.length>1) { - key = firstKey(path); - path = path.slice(key.length+1); - node.unchain(key, path); + if (path && path.length > 1) { + var nextKey = firstKey(path); + var nextPath = path.slice(nextKey.length + 1); + node.unchain(nextKey, nextPath); } // delete node if needed. node.count--; if (node.count<=0) { @@ -3305,20 +3335,26 @@ ChainNodePrototype.willChange = function(events) { var chains = this._chains; if (chains) { for(var key in chains) { - if (!chains.hasOwnProperty(key)) { continue; } + if (!chains.hasOwnProperty(key)) { + continue; + } chains[key].willChange(events); } } - if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } + if (this._parent) { + this._parent.chainWillChange(this, this._key, 1, events); + } }; ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { - if (this._key) { path = this._key + '.' + path; } + if (this._key) { + path = this._key + '.' + path; + } if (this._parent) { this._parent.chainWillChange(this, path, depth+1, events); } else { if (depth > 1) { @@ -3330,11 +3366,14 @@ } } }; ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { - if (this._key) { path = this._key + '.' + path; } + if (this._key) { + path = this._key + '.' + path; + } + if (this._parent) { this._parent.chainDidChange(this, path, depth+1, events); } else { if (depth > 1) { events.push(this.value(), path); @@ -3357,12 +3396,13 @@ } this._value = undefined; // Special-case: the EachProxy relies on immediate evaluation to // establish its observers. - if (this._parent && this._parent._key === '@each') + if (this._parent && this._parent._key === '@each') { this.value(); + } } // then notify chains... var chains = this._chains; if (chains) { @@ -3371,26 +3411,34 @@ chains[key].didChange(events); } } // if no events are passed in then we only care about the above wiring update - if (events === null) { return; } + if (events === null) { + return; + } // and finally tell parent about my path changing... - if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } + if (this._parent) { + this._parent.chainDidChange(this, this._key, 1, events); + } }; function finishChains(obj) { // We only create meta if we really have to - var m = obj['__ember_meta__'], - chains, chainWatchers, chainNodes; + var m = obj['__ember_meta__']; + var chains, chainWatchers, chainNodes; + if (m) { // finish any current chains node watchers that reference obj chainWatchers = m.chainWatchers; if (chainWatchers) { for(var key in chainWatchers) { - if (!chainWatchers.hasOwnProperty(key)) { continue; } + if (!chainWatchers.hasOwnProperty(key)) { + continue; + } + chainNodes = chainWatchers[key]; if (chainNodes) { for (var i=0,l=chainNodes.length;i<l;i++) { chainNodes[i].didChange(null); } @@ -3439,22 +3487,22 @@ // .......................................................... // COMPUTED PROPERTY // /** - A computed property transforms an objects function into a property. + A computed property transforms an object's function into a property. By default the function backing the computed property will only be called once and the result will be cached. You can specify various properties - that your computed property is dependent on. This will force the cached + that your computed property depends on. This will force the cached result to be recomputed if the dependencies are modified. In the following example we declare a computed property (by calling - `.property()` on the fullName function) and setup the properties + `.property()` on the fullName function) and setup the property dependencies (depending on firstName and lastName). The fullName function will be called once (regardless of how many times it is accessed) as long - as it's dependencies have not been changed. Once firstName or lastName are updated + as its dependencies have not changed. Once firstName or lastName are updated any future calls (or anything bound) to fullName will incorporate the new values. ```javascript var Person = Ember.Object.extend({ @@ -3746,11 +3794,13 @@ } else { cache[keyName] = ret; } chainNodes = meta.chainWatchers && meta.chainWatchers[keyName]; - if (chainNodes) { finishChains(chainNodes); } + if (chainNodes) { + finishChains(chainNodes); + } addDependentKeys(this, obj, keyName, meta); } else { ret = this.func.call(obj, keyName); } return ret; @@ -3988,11 +4038,13 @@ function cacheFor(obj, key) { var meta = obj['__ember_meta__']; var cache = meta && meta.cache; var ret = cache && cache[key]; - if (ret === UNDEFINED) { return undefined; } + if (ret === UNDEFINED) { + return undefined; + } return ret; } cacheFor.set = function(cache, key, value) { if (value === undefined) { @@ -4002,11 +4054,13 @@ } }; cacheFor.get = function(cache, key) { var ret = cache[key]; - if (ret === UNDEFINED) { return undefined; } + if (ret === UNDEFINED) { + return undefined; + } return ret; }; cacheFor.remove = function(cache, key) { cache[key] = undefined; @@ -4747,11 +4801,11 @@ The core Runtime framework is based on the jQuery API with a number of performance optimizations. @class Ember @static - @version 1.9.0-beta.1 + @version 1.9.0-beta.3 */ 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. @@ -4774,14 +4828,14 @@ /** @property VERSION @type String - @default '1.9.0-beta.1' + @default '1.9.0-beta.3' @static */ - Ember.VERSION = '1.9.0-beta.1'; + Ember.VERSION = '1.9.0-beta.3'; /** Standard environmental variables. You can define these in a global `EmberENV` variable before loading Ember to control various configuration settings. @@ -4892,11 +4946,11 @@ @default true */ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); /** - Determines whether Ember should add ECMAScript 5 shims to older browsers. + Determines whether Ember should add ECMAScript 5 Array shims to older browsers. @property SHIM_ES5 @type Boolean @default Ember.EXTEND_PROTOTYPES */ @@ -6425,11 +6479,12 @@ return function keys(obj) { if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } - var result = [], prop, i; + var result = []; + var prop, i; for (prop in obj) { if (prop !== '_super' && prop.lastIndexOf('__',0) !== 0 && hasOwnProperty.call(obj, prop)) { @@ -6515,12 +6570,16 @@ } var method = typeof consoleObj === 'object' ? consoleObj[name] : null; if (method) { - // Older IE doesn't support apply, but Chrome needs it - if (typeof method.apply === 'function') { + // Older IE doesn't support bind, but Chrome needs it + if (typeof method.bind === 'function') { + logToConsole = method.bind(consoleObj); + logToConsole.displayName = 'console.' + name; + return logToConsole; + } else if (typeof method.apply === 'function') { logToConsole = function() { method.apply(consoleObj, arguments); }; logToConsole.displayName = 'console.' + name; return logToConsole; @@ -7209,11 +7268,10 @@ */ var Ember = __dependency1__["default"]; // warn, assert, wrap, et; var merge = __dependency2__["default"]; - var a_map = __dependency3__.map; var a_indexOf = __dependency3__.indexOf; var a_forEach = __dependency3__.forEach; var o_create = __dependency4__.create; var get = __dependency5__.get; var set = __dependency6__.set; @@ -7264,26 +7322,10 @@ ret = m.mixins = o_create(ret); } return ret; } - function initMixin(mixin, args) { - if (args && args.length > 0) { - mixin.mixins = a_map.call(args, function(x) { - if (x instanceof Mixin) { return x; } - - // Note: Manually setup a primitive mixin here. This is the only - // way to actually get a primitive mixin. This way normal creation - // of mixins will give you combined mixins... - var mixin = new Mixin(); - mixin.properties = x; - return mixin; - }); - } - return mixin; - } - function isMethod(obj) { return 'function' === typeof obj && obj.isMethod !== false && obj !== Boolean && obj !== Object && @@ -7726,17 +7768,34 @@ @class Mixin @namespace Ember */ __exports__["default"] = Mixin; - function Mixin() { return initMixin(this, arguments); } - Mixin.prototype = { - properties: null, - mixins: null, - ownerConstructor: null - }; + function Mixin(args, properties) { + this.properties = properties; + var length = args && args.length; + + if (length > 0) { + var m = new Array(length); + + for (var i = 0; i < length; i++) { + var x = args[i]; + if (x instanceof Mixin) { + m[i] = x; + } else { + m[i] = new Mixin(undefined, x); + } + } + + this.mixins = m; + } else { + this.mixins = undefined; + } + this.ownerConstructor = undefined; + } + Mixin._apply = applyMixin; Mixin.applyPartial = function(obj) { var args = a_slice.call(arguments, 1); return applyMixin(obj, args, true); @@ -7754,26 +7813,30 @@ */ Mixin.create = function() { // ES6TODO: this relies on a global state? Ember.anyUnprocessedMixins = true; var M = this; - return initMixin(new M(), arguments); + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + return new M(args, undefined); }; var MixinPrototype = Mixin.prototype; /** @method reopen @param arguments* */ MixinPrototype.reopen = function() { - var mixin, tmp; + var mixin; if (this.properties) { - mixin = Mixin.create(); - mixin.properties = this.properties; - delete this.properties; + mixin = new Mixin(undefined, this.properties); + this.properties = undefined; this.mixins = [mixin]; } else if (!this.mixins) { this.mixins = []; } @@ -7788,13 +7851,11 @@ Object.prototype.toString.call(mixin) !== '[object Array]'); if (mixin instanceof Mixin) { mixins.push(mixin); } else { - tmp = Mixin.create(); - tmp.properties = mixin; - mixins.push(tmp); + mixins.push(new Mixin(undefined, mixin)); } } return this; }; @@ -7842,11 +7903,11 @@ } return false; }; MixinPrototype.without = function() { - var ret = new Mixin(this); + var ret = new Mixin([this]); ret._without = a_slice.call(arguments); return ret; }; function _keys(ret, mixin, seen) { @@ -7867,11 +7928,13 @@ var keys = {}; var seen = {}; var ret = []; _keys(keys, this, seen); for(var key in keys) { - if (keys.hasOwnProperty(key)) { ret.push(key); } + if (keys.hasOwnProperty(key)) { + ret.push(key); + } } return ret; }; // returns the mixins currently applied to the specified object @@ -8825,13 +8888,22 @@ var m = obj['__ember_meta__']; var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; var proto = m && m.proto; var desc = m && m.descs[keyName]; - if (!watching) { return; } - if (proto === obj) { return; } - if (desc && desc.willChange) { desc.willChange(obj, keyName); } + if (!watching) { + return; + } + + if (proto === obj) { + return; + } + + if (desc && desc.willChange) { + desc.willChange(obj, keyName); + } + dependentKeysWillChange(obj, keyName, m); chainsWillChange(obj, keyName, m); notifyBeforeObservers(obj, keyName); } @@ -8854,16 +8926,23 @@ var m = obj['__ember_meta__']; var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; var proto = m && m.proto; var desc = m && m.descs[keyName]; - if (proto === obj) { return; } + if (proto === obj) { + return; + } // shouldn't this mean that we're watching this key? - if (desc && desc.didChange) { desc.didChange(obj, keyName); } - if (!watching && keyName !== 'length') { return; } + if (desc && desc.didChange) { + desc.didChange(obj, keyName); + } + if (!watching && keyName !== 'length') { + return; + } + if (m && m.deps && m.deps[keyName]) { dependentKeysDidChange(obj, keyName, m); } chainsDidChange(obj, keyName, m, false); @@ -8877,13 +8956,20 @@ var deps; if (meta && meta.deps && (deps = meta.deps[depKey])) { var seen = WILL_SEEN; var top = !seen; - if (top) { seen = WILL_SEEN = {}; } + + if (top) { + seen = WILL_SEEN = {}; + } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); - if (top) { WILL_SEEN = null; } + + if (top) { + WILL_SEEN = null; + } } } // called whenever a property has just changed to update dependent keys function dependentKeysDidChange(obj, depKey, meta) { @@ -8891,37 +8977,59 @@ var deps; if (meta && meta.deps && (deps = meta.deps[depKey])) { var seen = DID_SEEN; var top = !seen; - if (top) { seen = DID_SEEN = {}; } + + if (top) { + seen = DID_SEEN = {}; + } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); - if (top) { DID_SEEN = null; } + + if (top) { + DID_SEEN = null; + } } } function keysOf(obj) { var keys = []; - for (var key in obj) keys.push(key); + + for (var key in obj) { + keys.push(key); + } + return keys; } function iterDeps(method, obj, deps, depKey, seen, meta) { var keys, key, i, desc; var guid = guidFor(obj); var current = seen[guid]; - if (!current) current = seen[guid] = {}; - if (current[depKey]) return; + + if (!current) { + current = seen[guid] = {}; + } + + if (current[depKey]) { + return; + } + current[depKey] = true; if (deps) { keys = keysOf(deps); var descs = meta.descs; for (i=0; i<keys.length; i++) { key = keys[i]; desc = descs[key]; - if (desc && desc._suspended === obj) continue; + + if (desc && desc._suspended === obj) { + continue; + } + method(obj, key); } } } @@ -9490,18 +9598,12 @@ 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, when called within an existing loop, no return value is possible. */ - run.join = function(target, method /* args */) { - if (!run.currentRunLoop) { - return Ember.run.apply(Ember, arguments); - } - - var args = slice.call(arguments); - args.unshift('actions'); - run.schedule.apply(run, args); + run.join = function() { + return backburner.join.apply(backburner, arguments); }; /** Provides a useful utility for when integrating with non-Ember libraries that provide asynchronous callbacks. @@ -11304,11 +11406,12 @@ } }; function unwatchKey(obj, keyName, meta) { - var m = meta || metaFor(obj), watching = m.watching; + var m = meta || metaFor(obj); + var watching = m.watching; if (watching[keyName] === 1) { watching[keyName] = 0; var desc = m.descs[keyName]; @@ -13721,11 +13824,11 @@ ``` Then, create a view that binds to your new controller: ```handlebars - {{#each MyApp.listController}} - {{firstName}} {{lastName}} + {{#each person in MyApp.listController}} + {{person.firstName}} {{person.lastName}} {{/each}} ``` Although you are binding to the controller, the behavior of this controller is to pass through any methods or properties to the underlying array. This