dist/ember-runtime.js in ember-source-1.2.2 vs dist/ember-runtime.js in ember-source-1.3.0.beta.1
- old
+ new
@@ -6,11 +6,11 @@
// License: Licensed under MIT license
// See https://raw.github.com/emberjs/ember.js/master/LICENSE
// ==========================================================================
- // Version: 1.2.2
+ // Version: 1.3.0-beta.1
(function() {
/*global __fail__*/
/**
@@ -192,11 +192,11 @@
// License: Licensed under MIT license
// See https://raw.github.com/emberjs/ember.js/master/LICENSE
// ==========================================================================
- // Version: 1.2.2
+ // Version: 1.3.0-beta.1
(function() {
var define, requireModule;
(function() {
@@ -257,11 +257,11 @@
The core Runtime framework is based on the jQuery API with a number of
performance optimizations.
@class Ember
@static
- @version 1.2.2
+ @version 1.3.0-beta.1
*/
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.
@@ -284,14 +284,14 @@
/**
@property VERSION
@type String
- @default '1.2.2'
+ @default '1.3.0-beta.1'
@final
*/
-Ember.VERSION = '1.2.2';
+Ember.VERSION = '1.3.0-beta.1';
/**
Standard environmental variables. You can define these in a global `ENV`
variable before loading Ember to control various configuration
settings.
@@ -3973,15 +3973,11 @@
})();
(function() {
-/**
- @module ember-metal
-*/
-
})();
(function() {
@@ -4045,11 +4041,10 @@
unwatchPath = Ember.unwatchPath,
typeOf = Ember.typeOf, // utils.js
generateGuid = Ember.generateGuid,
IS_PATH = /[\.\*]/;
-
// returns true if the passed path is just a keyName
function isKeyName(path) {
return path==='*' || !IS_PATH.test(path);
}
@@ -4069,17 +4064,15 @@
*/
Ember.watch = function(obj, _keyPath) {
// can't watch length on Array - it is special...
if (_keyPath === 'length' && typeOf(obj) === 'array') { return; }
-
- if (isKeyName(_keyPath)) {
- watchKey(obj, _keyPath);
- } else {
- watchPath(obj, _keyPath);
- }
-
+ if (isKeyName(_keyPath)) {
+ watchKey(obj, _keyPath);
+ } else {
+ watchPath(obj, _keyPath);
+ }
};
Ember.isWatching = function isWatching(obj, key) {
var meta = obj[META_KEY];
return (meta && meta.watching[key]) > 0;
@@ -4089,17 +4082,15 @@
Ember.unwatch = function(obj, _keyPath) {
// can't watch length on Array - it is special...
if (_keyPath === 'length' && typeOf(obj) === 'array') { return; }
-
- if (isKeyName(_keyPath)) {
- unwatchKey(obj, _keyPath);
- } else {
- unwatchPath(obj, _keyPath);
- }
-
+ if (isKeyName(_keyPath)) {
+ unwatchKey(obj, _keyPath);
+ } else {
+ unwatchPath(obj, _keyPath);
+ }
};
/**
@private
@@ -4441,19 +4432,16 @@
@param {String} path* zero or more property paths
@return {Ember.ComputedProperty} this
@chainable
*/
ComputedPropertyPrototype.property = function() {
- var addArg;
+ var args;
- var args = [];
- for (var i = 0, l = arguments.length; i < l; i++) {
-
- args.push(arguments[i]);
-
- }
+ args = a_slice.call(arguments);
+
+
this._dependentKeys = args;
return this;
};
/**
@@ -5302,11 +5290,10 @@
*/
var AFTER_OBSERVERS = ':change',
BEFORE_OBSERVERS = ':before';
-
function changeEvent(keyName) {
return keyName+AFTER_OBSERVERS;
}
function beforeEvent(keyName) {
@@ -5319,14 +5306,12 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.addObserver = function(obj, _path, target, method) {
-
- Ember.addListener(obj, changeEvent(_path), target, method);
- Ember.watch(obj, _path);
-
+ Ember.addListener(obj, changeEvent(_path), target, method);
+ Ember.watch(obj, _path);
return this;
};
Ember.observersFor = function(obj, path) {
@@ -5339,14 +5324,13 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.removeObserver = function(obj, _path, target, method) {
-
- Ember.unwatch(obj, _path);
- Ember.removeListener(obj, changeEvent(_path), target, method);
-
+ Ember.unwatch(obj, _path);
+ Ember.removeListener(obj, changeEvent(_path), target, method);
+
return this;
};
/**
@method addBeforeObserver
@@ -5354,14 +5338,13 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.addBeforeObserver = function(obj, _path, target, method) {
-
- Ember.addListener(obj, beforeEvent(_path), target, method);
- Ember.watch(obj, _path);
-
+ Ember.addListener(obj, beforeEvent(_path), target, method);
+ Ember.watch(obj, _path);
+
return this;
};
// Suspend observer during callback.
//
@@ -5397,14 +5380,13 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.removeBeforeObserver = function(obj, _path, target, method) {
-
- Ember.unwatch(obj, _path);
- Ember.removeListener(obj, beforeEvent(_path), target, method);
-
+ Ember.unwatch(obj, _path);
+ Ember.removeListener(obj, beforeEvent(_path), target, method);
+
return this;
};
})();
@@ -6084,11 +6066,10 @@
return ret;
};
/**
-
If no run-loop is present, it creates a new one. If a run loop is
present it will queue itself to run on the existing run-loops action
queue.
Please note: This is not for normal usage, and should be used sparingly.
@@ -7030,10 +7011,11 @@
a_slice = [].slice,
o_create = Ember.create,
defineProperty = Ember.defineProperty,
guidFor = Ember.guidFor;
+
function mixinsMeta(obj) {
var m = Ember.meta(obj, true), ret = m.mixins;
if (!ret) {
ret = m.mixins = {};
} else if (!m.hasOwnProperty('mixins')) {
@@ -7683,19 +7665,23 @@
@param {Function} func
@return func
*/
Ember.observer = function() {
var func = a_slice.call(arguments, -1)[0];
- var paths = a_slice.call(arguments, 0, -1);
+ var paths;
- if (typeof func !== "function") {
- // revert to old, soft-deprecated argument ordering
+
+ paths = a_slice.call(arguments, 0, -1);
- func = arguments[0];
- paths = a_slice.call(arguments, 1);
- }
+ if (typeof func !== "function") {
+ // revert to old, soft-deprecated argument ordering
+ func = arguments[0];
+ paths = a_slice.call(arguments, 1);
+ }
+
+
if (typeof func !== "function") {
throw new Ember.Error("Ember.observer called without a function");
}
func.__ember_observes__ = paths;
@@ -7777,19 +7763,23 @@
@param {Function} func
@return func
*/
Ember.beforeObserver = function() {
var func = a_slice.call(arguments, -1)[0];
- var paths = a_slice.call(arguments, 0, -1);
+ var paths;
- if (typeof func !== "function") {
- // revert to old, soft-deprecated argument ordering
+
+ paths = a_slice.call(arguments, 0, -1);
- func = arguments[0];
- paths = a_slice.call(arguments, 1);
- }
+ if (typeof func !== "function") {
+ // revert to old, soft-deprecated argument ordering
+ func = arguments[0];
+ paths = a_slice.call(arguments, 1);
+ }
+
+
if (typeof func !== "function") {
throw new Ember.Error("Ember.beforeObserver called without a function");
}
func.__ember_observesBefore__ = paths;
@@ -7908,97 +7898,149 @@
__exports__.all = all;
});
define("rsvp/async",
- ["exports"],
- function(__exports__) {
+ ["rsvp/config","exports"],
+ function(__dependency1__, __exports__) {
"use strict";
+ var config = __dependency1__.config;
+
var browserGlobal = (typeof window !== 'undefined') ? window : {};
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
- var async;
var local = (typeof global !== 'undefined') ? global : this;
- // old node
+ // node
function useNextTick() {
- return function(callback, arg) {
- process.nextTick(function() {
- callback(arg);
- });
+ return function() {
+ process.nextTick(flush);
};
}
- // node >= 0.10.x
- function useSetImmediate() {
- return function(callback, arg) {
- /* global setImmediate */
- setImmediate(function(){
- callback(arg);
- });
- };
- }
-
function useMutationObserver() {
- var queue = [];
-
- var observer = new BrowserMutationObserver(function() {
- var toProcess = queue.slice();
- queue = [];
-
- toProcess.forEach(function(tuple) {
- var callback = tuple[0], arg= tuple[1];
- callback(arg);
- });
- });
-
+ var observer = new BrowserMutationObserver(flush);
var element = document.createElement('div');
observer.observe(element, { attributes: true });
// Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661
window.addEventListener('unload', function(){
observer.disconnect();
observer = null;
}, false);
- return function(callback, arg) {
- queue.push([callback, arg]);
+ return function() {
element.setAttribute('drainQueue', 'drainQueue');
};
}
function useSetTimeout() {
- return function(callback, arg) {
- local.setTimeout(function() {
- callback(arg);
- }, 1);
+ return function() {
+ local.setTimeout(flush, 1);
};
}
- if (typeof setImmediate === 'function') {
- async = useSetImmediate();
- } else if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
- async = useNextTick();
+ var queue = [];
+ function flush() {
+ for (var i = 0; i < queue.length; i++) {
+ var tuple = queue[i];
+ var callback = tuple[0], arg = tuple[1];
+ callback(arg);
+ }
+ queue = [];
+ }
+
+ var scheduleFlush;
+
+ // Decide what async method to use to triggering processing of queued callbacks:
+ if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
+ scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) {
- async = useMutationObserver();
+ scheduleFlush = useMutationObserver();
} else {
- async = useSetTimeout();
+ scheduleFlush = useSetTimeout();
}
+ function asyncDefault(callback, arg) {
+ var length = queue.push([callback, arg]);
+ if (length === 1) {
+ // If length is 1, that means that we need to schedule an async flush.
+ // If additional callbacks are queued before the queue is flushed, they
+ // will be processed by this flush that we are scheduling.
+ scheduleFlush();
+ }
+ }
+ config.async = asyncDefault;
+
+ function async(callback, arg) {
+ config.async(callback, arg);
+ }
+
+
__exports__.async = async;
+ __exports__.asyncDefault = asyncDefault;
});
+define("rsvp/cast",
+ ["exports"],
+ function(__exports__) {
+ "use strict";
+ function cast(object) {
+ /*jshint validthis:true */
+ if (object && typeof object === 'object' && object.constructor === this) {
+ return object;
+ }
+
+ var Promise = this;
+
+ return new Promise(function(resolve) {
+ resolve(object);
+ });
+ }
+
+
+ __exports__.cast = cast;
+ });
define("rsvp/config",
- ["rsvp/async","exports"],
+ ["rsvp/events","exports"],
function(__dependency1__, __exports__) {
"use strict";
- var async = __dependency1__.async;
+ var EventTarget = __dependency1__.EventTarget;
var config = {};
- config.async = async;
+ EventTarget.mixin(config);
+ function configure(name, value) {
+ if (name === 'onerror') {
+ // handle for legacy users that expect the actual
+ // error to be passed to their function added via
+ // `RSVP.configure('onerror', someFunctionHere);`
+ config.on('error', function(event){
+ value(event.detail);
+ });
+ } else {
+ config[name] = value;
+ }
+ }
+ function on(){
+ return config.on.apply(config, arguments);
+ }
+
+ function off(){
+ return config.off.apply(config, arguments);
+ }
+
+ function trigger(){
+ return config.trigger.apply(config, arguments);
+ }
+
+
__exports__.config = config;
+ __exports__.configure = configure;
+ __exports__.on = on;
+ __exports__.off = off;
+ __exports__.trigger = trigger;
});
define("rsvp/defer",
["rsvp/promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
@@ -8223,25 +8265,26 @@
__exports__.denodeify = denodeify;
});
define("rsvp/promise",
- ["rsvp/config","rsvp/events","exports"],
- function(__dependency1__, __dependency2__, __exports__) {
+ ["rsvp/config","rsvp/events","rsvp/cast","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
"use strict";
var config = __dependency1__.config;
var EventTarget = __dependency2__.EventTarget;
+ var cast = __dependency3__.cast;
function objectOrFunction(x) {
return isFunction(x) || (typeof x === "object" && x !== null);
}
function isFunction(x){
return typeof x === "function";
}
- var Promise = function(resolver) {
+ function Promise(resolver) {
var promise = this,
resolved = false;
if (typeof resolver !== 'function') {
throw new TypeError('You must pass a resolver function as the sole argument to the promise constructor');
@@ -8261,31 +8304,15 @@
if (resolved) { return; }
resolved = true;
reject(promise, value);
};
- this.on('promise:resolved', function(event) {
- this.trigger('success', { detail: event.detail });
- }, this);
-
- this.on('promise:failed', function(event) {
- this.trigger('error', { detail: event.detail });
- }, this);
-
- this.on('error', onerror);
-
try {
resolver(resolvePromise, rejectPromise);
} catch(e) {
rejectPromise(e);
}
- };
-
- function onerror(event) {
- if (config.onerror) {
- config.onerror(event.detail);
- }
}
var invokeCallback = function(type, promise, callback, event) {
var hasCallback = isFunction(callback),
value, error, succeeded, failed;
@@ -8316,18 +8343,23 @@
}
};
Promise.prototype = {
constructor: Promise,
-
isRejected: undefined,
isFulfilled: undefined,
rejectedReason: undefined,
fulfillmentValue: undefined,
+ _onerror: function (reason) {
+ config.trigger('error', {
+ detail: reason
+ });
+ },
+
then: function(done, fail) {
- this.off('error', onerror);
+ this._onerror = null;
var thenPromise = new this.constructor(function() {});
if (this.isFulfilled) {
config.async(function(promise) {
@@ -8350,15 +8382,31 @@
});
return thenPromise;
},
- fail: function(fail) {
- return this.then(null, fail);
+ fail: function(onRejection) {
+ return this.then(null, onRejection);
+ },
+ 'finally': function(callback) {
+ var constructor = this.constructor;
+
+ return this.then(function(value) {
+ return constructor.cast(callback()).then(function(){
+ return value;
+ });
+ }, function(reason) {
+ return constructor.cast(callback()).then(function(){
+ throw reason;
+ });
+ });
}
};
+ Promise.prototype['catch'] = Promise.prototype.fail;
+ Promise.cast = cast;
+
EventTarget.mixin(Promise.prototype);
function resolve(promise, value) {
if (promise === value) {
fulfill(promise, value);
@@ -8415,10 +8463,11 @@
});
}
function reject(promise, value) {
config.async(function() {
+ if (promise._onerror) { promise._onerror(value); }
promise.trigger('promise:failed', { detail: value });
promise.isRejected = true;
promise.rejectedReason = value;
});
}
@@ -8471,40 +8520,48 @@
__exports__.rethrow = rethrow;
});
define("rsvp",
- ["rsvp/events","rsvp/promise","rsvp/node","rsvp/all","rsvp/hash","rsvp/rethrow","rsvp/defer","rsvp/config","rsvp/resolve","rsvp/reject","exports"],
- function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) {
+ ["rsvp/events","rsvp/promise","rsvp/node","rsvp/all","rsvp/hash","rsvp/rethrow","rsvp/defer","rsvp/config","rsvp/resolve","rsvp/reject","rsvp/async","exports"],
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) {
"use strict";
var EventTarget = __dependency1__.EventTarget;
var Promise = __dependency2__.Promise;
var denodeify = __dependency3__.denodeify;
var all = __dependency4__.all;
var hash = __dependency5__.hash;
var rethrow = __dependency6__.rethrow;
var defer = __dependency7__.defer;
var config = __dependency8__.config;
+ var configure = __dependency8__.configure;
+ var on = __dependency8__.on;
+ var off = __dependency8__.off;
+ var trigger = __dependency8__.trigger;
var resolve = __dependency9__.resolve;
var reject = __dependency10__.reject;
+ var async = __dependency11__.async;
+ var asyncDefault = __dependency11__.asyncDefault;
- function configure(name, value) {
- config[name] = value;
- }
-
__exports__.Promise = Promise;
__exports__.EventTarget = EventTarget;
__exports__.all = all;
__exports__.hash = hash;
__exports__.rethrow = rethrow;
__exports__.defer = defer;
__exports__.denodeify = denodeify;
__exports__.configure = configure;
+ __exports__.trigger = trigger;
+ __exports__.on = on;
+ __exports__.off = off;
__exports__.resolve = resolve;
__exports__.reject = reject;
+ __exports__.async = async;
+ __exports__.asyncDefault = asyncDefault;
});
+
})();
(function() {
/**
@private
@@ -9117,11 +9174,10 @@
one would do the following:
```javascript
var container = new Container();
- container.registerFactory('model:user', User);
container.register('store:main', SomeStore);
container.factoryTypeInjection('model', 'store', 'store:main');
var store = container.lookup('store:main');
@@ -9205,11 +9261,10 @@
their managed objects.
@method destroy
*/
destroy: function() {
- this.isDestroyed = true;
for (var i=0, l=this.children.length; i<l; i++) {
this.children[i].destroy();
}
@@ -10645,16 +10700,18 @@
for (var i = 0, l = props.length; i < l; i++) {
var properties = props[i];
Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin));
- if (properties === null || typeof properties !== 'object') {
- Ember.assert("Ember.Object.create only accepts objects.");
- continue;
+ if (typeof properties !== 'object' && properties !== undefined) {
+ throw new Ember.Error("Ember.Object.create only accepts objects.");
}
+ if (!properties) { continue; }
+
var keyNames = Ember.keys(properties);
+
for (var j = 0, ll = keyNames.length; j < ll; j++) {
var keyName = keyNames[j];
if (!properties.hasOwnProperty(keyName)) { continue; }
var value = properties[keyName],
@@ -11761,11 +11818,11 @@
1. You must have a length property. This property should change whenever
the number of items in your enumerable object changes. If you using this
with an `Ember.Object` subclass, you should be sure to change the length
property using `set().`
- 2. If you must implement `nextObject().` See documentation.
+ 2. You must implement `nextObject().` See documentation.
Once you have these two methods implement, apply the `Ember.Enumerable` mixin
to your class and you will be able to enumerate the contents of your object
like any other collection.
@@ -12261,33 +12318,39 @@
return !callback.call(target, x, idx, i);
});
},
/**
- Returns `true` if the passed property resolves to `true` for all items in
- the enumerable. This method is often simpler/faster than using a callback.
-
@method everyBy
@param {String} key the property to test
@param {String} [value] optional value to test against.
+ @deprecated Use `isEvery` instead
@return {Boolean}
*/
- everyBy: function(key, value) {
- return this.every(iter.apply(this, arguments));
- },
+ everyBy: Ember.aliasMethod('isEvery'),
/**
+ @method everyProperty
+ @param {String} key the property to test
+ @param {String} [value] optional value to test against.
+ @deprecated Use `isEvery` instead
+ @return {Boolean}
+ */
+ everyProperty: Ember.aliasMethod('isEvery'),
+
+ /**
Returns `true` if the passed property resolves to `true` for all items in
the enumerable. This method is often simpler/faster than using a callback.
- @method everyProperty
+ @method isEvery
@param {String} key the property to test
@param {String} [value] optional value to test against.
@return {Boolean}
- @deprecated Use `everyBy` instead
*/
- everyProperty: Ember.aliasMethod('everyBy'),
+ isEvery: function(key, value) {
+ return this.every(iter.apply(this, arguments));
+ },
/**
Returns `true` if the passed function returns true for any item in the
enumeration. This corresponds with the `some()` method in JavaScript 1.6.
@@ -12371,25 +12434,31 @@
@method anyBy
@param {String} key the property to test
@param {String} [value] optional value to test against.
@return {Boolean} `true` if the passed function returns `true` for any item
*/
- anyBy: function(key, value) {
+ isAny: function(key, value) {
return this.any(iter.apply(this, arguments));
},
/**
- Returns `true` if the passed property resolves to `true` for any item in
- the enumerable. This method is often simpler/faster than using a callback.
+ @method someProperty
+ @param {String} key the property to test
+ @param {String} [value] optional value to test against.
+ @return {Boolean} `true` if the passed function returns `true` for any item
+ @deprecated Use `isAny` instead
+ */
+ anyBy: Ember.aliasMethod('isAny'),
+ /**
@method someProperty
@param {String} key the property to test
@param {String} [value] optional value to test against.
@return {Boolean} `true` if the passed function returns `true` for any item
- @deprecated Use `anyBy` instead
+ @deprecated Use `isAny` instead
*/
- someProperty: Ember.aliasMethod('anyBy'),
+ someProperty: Ember.aliasMethod('isAny'),
/**
This will combine the values of the enumerator into a single value. It
is a useful way to collect a summary value from an enumeration. This
corresponds to the `reduce()` method defined in JavaScript 1.8.
@@ -12673,43 +12742,38 @@
Ember.sendEvent(this, '@enumerable:change', [this, removing, adding]);
if (hasDelta) Ember.propertyDidChange(this, 'length');
Ember.propertyDidChange(this, '[]');
return this ;
- }
+ },
-});
+ /**
+ Converts the enumerable into an array and sorts by the keys
+ specified in the argument.
+ You may provide multiple arguments to sort by multiple properties.
- Ember.Enumerable.reopen({
- /**
- Converts the enumerable into an array and sorts by the keys
- specified in the argument.
-
- You may provide multiple arguments to sort by multiple properties.
-
- @method sortBy
- @param {String} property name(s) to sort on
- @return {Array} The sorted array.
+ @method sortBy
+ @param {String} property name(s) to sort on
+ @return {Array} The sorted array.
*/
- sortBy: function() {
- var sortKeys = arguments;
- return this.toArray().sort(function(a, b){
- for(var i = 0; i < sortKeys.length; i++) {
- var key = sortKeys[i],
- propA = get(a, key),
- propB = get(b, key);
- // return 1 or -1 else continue to the next sortKey
- var compareValue = Ember.compare(propA, propB);
- if (compareValue) { return compareValue; }
- }
- return 0;
- });
- }
- });
+ sortBy: function() {
+ var sortKeys = arguments;
+ return this.toArray().sort(function(a, b){
+ for(var i = 0; i < sortKeys.length; i++) {
+ var key = sortKeys[i],
+ propA = get(a, key),
+ propB = get(b, key);
+ // return 1 or -1 else continue to the next sortKey
+ var compareValue = Ember.compare(propA, propB);
+ if (compareValue) { return compareValue; }
+ }
+ return 0;
+ });
+ }
+});
-
})();
(function() {
@@ -13157,18 +13221,18 @@
o_create = Ember.create,
forEach = Ember.EnumerableUtils.forEach,
// Here we explicitly don't allow `@each.foo`; it would require some special
// testing, but there's no particular reason why it should be disallowed.
eachPropertyPattern = /^(.*)\.@each\.(.*)/,
- doubleEachPropertyPattern = /(.*\.@each){2,}/;
+ doubleEachPropertyPattern = /(.*\.@each){2,}/,
+ arrayBracketPattern = /\.\[\]$/;
+
function get(obj, key) {
-
- if (key === '@this') {
- return obj;
- }
-
+ if (key === '@this') {
+ return obj;
+ }
return e_get(obj, key);
}
/*
@@ -13528,10 +13592,19 @@
if (cp.options.initialize) {
cp.options.initialize.call(this, meta.getValue(), { property: cp, propertyName: propertyName }, meta.sugarMeta);
}
}
+function partiallyRecomputeFor(obj, dependentKey) {
+ if (arrayBracketPattern.test(dependentKey)) {
+ return false;
+ }
+
+ var value = get(obj, dependentKey);
+ return Ember.Array.detect(value);
+}
+
function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) {
this.context = context;
this.propertyName = propertyName;
this.cache = metaFor(context).cache;
@@ -13608,10 +13681,14 @@
reset.call(this, cp, propertyName);
meta.dependentArraysObserver.suspendArrayObservers(function () {
forEach(cp._dependentKeys, function (dependentKey) {
+
+ if (!partiallyRecomputeFor(this, dependentKey)) { return; }
+
+
var dependentArray = get(this, dependentKey),
previousDependentArray = meta.dependentArrays[dependentKey];
if (dependentArray === previousDependentArray) {
// The array may be the same, but our item property keys may have
@@ -13635,10 +13712,14 @@
}
}, this);
}, this);
forEach(cp._dependentKeys, function(dependentKey) {
+
+ if (!partiallyRecomputeFor(this, dependentKey)) { return; }
+
+
var dependentArray = get(this, dependentKey);
if (dependentArray) {
addItems.call(this, dependentArray, callbacks, cp, propertyName, meta);
}
}, this);
@@ -13727,19 +13808,23 @@
forEach(a_slice.call(arguments), function (dependentKey) {
if (doubleEachPropertyPattern.test(dependentKey)) {
throw new Ember.Error("Nested @each properties not supported: " + dependentKey);
} else if (match = eachPropertyPattern.exec(dependentKey)) {
dependentArrayKey = match[1];
- itemPropertyKey = match[2];
- cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
+
+
+ itemPropertyKey = match[2];
+ cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
+
propertyArgs.add(dependentArrayKey);
} else {
propertyArgs.add(dependentKey);
}
});
return ComputedProperty.prototype.property.apply(this, propertyArgs.toArray());
+
};
/**
Creates a computed property which operates on dependent arrays and
is updated with "one at a time" semantics. When items are added or
@@ -13885,10 +13970,38 @@
return reverse(get(this, 'name'));
}.property('name')
})
```
+ Dependent keys whose values are not arrays are treated as regular
+ dependencies: when they change, the computed property is completely
+ recalculated. It is sometimes useful to have dependent arrays with similar
+ semantics. Dependent keys which end in `.[]` do not use "one at a time"
+ semantics. When an item is added or removed from such a dependency, the
+ computed property is completely recomputed.
+
+ Example
+
+ ```javascript
+ Ember.Object.extend({
+ // When `string` is changed, `computed` is completely recomputed.
+ string: 'a string',
+
+ // When an item is added to `array`, `addedItem` is called.
+ array: [],
+
+ // When an item is added to `anotherArray`, `computed` is completely
+ // recomputed.
+ anotherArray: [],
+
+ computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', {
+ addedItem: addedItemCallback,
+ removedItem: removedItemCallback
+ })
+ });
+ ```
+
@method reduceComputed
@for Ember
@param {String} [dependentKeys*]
@param {Object} options
@return {Ember.ComputedProperty}
@@ -14819,10 +14932,26 @@
@namespace Ember
@constructor
*/
Ember.RSVP = requireModule('rsvp');
+Ember.RSVP.onerrorDefault = function(event) {
+ var error = event.detail;
+
+ if (error instanceof Error) {
+ Ember.Logger.error(error.stack);
+
+ if (Ember.testing) {
+ throw error;
+ } else {
+ Ember.assert(error, false);
+ }
+ }
+};
+
+Ember.RSVP.on('error', Ember.RSVP.onerrorDefault);
+
})();
(function() {
@@ -14831,10 +14960,11 @@
@submodule ember-runtime
*/
var a_slice = Array.prototype.slice;
+
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
/**
The `property` extension of Javascript's Function prototype is available
when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is
@@ -14895,10 +15025,12 @@
@method property
@for Function
*/
Function.prototype.property = function() {
var ret = Ember.computed(this);
+ // ComputedProperty.prototype.property expands properties; no need for us to
+ // do so here.
return ret.property.apply(ret, arguments);
};
/**
The `observes` extension of Javascript's Function prototype is available
@@ -14924,11 +15056,14 @@
@method observes
@for Function
*/
Function.prototype.observes = function() {
- this.__ember_observes__ = a_slice.call(arguments);
+
+ this.__ember_observes__ = a_slice.call(arguments);
+
+
return this;
};
/**
The `observesImmediately` extension of Javascript's Function prototype is
@@ -14959,10 +15094,11 @@
for (var i=0, l=arguments.length; i<l; i++) {
var arg = arguments[i];
Ember.assert("Immediate observers must observe internal properties only, not properties on other objects.", arg.indexOf('.') === -1);
}
+ // observes handles property expansion
return this.observes.apply(this, arguments);
};
/**
The `observesBefore` extension of Javascript's Function prototype is
@@ -14985,10 +15121,13 @@
@method observesBefore
@for Function
*/
Function.prototype.observesBefore = function() {
- this.__ember_observesBefore__ = a_slice.call(arguments);
+
+ this.__ember_observesBefore__ = a_slice.call(arguments);
+
+
return this;
};
/**
The `on` extension of Javascript's Function prototype is available