dist/ember-template-compiler.js in ember-source-2.1.0.beta.1 vs dist/ember-template-compiler.js in ember-source-2.1.0.beta.3

- old
+ new

@@ -3,11 +3,11 @@ * @copyright Copyright 2011-2015 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 2.1.0-beta.1 + * @version 2.1.0-beta.3 */ (function() { var enifed, requireModule, eriuqer, requirejs, Ember; var mainContext = this; @@ -2895,614 +2895,10 @@ exports.removeChainWatcher = removeChainWatcher; exports.ChainNode = ChainNode; }); // warn, assert, etc; -enifed('ember-metal/computed', ['exports', 'ember-metal/core', 'ember-metal/property_set', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/expand_properties', 'ember-metal/error', 'ember-metal/properties', 'ember-metal/property_events', 'ember-metal/dependent_keys'], function (exports, _emberMetalCore, _emberMetalProperty_set, _emberMetalUtils, _emberMetalMeta, _emberMetalExpand_properties, _emberMetalError, _emberMetalProperties, _emberMetalProperty_events, _emberMetalDependent_keys) { - 'use strict'; - - exports.default = computed; - - /** - @module ember - @submodule ember-metal - */ - - var metaFor = _emberMetalMeta.meta; - - function UNDEFINED() {} - - // .......................................................... - // COMPUTED 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 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 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 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({ - // these will be supplied by `create` - firstName: null, - lastName: null, - - fullName: function() { - var firstName = this.get('firstName'); - var lastName = this.get('lastName'); - - return firstName + ' ' + lastName; - }.property('firstName', 'lastName') - }); - - var tom = Person.create({ - firstName: 'Tom', - lastName: 'Dale' - }); - - tom.get('fullName') // 'Tom Dale' - ``` - - You can also define what Ember should do when setting a computed property. - If you try to set a computed property, it will be invoked with the key and - value you want to set it to. You can also accept the previous value as the - third parameter. - - ```javascript - var Person = Ember.Object.extend({ - // these will be supplied by `create` - firstName: null, - lastName: null, - - fullName: function(key, value, oldValue) { - // getter - if (arguments.length === 1) { - var firstName = this.get('firstName'); - var lastName = this.get('lastName'); - - return firstName + ' ' + lastName; - - // setter - } else { - var name = value.split(' '); - - this.set('firstName', name[0]); - this.set('lastName', name[1]); - - return value; - } - }.property('firstName', 'lastName') - }); - - var person = Person.create(); - - person.set('fullName', 'Peter Wagenet'); - person.get('firstName'); // 'Peter' - person.get('lastName'); // 'Wagenet' - ``` - - @class ComputedProperty - @namespace Ember - @constructor - @public - */ - function ComputedProperty(config, opts) { - this.isDescriptor = true; - if (typeof config === 'function') { - this._getter = config; - } else { - this._getter = config.get; - this._setter = config.set; - } - this._dependentKeys = undefined; - this._suspended = undefined; - this._meta = undefined; - this._volatile = false; - this._dependentKeys = opts && opts.dependentKeys; - this._readOnly = false; - } - - ComputedProperty.prototype = new _emberMetalProperties.Descriptor(); - - var ComputedPropertyPrototype = ComputedProperty.prototype; - - /** - Call on a computed property to set it into non-cached mode. When in this - mode the computed property will not automatically cache the return value. - - It also does not automatically fire any change events. You must manually notify - any changes if you want to observe this property. - - Dependency keys have no effect on volatile properties as they are for cache - invalidation and notification when cached value is invalidated. - - ```javascript - var outsideService = Ember.Object.extend({ - value: function() { - return OutsideService.getValue(); - }.property().volatile() - }).create(); - ``` - - @method volatile - @return {Ember.ComputedProperty} this - @chainable - @public - */ - ComputedPropertyPrototype.volatile = function () { - this._volatile = true; - return this; - }; - - /** - Call on a computed property to set it into read-only mode. When in this - mode the computed property will throw an error when set. - - ```javascript - var Person = Ember.Object.extend({ - guid: function() { - return 'guid-guid-guid'; - }.property().readOnly() - }); - - var person = Person.create(); - - person.set('guid', 'new-guid'); // will throw an exception - ``` - - @method readOnly - @return {Ember.ComputedProperty} this - @chainable - @public - */ - ComputedPropertyPrototype.readOnly = function () { - this._readOnly = true; - _emberMetalCore.default.assert('Computed properties that define a setter using the new syntax cannot be read-only', !(this._readOnly && this._setter && this._setter !== this._getter)); - return this; - }; - - /** - Sets the dependent keys on this computed property. Pass any number of - arguments containing key paths that this computed property depends on. - - ```javascript - var President = Ember.Object.extend({ - fullName: computed(function() { - return this.get('firstName') + ' ' + this.get('lastName'); - - // Tell Ember that this computed property depends on firstName - // and lastName - }).property('firstName', 'lastName') - }); - - var president = President.create({ - firstName: 'Barack', - lastName: 'Obama' - }); - - president.get('fullName'); // 'Barack Obama' - ``` - - @method property - @param {String} path* zero or more property paths - @return {Ember.ComputedProperty} this - @chainable - @public - */ - ComputedPropertyPrototype.property = function () { - var args; - - var addArg = function (property) { - _emberMetalCore.default.assert('Depending on arrays using a dependent key ending with `@each` is no longer supported. ' + ('Please refactor from `Ember.computed(\'' + property + '\', function() {});` to `Ember.computed(\'' + property.slice(0, -6) + '.[]\', function() {})`.'), property.slice(-5) !== '@each'); - args.push(property); - }; - - args = []; - for (var i = 0, l = arguments.length; i < l; i++) { - _emberMetalExpand_properties.default(arguments[i], addArg); - } - - this._dependentKeys = args; - return this; - }; - - /** - In some cases, you may want to annotate computed properties with additional - metadata about how they function or what values they operate on. For example, - computed property functions may close over variables that are then no longer - available for introspection. - - You can pass a hash of these values to a computed property like this: - - ``` - person: function() { - var personId = this.get('personId'); - return App.Person.create({ id: personId }); - }.property().meta({ type: App.Person }) - ``` - - The hash that you pass to the `meta()` function will be saved on the - computed property descriptor under the `_meta` key. Ember runtime - exposes a public API for retrieving these values from classes, - via the `metaForProperty()` function. - - @method meta - @param {Object} meta - @chainable - @public - */ - - ComputedPropertyPrototype.meta = function (meta) { - if (arguments.length === 0) { - return this._meta || {}; - } else { - this._meta = meta; - return this; - } - }; - - // invalidate cache when CP key changes - ComputedPropertyPrototype.didChange = function (obj, keyName) { - // _suspended is set via a CP.set to ensure we don't clear - // the cached value set by the setter - if (this._volatile || this._suspended === obj) { - return; - } - - // don't create objects just to invalidate - var meta = obj.__ember_meta__; - if (!meta || meta.source !== obj) { - return; - } - - var cache = meta.readableCache(); - if (cache && cache[keyName] !== undefined) { - cache[keyName] = undefined; - _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, meta); - } - }; - - /** - Access the value of the function backing the computed property. - If this property has already been cached, return the cached result. - Otherwise, call the function passing the property name as an argument. - - ```javascript - var Person = Ember.Object.extend({ - fullName: function(keyName) { - // the keyName parameter is 'fullName' in this case. - return this.get('firstName') + ' ' + this.get('lastName'); - }.property('firstName', 'lastName') - }); - - - var tom = Person.create({ - firstName: 'Tom', - lastName: 'Dale' - }); - - tom.get('fullName') // 'Tom Dale' - ``` - - @method get - @param {String} keyName The key being accessed. - @return {Object} The return value of the function backing the CP. - @public - */ - ComputedPropertyPrototype.get = function (obj, keyName) { - if (this._volatile) { - return this._getter.call(obj, keyName); - } - - var meta = metaFor(obj); - var cache = meta.writableCache(); - - var result = cache[keyName]; - if (result === UNDEFINED) { - return undefined; - } else if (result !== undefined) { - return result; - } - - var ret = this._getter.call(obj, keyName); - if (ret === undefined) { - cache[keyName] = UNDEFINED; - } else { - cache[keyName] = ret; - } - - var chainWatchers = meta.readableChainWatchers(); - if (chainWatchers) { - chainWatchers.revalidate(keyName); - } - _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, meta); - - return ret; - }; - - /** - Set the value of a computed property. If the function that backs your - computed property does not accept arguments then the default action for - setting would be to define the property on the current object, and set - the value of the property to the value being set. - - Generally speaking if you intend for your computed property to be set - your backing function should accept either two or three arguments. - - ```javascript - var Person = Ember.Object.extend({ - // these will be supplied by `create` - firstName: null, - lastName: null, - - fullName: function(key, value, oldValue) { - // getter - if (arguments.length === 1) { - var firstName = this.get('firstName'); - var lastName = this.get('lastName'); - - return firstName + ' ' + lastName; - - // setter - } else { - var name = value.split(' '); - - this.set('firstName', name[0]); - this.set('lastName', name[1]); - - return value; - } - }.property('firstName', 'lastName') - }); - - var person = Person.create(); - - person.set('fullName', 'Peter Wagenet'); - person.get('firstName'); // 'Peter' - person.get('lastName'); // 'Wagenet' - ``` - - @method set - @param {String} keyName The key being accessed. - @param {Object} newValue The new value being assigned. - @param {String} oldValue The old value being replaced. - @return {Object} The return value of the function backing the CP. - @public - */ - ComputedPropertyPrototype.set = function computedPropertySetEntry(obj, keyName, value) { - if (this._readOnly) { - this._throwReadOnlyError(obj, keyName); - } - - if (!this._setter) { - return this.clobberSet(obj, keyName, value); - } - - if (this._volatile) { - return this.volatileSet(obj, keyName, value); - } - - return this.setWithSuspend(obj, keyName, value); - }; - - ComputedPropertyPrototype._throwReadOnlyError = function computedPropertyThrowReadOnlyError(obj, keyName) { - throw new _emberMetalError.default('Cannot set read-only property "' + keyName + '" on object: ' + _emberMetalUtils.inspect(obj)); - }; - - ComputedPropertyPrototype.clobberSet = function computedPropertyClobberSet(obj, keyName, value) { - var cachedValue = cacheFor(obj, keyName); - _emberMetalProperties.defineProperty(obj, keyName, null, cachedValue); - _emberMetalProperty_set.set(obj, keyName, value); - return value; - }; - - ComputedPropertyPrototype.volatileSet = function computedPropertyVolatileSet(obj, keyName, value) { - return this._setter.call(obj, keyName, value); - }; - - ComputedPropertyPrototype.setWithSuspend = function computedPropertySetWithSuspend(obj, keyName, value) { - var oldSuspended = this._suspended; - this._suspended = obj; - try { - return this._set(obj, keyName, value); - } finally { - this._suspended = oldSuspended; - } - }; - - ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, value) { - // cache requires own meta - var meta = metaFor(obj); - // either there is a writable cache or we need one to update - var cache = meta.writableCache(); - var hadCachedValue = false; - var cachedValue = undefined; - if (cache[keyName] !== undefined) { - if (cache[keyName] !== UNDEFINED) { - cachedValue = cache[keyName]; - } - hadCachedValue = true; - } - - var ret = this._setter.call(obj, keyName, value, cachedValue); - - // allows setter to return the same value that is cached already - if (hadCachedValue && cachedValue === ret) { - return ret; - } - - var watched = meta.peekWatching(keyName); - if (watched) { - _emberMetalProperty_events.propertyWillChange(obj, keyName); - } - - if (hadCachedValue) { - cache[keyName] = undefined; - } - - if (!hadCachedValue) { - _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, meta); - } - - if (ret === undefined) { - cache[keyName] = UNDEFINED; - } else { - cache[keyName] = ret; - } - - if (watched) { - _emberMetalProperty_events.propertyDidChange(obj, keyName); - } - - return ret; - }; - - /* called before property is overridden */ - ComputedPropertyPrototype.teardown = function (obj, keyName) { - if (this._volatile) { - return; - } - var meta = metaFor(obj); - var cache = meta.readableCache(); - if (cache && cache[keyName] !== undefined) { - _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, meta); - cache[keyName] = undefined; - } - }; - - /** - This helper returns a new property descriptor that wraps the passed - computed property function. You can use this helper to define properties - with mixins or via `Ember.defineProperty()`. - - The function you pass will be used to both get and set property values. - The function should accept two parameters, key and value. If value is not - undefined you should set the value first. In either case return the - current value of the property. - - A computed property defined in this way might look like this: - - ```js - var Person = Ember.Object.extend({ - firstName: 'Betty', - lastName: 'Jones', - - fullName: Ember.computed('firstName', 'lastName', function(key, value) { - return this.get('firstName') + ' ' + this.get('lastName'); - }) - }); - - var client = Person.create(); - - client.get('fullName'); // 'Betty Jones' - - client.set('lastName', 'Fuller'); - client.get('fullName'); // 'Betty Fuller' - ``` - - _Note: This is the preferred way to define computed properties when writing third-party - libraries that depend on or use Ember, since there is no guarantee that the user - will have prototype extensions enabled._ - - You might use this method if you disabled - [Prototype Extensions](http://emberjs.com/guides/configuring-ember/disabling-prototype-extensions/). - The alternative syntax might look like this - (if prototype extensions are enabled, which is the default behavior): - - ```js - fullName: function () { - return this.get('firstName') + ' ' + this.get('lastName'); - }.property('firstName', 'lastName') - ``` - - @class computed - @namespace Ember - @constructor - @static - @param {String} [dependentKeys*] Optional dependent keys that trigger this computed property. - @param {Function} func The computed property function. - @return {Ember.ComputedProperty} property descriptor instance - @public - */ - - function computed(func) { - var args; - - if (arguments.length > 1) { - args = [].slice.call(arguments); - func = args.pop(); - } - - var cp = new ComputedProperty(func); - - if (args) { - cp.property.apply(cp, args); - } - - return cp; - } - - /** - Returns the cached value for a property, if one exists. - This can be useful for peeking at the value of a computed - property that is generated lazily, without accidentally causing - it to be created. - - @method cacheFor - @for Ember - @param {Object} obj the object whose property you want to check - @param {String} key the name of the property whose cached value you want - to return - @return {Object} the cached value - @public - */ - function cacheFor(obj, key) { - var meta = obj.__ember_meta__; - var cache = meta && meta.source === obj && meta.readableCache(); - var ret = cache && cache[key]; - - if (ret === UNDEFINED) { - return undefined; - } - return ret; - } - - cacheFor.set = function (cache, key, value) { - if (value === undefined) { - cache[key] = UNDEFINED; - } else { - cache[key] = value; - } - }; - - cacheFor.get = function (cache, key) { - var ret = cache[key]; - if (ret === UNDEFINED) { - return undefined; - } - return ret; - }; - - cacheFor.remove = function (cache, key) { - cache[key] = undefined; - }; - - exports.ComputedProperty = ComputedProperty; - exports.computed = computed; - exports.cacheFor = cacheFor; -}); enifed('ember-metal/computed_macros', ['exports', 'ember-metal/core', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/computed', 'ember-metal/is_empty', 'ember-metal/is_none', 'ember-metal/alias'], function (exports, _emberMetalCore, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalComputed, _emberMetalIs_empty, _emberMetalIs_none, _emberMetalAlias) { 'use strict'; exports.empty = empty; exports.notEmpty = notEmpty; @@ -4193,10 +3589,625 @@ return value; } }); } }); +enifed('ember-metal/computed', ['exports', 'ember-metal/core', 'ember-metal/property_set', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/expand_properties', 'ember-metal/error', 'ember-metal/properties', 'ember-metal/property_events', 'ember-metal/dependent_keys'], function (exports, _emberMetalCore, _emberMetalProperty_set, _emberMetalUtils, _emberMetalMeta, _emberMetalExpand_properties, _emberMetalError, _emberMetalProperties, _emberMetalProperty_events, _emberMetalDependent_keys) { + 'use strict'; + + exports.default = computed; + + /** + @module ember + @submodule ember-metal + */ + + var metaFor = _emberMetalMeta.meta; + + function UNDEFINED() {} + + // .......................................................... + // COMPUTED 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 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 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 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({ + // these will be supplied by `create` + firstName: null, + lastName: null, + + fullName: function() { + var firstName = this.get('firstName'); + var lastName = this.get('lastName'); + + return firstName + ' ' + lastName; + }.property('firstName', 'lastName') + }); + + var tom = Person.create({ + firstName: 'Tom', + lastName: 'Dale' + }); + + tom.get('fullName') // 'Tom Dale' + ``` + + You can also define what Ember should do when setting a computed property. + If you try to set a computed property, it will be invoked with the key and + value you want to set it to. You can also accept the previous value as the + third parameter. + + ```javascript + var Person = Ember.Object.extend({ + // these will be supplied by `create` + firstName: null, + lastName: null, + + fullName: function(key, value, oldValue) { + // getter + if (arguments.length === 1) { + var firstName = this.get('firstName'); + var lastName = this.get('lastName'); + + return firstName + ' ' + lastName; + + // setter + } else { + var name = value.split(' '); + + this.set('firstName', name[0]); + this.set('lastName', name[1]); + + return value; + } + }.property('firstName', 'lastName') + }); + + var person = Person.create(); + + person.set('fullName', 'Peter Wagenet'); + person.get('firstName'); // 'Peter' + person.get('lastName'); // 'Wagenet' + ``` + + @class ComputedProperty + @namespace Ember + @constructor + @public + */ + function ComputedProperty(config, opts) { + this.isDescriptor = true; + if (typeof config === 'function') { + this._getter = config; + } else { + _emberMetalCore.default.assert('Ember.computed expects a function or an object as last argument.', typeof config === 'object' && !Array.isArray(config)); + _emberMetalCore.default.assert('Config object pased to a Ember.computed can only contain `get` or `set` keys.', (function () { + var keys = Object.keys(config); + for (var i = 0; i < keys.length; i++) { + if (keys[i] !== 'get' && keys[i] !== 'set') { + return false; + } + } + return true; + })()); + this._getter = config.get; + this._setter = config.set; + } + _emberMetalCore.default.assert('Computed properties must receive a getter or a setter, you passed none.', !!this._getter || !!this._setter); + this._dependentKeys = undefined; + this._suspended = undefined; + this._meta = undefined; + this._volatile = false; + this._dependentKeys = opts && opts.dependentKeys; + this._readOnly = false; + } + + ComputedProperty.prototype = new _emberMetalProperties.Descriptor(); + + var ComputedPropertyPrototype = ComputedProperty.prototype; + + /** + Call on a computed property to set it into non-cached mode. When in this + mode the computed property will not automatically cache the return value. + + It also does not automatically fire any change events. You must manually notify + any changes if you want to observe this property. + + Dependency keys have no effect on volatile properties as they are for cache + invalidation and notification when cached value is invalidated. + + ```javascript + var outsideService = Ember.Object.extend({ + value: function() { + return OutsideService.getValue(); + }.property().volatile() + }).create(); + ``` + + @method volatile + @return {Ember.ComputedProperty} this + @chainable + @public + */ + ComputedPropertyPrototype.volatile = function () { + this._volatile = true; + return this; + }; + + /** + Call on a computed property to set it into read-only mode. When in this + mode the computed property will throw an error when set. + + ```javascript + var Person = Ember.Object.extend({ + guid: function() { + return 'guid-guid-guid'; + }.property().readOnly() + }); + + var person = Person.create(); + + person.set('guid', 'new-guid'); // will throw an exception + ``` + + @method readOnly + @return {Ember.ComputedProperty} this + @chainable + @public + */ + ComputedPropertyPrototype.readOnly = function () { + this._readOnly = true; + _emberMetalCore.default.assert('Computed properties that define a setter using the new syntax cannot be read-only', !(this._readOnly && this._setter && this._setter !== this._getter)); + return this; + }; + + /** + Sets the dependent keys on this computed property. Pass any number of + arguments containing key paths that this computed property depends on. + + ```javascript + var President = Ember.Object.extend({ + fullName: computed(function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember that this computed property depends on firstName + // and lastName + }).property('firstName', 'lastName') + }); + + var president = President.create({ + firstName: 'Barack', + lastName: 'Obama' + }); + + president.get('fullName'); // 'Barack Obama' + ``` + + @method property + @param {String} path* zero or more property paths + @return {Ember.ComputedProperty} this + @chainable + @public + */ + ComputedPropertyPrototype.property = function () { + var args; + + var addArg = function (property) { + _emberMetalCore.default.assert('Depending on arrays using a dependent key ending with `@each` is no longer supported. ' + ('Please refactor from `Ember.computed(\'' + property + '\', function() {});` to `Ember.computed(\'' + property.slice(0, -6) + '.[]\', function() {})`.'), property.slice(-5) !== '@each'); + args.push(property); + }; + + args = []; + for (var i = 0, l = arguments.length; i < l; i++) { + _emberMetalExpand_properties.default(arguments[i], addArg); + } + + this._dependentKeys = args; + return this; + }; + + /** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For example, + computed property functions may close over variables that are then no longer + available for introspection. + + You can pass a hash of these values to a computed property like this: + + ``` + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + The hash that you pass to the `meta()` function will be saved on the + computed property descriptor under the `_meta` key. Ember runtime + exposes a public API for retrieving these values from classes, + via the `metaForProperty()` function. + + @method meta + @param {Object} meta + @chainable + @public + */ + + ComputedPropertyPrototype.meta = function (meta) { + if (arguments.length === 0) { + return this._meta || {}; + } else { + this._meta = meta; + return this; + } + }; + + // invalidate cache when CP key changes + ComputedPropertyPrototype.didChange = function (obj, keyName) { + // _suspended is set via a CP.set to ensure we don't clear + // the cached value set by the setter + if (this._volatile || this._suspended === obj) { + return; + } + + // don't create objects just to invalidate + var meta = obj.__ember_meta__; + if (!meta || meta.source !== obj) { + return; + } + + var cache = meta.readableCache(); + if (cache && cache[keyName] !== undefined) { + cache[keyName] = undefined; + _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, meta); + } + }; + + /** + Access the value of the function backing the computed property. + If this property has already been cached, return the cached result. + Otherwise, call the function passing the property name as an argument. + + ```javascript + var Person = Ember.Object.extend({ + fullName: function(keyName) { + // the keyName parameter is 'fullName' in this case. + return this.get('firstName') + ' ' + this.get('lastName'); + }.property('firstName', 'lastName') + }); + + + var tom = Person.create({ + firstName: 'Tom', + lastName: 'Dale' + }); + + tom.get('fullName') // 'Tom Dale' + ``` + + @method get + @param {String} keyName The key being accessed. + @return {Object} The return value of the function backing the CP. + @public + */ + ComputedPropertyPrototype.get = function (obj, keyName) { + if (this._volatile) { + return this._getter.call(obj, keyName); + } + + var meta = metaFor(obj); + var cache = meta.writableCache(); + + var result = cache[keyName]; + if (result === UNDEFINED) { + return undefined; + } else if (result !== undefined) { + return result; + } + + var ret = this._getter.call(obj, keyName); + if (ret === undefined) { + cache[keyName] = UNDEFINED; + } else { + cache[keyName] = ret; + } + + var chainWatchers = meta.readableChainWatchers(); + if (chainWatchers) { + chainWatchers.revalidate(keyName); + } + _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, meta); + + return ret; + }; + + /** + Set the value of a computed property. If the function that backs your + computed property does not accept arguments then the default action for + setting would be to define the property on the current object, and set + the value of the property to the value being set. + + Generally speaking if you intend for your computed property to be set + your backing function should accept either two or three arguments. + + ```javascript + var Person = Ember.Object.extend({ + // these will be supplied by `create` + firstName: null, + lastName: null, + + fullName: function(key, value, oldValue) { + // getter + if (arguments.length === 1) { + var firstName = this.get('firstName'); + var lastName = this.get('lastName'); + + return firstName + ' ' + lastName; + + // setter + } else { + var name = value.split(' '); + + this.set('firstName', name[0]); + this.set('lastName', name[1]); + + return value; + } + }.property('firstName', 'lastName') + }); + + var person = Person.create(); + + person.set('fullName', 'Peter Wagenet'); + person.get('firstName'); // 'Peter' + person.get('lastName'); // 'Wagenet' + ``` + + @method set + @param {String} keyName The key being accessed. + @param {Object} newValue The new value being assigned. + @param {String} oldValue The old value being replaced. + @return {Object} The return value of the function backing the CP. + @public + */ + ComputedPropertyPrototype.set = function computedPropertySetEntry(obj, keyName, value) { + if (this._readOnly) { + this._throwReadOnlyError(obj, keyName); + } + + if (!this._setter) { + return this.clobberSet(obj, keyName, value); + } + + if (this._volatile) { + return this.volatileSet(obj, keyName, value); + } + + return this.setWithSuspend(obj, keyName, value); + }; + + ComputedPropertyPrototype._throwReadOnlyError = function computedPropertyThrowReadOnlyError(obj, keyName) { + throw new _emberMetalError.default('Cannot set read-only property "' + keyName + '" on object: ' + _emberMetalUtils.inspect(obj)); + }; + + ComputedPropertyPrototype.clobberSet = function computedPropertyClobberSet(obj, keyName, value) { + var cachedValue = cacheFor(obj, keyName); + _emberMetalProperties.defineProperty(obj, keyName, null, cachedValue); + _emberMetalProperty_set.set(obj, keyName, value); + return value; + }; + + ComputedPropertyPrototype.volatileSet = function computedPropertyVolatileSet(obj, keyName, value) { + return this._setter.call(obj, keyName, value); + }; + + ComputedPropertyPrototype.setWithSuspend = function computedPropertySetWithSuspend(obj, keyName, value) { + var oldSuspended = this._suspended; + this._suspended = obj; + try { + return this._set(obj, keyName, value); + } finally { + this._suspended = oldSuspended; + } + }; + + ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, value) { + // cache requires own meta + var meta = metaFor(obj); + // either there is a writable cache or we need one to update + var cache = meta.writableCache(); + var hadCachedValue = false; + var cachedValue = undefined; + if (cache[keyName] !== undefined) { + if (cache[keyName] !== UNDEFINED) { + cachedValue = cache[keyName]; + } + hadCachedValue = true; + } + + var ret = this._setter.call(obj, keyName, value, cachedValue); + + // allows setter to return the same value that is cached already + if (hadCachedValue && cachedValue === ret) { + return ret; + } + + var watched = meta.peekWatching(keyName); + if (watched) { + _emberMetalProperty_events.propertyWillChange(obj, keyName); + } + + if (hadCachedValue) { + cache[keyName] = undefined; + } + + if (!hadCachedValue) { + _emberMetalDependent_keys.addDependentKeys(this, obj, keyName, meta); + } + + if (ret === undefined) { + cache[keyName] = UNDEFINED; + } else { + cache[keyName] = ret; + } + + if (watched) { + _emberMetalProperty_events.propertyDidChange(obj, keyName); + } + + return ret; + }; + + /* called before property is overridden */ + ComputedPropertyPrototype.teardown = function (obj, keyName) { + if (this._volatile) { + return; + } + var meta = metaFor(obj); + var cache = meta.readableCache(); + if (cache && cache[keyName] !== undefined) { + _emberMetalDependent_keys.removeDependentKeys(this, obj, keyName, meta); + cache[keyName] = undefined; + } + }; + + /** + This helper returns a new property descriptor that wraps the passed + computed property function. You can use this helper to define properties + with mixins or via `Ember.defineProperty()`. + + The function you pass will be used to both get and set property values. + The function should accept two parameters, key and value. If value is not + undefined you should set the value first. In either case return the + current value of the property. + + A computed property defined in this way might look like this: + + ```js + var Person = Ember.Object.extend({ + firstName: 'Betty', + lastName: 'Jones', + + fullName: Ember.computed('firstName', 'lastName', function(key, value) { + return this.get('firstName') + ' ' + this.get('lastName'); + }) + }); + + var client = Person.create(); + + client.get('fullName'); // 'Betty Jones' + + client.set('lastName', 'Fuller'); + client.get('fullName'); // 'Betty Fuller' + ``` + + _Note: This is the preferred way to define computed properties when writing third-party + libraries that depend on or use Ember, since there is no guarantee that the user + will have prototype extensions enabled._ + + You might use this method if you disabled + [Prototype Extensions](http://emberjs.com/guides/configuring-ember/disabling-prototype-extensions/). + The alternative syntax might look like this + (if prototype extensions are enabled, which is the default behavior): + + ```js + fullName: function () { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property('firstName', 'lastName') + ``` + + @class computed + @namespace Ember + @constructor + @static + @param {String} [dependentKeys*] Optional dependent keys that trigger this computed property. + @param {Function} func The computed property function. + @return {Ember.ComputedProperty} property descriptor instance + @public + */ + + function computed(func) { + var args; + + if (arguments.length > 1) { + args = [].slice.call(arguments); + func = args.pop(); + } + + var cp = new ComputedProperty(func); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + /** + Returns the cached value for a property, if one exists. + This can be useful for peeking at the value of a computed + property that is generated lazily, without accidentally causing + it to be created. + + @method cacheFor + @for Ember + @param {Object} obj the object whose property you want to check + @param {String} key the name of the property whose cached value you want + to return + @return {Object} the cached value + @public + */ + function cacheFor(obj, key) { + var meta = obj.__ember_meta__; + var cache = meta && meta.source === obj && meta.readableCache(); + var ret = cache && cache[key]; + + if (ret === UNDEFINED) { + return undefined; + } + return ret; + } + + cacheFor.set = function (cache, key, value) { + if (value === undefined) { + cache[key] = UNDEFINED; + } else { + cache[key] = value; + } + }; + + cacheFor.get = function (cache, key) { + var ret = cache[key]; + if (ret === UNDEFINED) { + return undefined; + } + return ret; + }; + + cacheFor.remove = function (cache, key) { + cache[key] = undefined; + }; + + exports.ComputedProperty = ComputedProperty; + exports.computed = computed; + exports.cacheFor = cacheFor; +}); enifed('ember-metal/core', ['exports', 'ember-metal/assert'], function (exports, _emberMetalAssert) { /*globals Ember:true,ENV,EmberENV */ /** @module ember @@ -4216,11 +4227,11 @@ cross-platform libraries such as jQuery. For more details, see [Ember-Runtime](http://emberjs.com/api/modules/ember-runtime.html). @class Ember @static - @version 2.1.0-beta.1 + @version 2.1.0-beta.3 @public */ 'use strict'; @@ -4250,15 +4261,15 @@ /** The semantic version. @property VERSION @type String - @default '2.1.0-beta.1' + @default '2.1.0-beta.3' @static @public */ - Ember.VERSION = '2.1.0-beta.1'; + Ember.VERSION = '2.1.0-beta.3'; /** The hash of environment variables used to control various configuration settings. To specify your own or override default settings, add the desired properties to a global hash named `EmberENV` (or `ENV` for @@ -6361,10 +6372,183 @@ } return original; } }); +enifed('ember-metal/meta_listeners', ['exports'], function (exports) { + /* + When we render a rich template hierarchy, the set of events that + *might* happen tends to be much larger than the set of events that + actually happen. This implies that we should make listener creation & + destruction cheap, even at the cost of making event dispatch more + expensive. + + Thus we store a new listener with a single push and no new + allocations, without even bothering to do deduplication -- we can + save that for dispatch time, if an event actually happens. + */ + + /* listener flags */ + 'use strict'; + + var ONCE = 1; + exports.ONCE = ONCE; + var SUSPENDED = 2; + + exports.SUSPENDED = SUSPENDED; + var protoMethods = { + + addToListeners: function (eventName, target, method, flags) { + if (!this._listeners) { + this._listeners = []; + } + this._listeners.push(eventName, target, method, flags); + }, + + _finalizeListeners: function () { + if (this._listenersFinalized) { + return; + } + if (!this._listeners) { + this._listeners = []; + } + var pointer = this.parent; + while (pointer) { + var listeners = pointer._listeners; + if (listeners) { + this._listeners = this._listeners.concat(listeners); + } + if (pointer._listenersFinalized) { + break; + } + pointer = pointer.parent; + } + this._listenersFinalized = true; + }, + + removeFromListeners: function (eventName, target, method, didRemove) { + var pointer = this; + while (pointer) { + var listeners = pointer._listeners; + if (listeners) { + for (var index = listeners.length - 4; index >= 0; index -= 4) { + if (listeners[index] === eventName && (!method || listeners[index + 1] === target && listeners[index + 2] === method)) { + if (pointer === this) { + // we are modifying our own list, so we edit directly + if (typeof didRemove === 'function') { + didRemove(eventName, target, listeners[index + 2]); + } + listeners.splice(index, 4); + } else { + // we are trying to remove an inherited listener, so we do + // just-in-time copying to detach our own listeners from + // our inheritance chain. + this._finalizeListeners(); + return this.removeFromListeners(eventName, target, method); + } + } + } + } + if (pointer._listenersFinalized) { + break; + } + pointer = pointer.parent; + } + }, + + matchingListeners: function (eventName) { + var pointer = this; + var result = []; + while (pointer) { + var listeners = pointer._listeners; + if (listeners) { + for (var index = 0; index < listeners.length - 3; index += 4) { + if (listeners[index] === eventName) { + pushUniqueListener(result, listeners, index); + } + } + } + if (pointer._listenersFinalized) { + break; + } + pointer = pointer.parent; + } + var sus = this._suspendedListeners; + if (sus) { + for (var susIndex = 0; susIndex < sus.length - 2; susIndex += 3) { + if (eventName === sus[susIndex]) { + for (var resultIndex = 0; resultIndex < result.length - 2; resultIndex += 3) { + if (result[resultIndex] === sus[susIndex + 1] && result[resultIndex + 1] === sus[susIndex + 2]) { + result[resultIndex + 2] |= SUSPENDED; + } + } + } + } + } + return result; + }, + + suspendListeners: function (eventNames, target, method, callback) { + var sus = this._suspendedListeners; + if (!sus) { + sus = this._suspendedListeners = []; + } + for (var i = 0; i < eventNames.length; i++) { + sus.push(eventNames[i], target, method); + } + try { + return callback.call(target); + } finally { + if (sus.length === eventNames.length) { + this._suspendedListeners = undefined; + } else { + for (var i = sus.length - 3; i >= 0; i -= 3) { + if (sus[i + 1] === target && sus[i + 2] === method && eventNames.indexOf(sus[i]) !== -1) { + sus.splice(i, 3); + } + } + } + } + }, + + watchedEvents: function () { + var pointer = this; + var names = {}; + while (pointer) { + var listeners = pointer._listeners; + if (listeners) { + for (var index = 0; index < listeners.length - 3; index += 4) { + names[listeners[index]] = true; + } + } + if (pointer._listenersFinalized) { + break; + } + pointer = pointer.parent; + } + return Object.keys(names); + }, + + _initializeListeners: function () { + this._listeners = undefined; + this._listenersFinalized = undefined; + this._suspendedListeners = undefined; + } + }; + + exports.protoMethods = protoMethods; + function pushUniqueListener(destination, source, index) { + var target = source[index + 1]; + var method = source[index + 2]; + for (var destinationIndex = 0; destinationIndex < destination.length - 2; destinationIndex += 3) { + if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { + return; + } + } + destination.push(target, method, source[index + 3]); + } +}); enifed('ember-metal/meta', ['exports', 'ember-metal/features', 'ember-metal/meta_listeners', 'ember-metal/empty_object'], function (exports, _emberMetalFeatures, _emberMetalMeta_listeners, _emberMetalEmpty_object) { // Remove "use strict"; from transpiled module until // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed // @@ -6655,183 +6839,10 @@ obj.__ember_meta__ = ret; return ret; } }); -enifed('ember-metal/meta_listeners', ['exports'], function (exports) { - /* - When we render a rich template hierarchy, the set of events that - *might* happen tends to be much larger than the set of events that - actually happen. This implies that we should make listener creation & - destruction cheap, even at the cost of making event dispatch more - expensive. - - Thus we store a new listener with a single push and no new - allocations, without even bothering to do deduplication -- we can - save that for dispatch time, if an event actually happens. - */ - - /* listener flags */ - 'use strict'; - - var ONCE = 1; - exports.ONCE = ONCE; - var SUSPENDED = 2; - - exports.SUSPENDED = SUSPENDED; - var protoMethods = { - - addToListeners: function (eventName, target, method, flags) { - if (!this._listeners) { - this._listeners = []; - } - this._listeners.push(eventName, target, method, flags); - }, - - _finalizeListeners: function () { - if (this._listenersFinalized) { - return; - } - if (!this._listeners) { - this._listeners = []; - } - var pointer = this.parent; - while (pointer) { - var listeners = pointer._listeners; - if (listeners) { - this._listeners = this._listeners.concat(listeners); - } - if (pointer._listenersFinalized) { - break; - } - pointer = pointer.parent; - } - this._listenersFinalized = true; - }, - - removeFromListeners: function (eventName, target, method, didRemove) { - var pointer = this; - while (pointer) { - var listeners = pointer._listeners; - if (listeners) { - for (var index = listeners.length - 4; index >= 0; index -= 4) { - if (listeners[index] === eventName && (!method || listeners[index + 1] === target && listeners[index + 2] === method)) { - if (pointer === this) { - // we are modifying our own list, so we edit directly - if (typeof didRemove === 'function') { - didRemove(eventName, target, listeners[index + 2]); - } - listeners.splice(index, 4); - } else { - // we are trying to remove an inherited listener, so we do - // just-in-time copying to detach our own listeners from - // our inheritance chain. - this._finalizeListeners(); - return this.removeFromListeners(eventName, target, method); - } - } - } - } - if (pointer._listenersFinalized) { - break; - } - pointer = pointer.parent; - } - }, - - matchingListeners: function (eventName) { - var pointer = this; - var result = []; - while (pointer) { - var listeners = pointer._listeners; - if (listeners) { - for (var index = 0; index < listeners.length - 3; index += 4) { - if (listeners[index] === eventName) { - pushUniqueListener(result, listeners, index); - } - } - } - if (pointer._listenersFinalized) { - break; - } - pointer = pointer.parent; - } - var sus = this._suspendedListeners; - if (sus) { - for (var susIndex = 0; susIndex < sus.length - 2; susIndex += 3) { - if (eventName === sus[susIndex]) { - for (var resultIndex = 0; resultIndex < result.length - 2; resultIndex += 3) { - if (result[resultIndex] === sus[susIndex + 1] && result[resultIndex + 1] === sus[susIndex + 2]) { - result[resultIndex + 2] |= SUSPENDED; - } - } - } - } - } - return result; - }, - - suspendListeners: function (eventNames, target, method, callback) { - var sus = this._suspendedListeners; - if (!sus) { - sus = this._suspendedListeners = []; - } - for (var i = 0; i < eventNames.length; i++) { - sus.push(eventNames[i], target, method); - } - try { - return callback.call(target); - } finally { - if (sus.length === eventNames.length) { - this._suspendedListeners = undefined; - } else { - for (var i = sus.length - 3; i >= 0; i -= 3) { - if (sus[i + 1] === target && sus[i + 2] === method && eventNames.indexOf(sus[i]) !== -1) { - sus.splice(i, 3); - } - } - } - } - }, - - watchedEvents: function () { - var pointer = this; - var names = {}; - while (pointer) { - var listeners = pointer._listeners; - if (listeners) { - for (var index = 0; index < listeners.length - 3; index += 4) { - names[listeners[index]] = true; - } - } - if (pointer._listenersFinalized) { - break; - } - pointer = pointer.parent; - } - return Object.keys(names); - }, - - _initializeListeners: function () { - this._listeners = undefined; - this._listenersFinalized = undefined; - this._suspendedListeners = undefined; - } - }; - - exports.protoMethods = protoMethods; - function pushUniqueListener(destination, source, index) { - var target = source[index + 1]; - var method = source[index + 2]; - for (var destinationIndex = 0; destinationIndex < destination.length - 2; destinationIndex += 3) { - if (destination[destinationIndex] === target && destination[destinationIndex + 1] === method) { - return; - } - } - destination.push(target, method, source[index + 3]); - } -}); enifed('ember-metal/mixin', ['exports', 'ember-metal/core', 'ember-metal/merge', 'ember-metal/empty_object', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-metal/utils', 'ember-metal/meta', 'ember-metal/expand_properties', 'ember-metal/properties', 'ember-metal/computed', 'ember-metal/binding', 'ember-metal/observer', 'ember-metal/events', 'ember-metal/streams/utils'], function (exports, _emberMetalCore, _emberMetalMerge, _emberMetalEmpty_object, _emberMetalProperty_get, _emberMetalProperty_set, _emberMetalUtils, _emberMetalMeta, _emberMetalExpand_properties, _emberMetalProperties, _emberMetalComputed, _emberMetalBinding, _emberMetalObserver, _emberMetalEvents, _emberMetalStreamsUtils) { // Remove "use strict"; from transpiled module until // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed // @@ -6847,10 +6858,13 @@ /** @module ember @submodule ember-metal */ + function ROOT() {} + ROOT.__hasSuper = false; + var REQUIRED; var a_slice = [].slice; function mixinsMeta(obj) { return _emberMetalMeta.meta(obj, true).writableMixins(); @@ -6992,11 +7006,11 @@ newBase[prop] = propValue; } } if (hasFunction) { - newBase._super = function () {}; + newBase._super = ROOT; } return newBase; } @@ -7189,11 +7203,11 @@ var values = {}; var m = _emberMetalMeta.meta(obj); var keys = []; var key, value, desc; - obj._super = function () {}; + obj._super = ROOT; // Go through all mixins and hashes passed in, and: // // * Handle concatenated properties // * Handle merged properties @@ -7567,11 +7581,11 @@ ``` @method aliasMethod @for Ember @param {String} methodName name of the method to alias - @private + @public */ function aliasMethod(methodName) { return new Alias(methodName); } @@ -7756,10 +7770,79 @@ exports.Mixin = Mixin; exports.required = required; exports.REQUIRED = REQUIRED; }); // warn, assert, wrap, et; +enifed('ember-metal/observer_set', ['exports', 'ember-metal/utils', 'ember-metal/events'], function (exports, _emberMetalUtils, _emberMetalEvents) { + 'use strict'; + + /* + this.observerSet = { + [senderGuid]: { // variable name: `keySet` + [keyName]: listIndex + } + }, + this.observers = [ + { + sender: obj, + keyName: keyName, + eventName: eventName, + listeners: [ + [target, method, flags] + ] + }, + ... + ] + */ + exports.default = ObserverSet; + + function ObserverSet() { + this.clear(); + } + + ObserverSet.prototype.add = function (sender, keyName, eventName) { + var observerSet = this.observerSet; + var observers = this.observers; + var senderGuid = _emberMetalUtils.guidFor(sender); + var keySet = observerSet[senderGuid]; + var index; + + if (!keySet) { + observerSet[senderGuid] = keySet = {}; + } + index = keySet[keyName]; + if (index === undefined) { + index = observers.push({ + sender: sender, + keyName: keyName, + eventName: eventName, + listeners: [] + }) - 1; + keySet[keyName] = index; + } + return observers[index].listeners; + }; + + ObserverSet.prototype.flush = function () { + var observers = this.observers; + var i, len, observer, sender; + this.clear(); + for (i = 0, len = observers.length; i < len; ++i) { + observer = observers[i]; + sender = observer.sender; + if (sender.isDestroying || sender.isDestroyed) { + continue; + } + _emberMetalEvents.sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); + } + }; + + ObserverSet.prototype.clear = function () { + this.observerSet = {}; + this.observers = []; + }; +}); enifed('ember-metal/observer', ['exports', 'ember-metal/watching', 'ember-metal/events'], function (exports, _emberMetalWatching, _emberMetalEvents) { 'use strict'; exports.addObserver = addObserver; exports.observersFor = observersFor; @@ -7870,79 +7953,10 @@ _emberMetalEvents.removeListener(obj, beforeEvent(path), target, method); return this; } }); -enifed('ember-metal/observer_set', ['exports', 'ember-metal/utils', 'ember-metal/events'], function (exports, _emberMetalUtils, _emberMetalEvents) { - 'use strict'; - - /* - this.observerSet = { - [senderGuid]: { // variable name: `keySet` - [keyName]: listIndex - } - }, - this.observers = [ - { - sender: obj, - keyName: keyName, - eventName: eventName, - listeners: [ - [target, method, flags] - ] - }, - ... - ] - */ - exports.default = ObserverSet; - - function ObserverSet() { - this.clear(); - } - - ObserverSet.prototype.add = function (sender, keyName, eventName) { - var observerSet = this.observerSet; - var observers = this.observers; - var senderGuid = _emberMetalUtils.guidFor(sender); - var keySet = observerSet[senderGuid]; - var index; - - if (!keySet) { - observerSet[senderGuid] = keySet = {}; - } - index = keySet[keyName]; - if (index === undefined) { - index = observers.push({ - sender: sender, - keyName: keyName, - eventName: eventName, - listeners: [] - }) - 1; - keySet[keyName] = index; - } - return observers[index].listeners; - }; - - ObserverSet.prototype.flush = function () { - var observers = this.observers; - var i, len, observer, sender; - this.clear(); - for (i = 0, len = observers.length; i < len; ++i) { - observer = observers[i]; - sender = observer.sender; - if (sender.isDestroying || sender.isDestroyed) { - continue; - } - _emberMetalEvents.sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); - } - }; - - ObserverSet.prototype.clear = function () { - this.observerSet = {}; - this.observers = []; - }; -}); enifed('ember-metal/path_cache', ['exports', 'ember-metal/cache'], function (exports, _emberMetalCache) { 'use strict'; exports.isGlobal = isGlobal; exports.isGlobalPath = isGlobalPath; @@ -9564,65 +9578,10 @@ } }); return properties; } }); -enifed('ember-metal/streams/conditional', ['exports', 'ember-metal/streams/stream', 'ember-metal/streams/utils'], function (exports, _emberMetalStreamsStream, _emberMetalStreamsUtils) { - 'use strict'; - - exports.default = conditional; - - function conditional(test, consequent, alternate) { - if (_emberMetalStreamsUtils.isStream(test)) { - return new ConditionalStream(test, consequent, alternate); - } else { - if (test) { - return consequent; - } else { - return alternate; - } - } - } - - function ConditionalStream(test, consequent, alternate) { - this.init(); - - this.oldTestResult = undefined; - this.test = test; - this.consequent = consequent; - this.alternate = alternate; - } - - ConditionalStream.prototype = Object.create(_emberMetalStreamsStream.default.prototype); - - ConditionalStream.prototype.compute = function () { - var oldTestResult = this.oldTestResult; - var newTestResult = !!_emberMetalStreamsUtils.read(this.test); - - if (newTestResult !== oldTestResult) { - switch (oldTestResult) { - case true: - _emberMetalStreamsUtils.unsubscribe(this.consequent, this.notify, this);break; - case false: - _emberMetalStreamsUtils.unsubscribe(this.alternate, this.notify, this);break; - case undefined: - _emberMetalStreamsUtils.subscribe(this.test, this.notify, this); - } - - switch (newTestResult) { - case true: - _emberMetalStreamsUtils.subscribe(this.consequent, this.notify, this);break; - case false: - _emberMetalStreamsUtils.subscribe(this.alternate, this.notify, this); - } - - this.oldTestResult = newTestResult; - } - - return newTestResult ? _emberMetalStreamsUtils.read(this.consequent) : _emberMetalStreamsUtils.read(this.alternate); - }; -}); enifed('ember-metal/streams/dependency', ['exports', 'ember-metal/core', 'ember-metal/merge', 'ember-metal/streams/utils'], function (exports, _emberMetalCore, _emberMetalMerge, _emberMetalStreamsUtils) { 'use strict'; /** @module ember-metal @@ -10377,11 +10336,11 @@ var labels = labelsFor(array); return 'concat([' + labels.join(', ') + ']; separator=' + inspect(separator) + ')'; }); for (i = 0, l = array.length; i < l; i++) { - subscribe(array[i], stream.notify, stream); + stream.addDependency(array[i]); } // used by angle bracket components to detect an attribute was provided // as a string literal stream.isConcat = true; @@ -10813,14 +10772,36 @@ } return ret; } } - var sourceAvailable = (function () { - return this; - }).toString().indexOf('return this;') > -1; + var checkHasSuper = (function () { + var sourceAvailable = (function () { + return this; + }).toString().indexOf('return this;') > -1; + if (sourceAvailable) { + return function checkHasSuper(func) { + return func.toString().indexOf('_super') > -1; + }; + } + + return function checkHasSuper() { + return true; + }; + })(); + + function ROOT() {} + ROOT.__hasSuper = false; + + function hasSuper(func) { + if (func.__hasSuper === undefined) { + func.__hasSuper = checkHasSuper(func); + } + return func.__hasSuper; + } + /** Wraps the passed function so that `this._super` will point to the superFunc when the function is invoked. This is the primitive we use to implement calls to super. @@ -10830,40 +10811,28 @@ @param {Function} func The function to call @param {Function} superFunc The super function. @return {Function} wrapped function. */ - function wrap(func, _superFunc) { - var superFunc = _superFunc; - var hasSuper; - if (sourceAvailable) { - hasSuper = func.__hasSuper; - - if (hasSuper === undefined) { - hasSuper = func.toString().indexOf('_super') > -1; - func.__hasSuper = hasSuper; - } - - if (!hasSuper) { - return func; - } + function wrap(func, superFunc) { + if (!hasSuper(func)) { + return func; } - - if (superFunc.wrappedFunction === undefined) { - // terminate _super to prevent infinite recursion - superFunc = wrap(superFunc, function () {}); + // ensure an unwrapped super that calls _super is wrapped with a terminal _super + if (!superFunc.wrappedFunction && hasSuper(superFunc)) { + return _wrap(func, _wrap(superFunc, ROOT)); } - return _wrap(func, superFunc); } function _wrap(func, superFunc) { function superWrapper() { - var ret; var orig = this._super; + var length = arguments.length; + var ret = undefined; this._super = superFunc; - switch (arguments.length) { + switch (length) { case 0: ret = func.call(this);break; case 1: ret = func.call(this, arguments[0]);break; case 2: @@ -10873,11 +10842,18 @@ case 4: ret = func.call(this, arguments[0], arguments[1], arguments[2], arguments[3]);break; case 5: ret = func.call(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);break; default: - ret = func.apply(this, arguments);break; + // v8 bug potentially incorrectly deopts this function: https://code.google.com/p/v8/issues/detail?id=3709 + // we may want to keep this around till this ages out on mobile + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + ret = func.apply(this, args); + break; } this._super = orig; return ret; } @@ -11348,21 +11324,22 @@ } } } } }); -enifed('ember-template-compiler', ['exports', 'ember-metal', 'ember-template-compiler/system/precompile', 'ember-template-compiler/system/compile', 'ember-template-compiler/system/template', 'ember-template-compiler/plugins', 'ember-template-compiler/plugins/transform-old-binding-syntax', 'ember-template-compiler/plugins/transform-old-class-binding-syntax', 'ember-template-compiler/plugins/transform-item-class', 'ember-template-compiler/plugins/transform-component-attrs-into-mut', 'ember-template-compiler/plugins/transform-component-curly-to-readonly', 'ember-template-compiler/plugins/transform-angle-bracket-components', 'ember-template-compiler/plugins/transform-input-on-to-onEvent', 'ember-template-compiler/plugins/transform-top-level-components', 'ember-template-compiler/plugins/transform-each-into-collection', 'ember-template-compiler/plugins/assert-no-view-and-controller-paths', 'ember-template-compiler/plugins/assert-no-view-helper', 'ember-template-compiler/compat'], function (exports, _emberMetal, _emberTemplateCompilerSystemPrecompile, _emberTemplateCompilerSystemCompile, _emberTemplateCompilerSystemTemplate, _emberTemplateCompilerPlugins, _emberTemplateCompilerPluginsTransformOldBindingSyntax, _emberTemplateCompilerPluginsTransformOldClassBindingSyntax, _emberTemplateCompilerPluginsTransformItemClass, _emberTemplateCompilerPluginsTransformComponentAttrsIntoMut, _emberTemplateCompilerPluginsTransformComponentCurlyToReadonly, _emberTemplateCompilerPluginsTransformAngleBracketComponents, _emberTemplateCompilerPluginsTransformInputOnToOnEvent, _emberTemplateCompilerPluginsTransformTopLevelComponents, _emberTemplateCompilerPluginsTransformEachIntoCollection, _emberTemplateCompilerPluginsAssertNoViewAndControllerPaths, _emberTemplateCompilerPluginsAssertNoViewHelper, _emberTemplateCompilerCompat) { +enifed('ember-template-compiler', ['exports', 'ember-metal', 'ember-template-compiler/system/precompile', 'ember-template-compiler/system/compile', 'ember-template-compiler/system/template', 'ember-template-compiler/plugins', 'ember-template-compiler/plugins/transform-old-binding-syntax', 'ember-template-compiler/plugins/transform-old-class-binding-syntax', 'ember-template-compiler/plugins/transform-item-class', 'ember-template-compiler/plugins/transform-component-attrs-into-mut', 'ember-template-compiler/plugins/transform-component-curly-to-readonly', 'ember-template-compiler/plugins/transform-angle-bracket-components', 'ember-template-compiler/plugins/transform-input-on-to-onEvent', 'ember-template-compiler/plugins/transform-top-level-components', 'ember-template-compiler/plugins/transform-each-into-collection', 'ember-template-compiler/plugins/transform-unescaped-inline-link-to', 'ember-template-compiler/plugins/assert-no-view-and-controller-paths', 'ember-template-compiler/plugins/assert-no-view-helper', 'ember-template-compiler/compat'], function (exports, _emberMetal, _emberTemplateCompilerSystemPrecompile, _emberTemplateCompilerSystemCompile, _emberTemplateCompilerSystemTemplate, _emberTemplateCompilerPlugins, _emberTemplateCompilerPluginsTransformOldBindingSyntax, _emberTemplateCompilerPluginsTransformOldClassBindingSyntax, _emberTemplateCompilerPluginsTransformItemClass, _emberTemplateCompilerPluginsTransformComponentAttrsIntoMut, _emberTemplateCompilerPluginsTransformComponentCurlyToReadonly, _emberTemplateCompilerPluginsTransformAngleBracketComponents, _emberTemplateCompilerPluginsTransformInputOnToOnEvent, _emberTemplateCompilerPluginsTransformTopLevelComponents, _emberTemplateCompilerPluginsTransformEachIntoCollection, _emberTemplateCompilerPluginsTransformUnescapedInlineLinkTo, _emberTemplateCompilerPluginsAssertNoViewAndControllerPaths, _emberTemplateCompilerPluginsAssertNoViewHelper, _emberTemplateCompilerCompat) { 'use strict'; _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformOldBindingSyntax.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformOldClassBindingSyntax.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformItemClass.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformComponentAttrsIntoMut.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformComponentCurlyToReadonly.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformAngleBracketComponents.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformInputOnToOnEvent.default); _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformTopLevelComponents.default); + _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformUnescapedInlineLinkTo.default); if (_emberMetal.default.ENV._ENABLE_LEGACY_VIEW_SUPPORT) { _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsTransformEachIntoCollection.default); } else { _emberTemplateCompilerPlugins.registerPlugin('ast', _emberTemplateCompilerPluginsAssertNoViewAndControllerPaths.default); @@ -12265,10 +12242,40 @@ } } exports.default = TransformTopLevelComponents; }); +enifed('ember-template-compiler/plugins/transform-unescaped-inline-link-to', ['exports'], function (exports) { + 'use strict'; + + exports.default = TransformUnescapedInlineLinkTo; + + function TransformUnescapedInlineLinkTo(options) { + this.options = options; + this.syntax = null; + } + + TransformUnescapedInlineLinkTo.prototype.transform = function TransformUnescapedInlineLinkTo_transform(ast) { + var b = this.syntax.builders; + var walker = new this.syntax.Walker(); + + walker.visit(ast, function (node) { + if (!validate(node)) { + return; + } + + node.escaped = true; + node.params[0] = b.sexpr(b.string('-html-safe'), [node.params[0]]); + }); + + return ast; + }; + + function validate(node) { + return node.type === 'MustacheStatement' && node.path.original === 'link-to' && !node.escaped; + } +}); enifed('ember-template-compiler/system/calculate-location-display', ['exports'], function (exports) { 'use strict'; exports.default = calculateLocationDisplay; @@ -12298,45 +12305,10 @@ } return moduleInfo; } }); -enifed('ember-template-compiler/system/compile', ['exports', 'ember-metal/core', 'ember-template-compiler/system/compile_options', 'ember-template-compiler/system/template'], function (exports, _emberMetalCore, _emberTemplateCompilerSystemCompile_options, _emberTemplateCompilerSystemTemplate) { - /** - @module ember - @submodule ember-template-compiler - */ - - 'use strict'; - - var compile; - - /** - Uses HTMLBars `compile` function to process a string into a compiled template. - - This is not present in production builds. - - @private - @method compile - @param {String} templateString This is the string to be compiled by HTMLBars. - @param {Object} options This is an options hash to augment the compiler options. - */ - - exports.default = function (templateString, options) { - if (!compile && _emberMetalCore.default.__loader.registry['htmlbars-compiler/compiler']) { - compile = requireModule('htmlbars-compiler/compiler').compile; - } - - if (!compile) { - throw new Error('Cannot call `compile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compile`.'); - } - - var templateSpec = compile(templateString, _emberTemplateCompilerSystemCompile_options.default(options)); - - return _emberTemplateCompilerSystemTemplate.default(templateSpec); - }; -}); enifed('ember-template-compiler/system/compile_options', ['exports', 'ember-metal/features', 'ember-metal/assign', 'ember-template-compiler/plugins'], function (exports, _emberMetalFeatures, _emberMetalAssign, _emberTemplateCompilerPlugins) { /** @module ember @submodule ember-template-compiler */ @@ -12373,11 +12345,11 @@ options.plugins = plugins; options.buildMeta = function buildMeta(program) { return { topLevel: detectTopLevel(program), - revision: 'Ember@2.1.0-beta.1', + revision: 'Ember@2.1.0-beta.3', loc: program.loc, moduleName: options.moduleName }; }; @@ -12428,10 +12400,45 @@ } return null; } }); +enifed('ember-template-compiler/system/compile', ['exports', 'ember-metal/core', 'ember-template-compiler/system/compile_options', 'ember-template-compiler/system/template'], function (exports, _emberMetalCore, _emberTemplateCompilerSystemCompile_options, _emberTemplateCompilerSystemTemplate) { + /** + @module ember + @submodule ember-template-compiler + */ + + 'use strict'; + + var compile; + + /** + Uses HTMLBars `compile` function to process a string into a compiled template. + + This is not present in production builds. + + @private + @method compile + @param {String} templateString This is the string to be compiled by HTMLBars. + @param {Object} options This is an options hash to augment the compiler options. + */ + + exports.default = function (templateString, options) { + if (!compile && _emberMetalCore.default.__loader.registry['htmlbars-compiler/compiler']) { + compile = requireModule('htmlbars-compiler/compiler').compile; + } + + if (!compile) { + throw new Error('Cannot call `compile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compile`.'); + } + + var templateSpec = compile(templateString, _emberTemplateCompilerSystemCompile_options.default(options)); + + return _emberTemplateCompilerSystemTemplate.default(templateSpec); + }; +}); enifed('ember-template-compiler/system/precompile', ['exports', 'ember-metal/core', 'ember-template-compiler/system/compile_options'], function (exports, _emberMetalCore, _emberTemplateCompilerSystemCompile_options) { /** @module ember @submodule ember-template-compiler */ @@ -13866,11 +13873,10 @@ enifed("htmlbars-runtime/hooks", ["exports", "./render", "../morph-range/morph-list", "../htmlbars-util/object-utils", "../htmlbars-util/morph-utils", "../htmlbars-util/template-utils"], function (exports, _render, _morphRangeMorphList, _htmlbarsUtilObjectUtils, _htmlbarsUtilMorphUtils, _htmlbarsUtilTemplateUtils) { "use strict"; exports.wrap = wrap; exports.wrapForHelper = wrapForHelper; - exports.hostYieldWithShadowTemplate = hostYieldWithShadowTemplate; exports.createScope = createScope; exports.createFreshScope = createFreshScope; exports.bindShadowScope = bindShadowScope; exports.createChildScope = createChildScope; exports.bindSelf = bindSelf; @@ -13893,10 +13899,11 @@ exports.element = element; exports.attribute = attribute; exports.subexpr = subexpr; exports.get = get; exports.getRoot = getRoot; + exports.getBlock = getBlock; exports.getChild = getChild; exports.getValue = getValue; exports.getCellOrValue = getCellOrValue; exports.component = component; exports.concat = concat; @@ -13998,23 +14005,20 @@ }; } function wrapForHelper(template, env, scope, morph, renderState, visitor) { if (!template) { - return { - yieldIn: yieldInShadowTemplate(null, env, scope, morph, renderState, visitor) - }; + return {}; } var yieldArgs = yieldTemplate(template, env, scope, morph, renderState, visitor); return { meta: template.meta, arity: template.arity, yield: yieldArgs, yieldItem: yieldItem(template, env, scope, morph, renderState, visitor), - yieldIn: yieldInShadowTemplate(template, env, scope, morph, renderState, visitor), raw: template, render: function (self, blockArguments) { yieldArgs(blockArguments, self); } @@ -14177,59 +14181,10 @@ } function isStableTemplate(template, lastYielded) { return !lastYielded.shadowTemplate && template === lastYielded.template; } - - function yieldInShadowTemplate(template, env, parentScope, morph, renderState, visitor) { - var hostYield = hostYieldWithShadowTemplate(template, env, parentScope, morph, renderState, visitor); - - return function (shadowTemplate, self) { - hostYield(shadowTemplate, env, self, []); - }; - } - - function hostYieldWithShadowTemplate(template, env, parentScope, morph, renderState, visitor) { - return function (shadowTemplate, env, self, blockArguments) { - renderState.morphToClear = null; - - if (morph.lastYielded && isStableShadowRoot(template, shadowTemplate, morph.lastYielded)) { - return morph.lastResult.revalidateWith(env, undefined, self, blockArguments, visitor); - } - - var shadowScope = env.hooks.createFreshScope(); - env.hooks.bindShadowScope(env, parentScope, shadowScope, renderState.shadowOptions); - blockToYield.arity = template.arity; - env.hooks.bindBlock(env, shadowScope, blockToYield); - - morph.lastYielded = { self: self, template: template, shadowTemplate: shadowTemplate }; - - // Render the shadow template with the block available - _render.default(shadowTemplate.raw, env, shadowScope, { renderNode: morph, self: self, blockArguments: blockArguments }); - }; - - function blockToYield(env, blockArguments, self, renderNode, shadowParent, visitor) { - if (renderNode.lastResult) { - renderNode.lastResult.revalidateWith(env, undefined, undefined, blockArguments, visitor); - } else { - var scope = parentScope; - - // Since a yielded template shares a `self` with its original context, - // we only need to create a new scope if the template has block parameters - if (template.arity) { - scope = env.hooks.createChildScope(parentScope); - } - - _render.default(template, env, scope, { renderNode: renderNode, self: self, blockArguments: blockArguments }); - } - } - } - - function isStableShadowRoot(template, shadowTemplate, lastYielded) { - return template === lastYielded.template && shadowTemplate === lastYielded.shadowTemplate; - } - function optionsFor(template, inverse, env, scope, morph, visitor) { // If there was a template yielded last time, set morphToClear so it will be cleared // if no template is yielded on this render. var morphToClear = morph.lastResult ? morph : null; var renderState = new _htmlbarsUtilTemplateUtils.RenderState(morphToClear, morph.morphList || null); @@ -14738,24 +14693,27 @@ yield: function (morph, env, scope, params, hash, template, inverse, visitor) { // the current scope is provided purely for the creation of shadow // scopes; it should not be provided to user code. var to = env.hooks.getValue(hash.to) || 'default'; - if (scope.blocks[to]) { - scope.blocks[to](env, params, hash.self, morph, scope, visitor); + var block = env.hooks.getBlock(scope, to); + + if (block) { + block.invoke(env, params, hash.self, morph, scope, visitor); } return true; }, hasBlock: function (morph, env, scope, params) { var name = env.hooks.getValue(params[0]) || 'default'; - return !!scope.blocks[name]; + return !!env.hooks.getBlock(scope, name); }, hasBlockParams: function (morph, env, scope, params) { var name = env.hooks.getValue(params[0]) || 'default'; - return !!(scope.blocks[name] && scope.blocks[name].arity); + var block = env.hooks.getBlock(scope, name); + return !!(block && block.arity); } }; exports.keywords = keywords; @@ -14951,10 +14909,14 @@ } else { return [undefined]; } } + function getBlock(scope, key) { + return scope.blocks[key]; + } + function getChild(value, key) { return value[key]; } function getValue(reference) { @@ -15017,10 +14979,11 @@ component: component, concat: concat, createFreshScope: createFreshScope, getChild: getChild, getRoot: getRoot, + getBlock: getBlock, getValue: getValue, getCellOrValue: getCellOrValue, keywords: keywords, linkRenderNode: linkRenderNode, partial: partial, @@ -15343,15 +15306,10 @@ this.scope = scope; this.shouldSetContent = shouldSetContent; this.bindScope(); - if (options.attributes !== undefined) { - nodes.push({ state: {} }); - this.statements.push(['attributes', attachAttributes(options.attributes)]); - } - if (options.self !== undefined) { this.bindSelf(options.self); } if (options.blockArguments !== undefined) { this.bindLocals(options.blockArguments); @@ -15587,12 +15545,10 @@ visitor.element(statement, morph, env, scope, template, visitor);break; case 'attribute': visitor.attribute(statement, morph, env, scope);break; case 'component': visitor.component(statement, morph, env, scope, template, visitor);break; - case 'attributes': - visitor.attributes(statement, morph, env, scope, this.fragment, visitor);break; } if (env.hooks.didRenderNode) { env.hooks.didRenderNode(morph, env, scope); } @@ -18841,11 +18797,16 @@ while (current) { nodes.push(current); current = current.nextMorph; } } else if (node.morphList) { - nodes.push(node.morphList); + var current = node.morphList.firstChildMorph; + + while (current) { + nodes.push(current); + current = current.nextMorph; + } } } } function validateChildMorphs(env, morph, visitor) { @@ -19049,47 +19010,57 @@ this.morphToClear = renderNode; this.shadowOptions = null; } - function blockFor(render, template, blockOptions) { - var block = function (env, blockArguments, self, renderNode, parentScope, visitor) { - if (renderNode.lastResult) { - renderNode.lastResult.revalidateWith(env, undefined, self, blockArguments, visitor); - } else { + function Block(render, template, blockOptions) { + this.render = render; + this.template = template; + this.blockOptions = blockOptions; + this.arity = template.arity; + } + + Block.prototype.invoke = function (env, blockArguments, self, renderNode, parentScope, visitor) { + var _this = this; + + if (renderNode.lastResult) { + renderNode.lastResult.revalidateWith(env, undefined, self, blockArguments, visitor); + } else { + (function () { var options = { renderState: new RenderState(renderNode) }; + var render = _this.render; + var template = _this.template; + var scope = _this.blockOptions.scope; - var scope = blockOptions.scope; var shadowScope = scope ? env.hooks.createChildScope(scope) : env.hooks.createFreshScope(); - var attributes = blockOptions.attributes; - env.hooks.bindShadowScope(env, parentScope, shadowScope, blockOptions.options); + env.hooks.bindShadowScope(env, parentScope, shadowScope, _this.blockOptions.options); if (self !== undefined) { env.hooks.bindSelf(env, shadowScope, self); - } else if (blockOptions.self !== undefined) { - env.hooks.bindSelf(env, shadowScope, blockOptions.self); + } else if (_this.blockOptions.self !== undefined) { + env.hooks.bindSelf(env, shadowScope, _this.blockOptions.self); } - bindBlocks(env, shadowScope, blockOptions.yieldTo); + bindBlocks(env, shadowScope, _this.blockOptions.yieldTo); renderAndCleanup(renderNode, env, options, null, function () { options.renderState.morphToClear = null; - render(template, env, shadowScope, { renderNode: renderNode, blockArguments: blockArguments, attributes: attributes }); + render(template, env, shadowScope, { renderNode: renderNode, blockArguments: blockArguments }); }); - } - }; + })(); + } + }; - block.arity = template.arity; - - return block; + function blockFor(render, template, blockOptions) { + return new Block(render, template, blockOptions); } function bindBlocks(env, shadowScope, blocks) { if (!blocks) { return; } - if (typeof blocks === 'function') { + if (blocks instanceof Block) { env.hooks.bindBlock(env, shadowScope, blocks); } else { for (var name in blocks) { if (blocks.hasOwnProperty(name)) { env.hooks.bindBlock(env, shadowScope, blocks[name], name); \ No newline at end of file