dist/ember-runtime.js in ember-source-1.2.0.beta.1 vs dist/ember-runtime.js in ember-source-1.2.0.beta.2
- old
+ new
@@ -6,11 +6,11 @@
// License: Licensed under MIT license
// See https://raw.github.com/emberjs/ember.js/master/LICENSE
// ==========================================================================
- // Version: 1.2.0-beta.1
+ // Version: 1.2.0-beta.2
(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.0-beta.1
+ // Version: 1.2.0-beta.2
(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.0-beta.1
+ @version 1.2.0-beta.2
*/
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.0-beta.1'
+ @default '1.2.0-beta.2'
@final
*/
-Ember.VERSION = '1.2.0-beta.1';
+Ember.VERSION = '1.2.0-beta.2';
/**
Standard environmental variables. You can define these in a global `ENV`
variable before loading Ember to control various configuration
settings.
@@ -327,19 +327,32 @@
/**
Test that a feature is enabled. Parsed by Ember's build tools to leave
experimental features out of beta/stable builds.
- You can define an `ENV.ENABLE_ALL_FEATURES` config to force all features to
- be enabled.
+ You can define the following configuration options:
+ * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled.
+ * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly
+ enabled/disabled.
+
@method isEnabled
@param {string} feature
*/
Ember.FEATURES.isEnabled = function(feature) {
- return Ember.ENV.ENABLE_ALL_FEATURES || Ember.FEATURES[feature];
+ var featureValue = Ember.FEATURES[feature];
+
+ if (Ember.ENV.ENABLE_ALL_FEATURES) {
+ return true;
+ } else if (featureValue === true || featureValue === false || featureValue === undefined) {
+ return featureValue;
+ } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) {
+ return true;
+ } else {
+ return false;
+ }
};
// ..........................................................
// BOOTSTRAP
//
@@ -3954,43 +3967,14 @@
(function() {
/**
- @module ember-metal
+ @module ember-metal
*/
-var forEach = Ember.EnumerableUtils.forEach,
- IS_BRACE_EXPANSION = /^\{([^.]*)\}$/;
-/**
- Expands `pattern`, invoking `callback` for each expansion.
-
- The only pattern supported is brace-expansion, anything else will be passed
- once to `callback` directly. Furthermore, brace-expansion is only applied to
- the entire pattern, not to substrings.
-
- Example
- ```js
- function echo(arg){ console.log(arg); }
-
- Ember.expandProperties('foo.bar', echo); //=> 'foo.bar'
- Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar'
- Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.{bar,baz}'
- ```
-
- @method
- @private
- @param {string} pattern The property pattern to expand.
- @param {function} callback The callback to invoke. It is invoked once per
- expansion, and is passed the expansion.
-*/
-Ember.expandProperties = function (pattern, callback) {
-
- callback(pattern);
-};
-
})();
(function() {
@@ -4045,20 +4029,20 @@
*/
var metaFor = Ember.meta, // utils.js
GUID_KEY = Ember.GUID_KEY, // utils.js
META_KEY = Ember.META_KEY, // utils.js
- expandProperties = Ember.expandProperties,
removeChainWatcher = Ember.removeChainWatcher,
watchKey = Ember.watchKey, // watch_key.js
unwatchKey = Ember.unwatchKey,
watchPath = Ember.watchPath, // watch_path.js
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);
}
@@ -4078,17 +4062,17 @@
*/
Ember.watch = function(obj, _keyPath) {
// can't watch length on Array - it is special...
if (_keyPath === 'length' && typeOf(obj) === 'array') { return; }
- expandProperties(_keyPath, function (keyPath) {
- if (isKeyName(keyPath)) {
- watchKey(obj, keyPath);
+
+ if (isKeyName(_keyPath)) {
+ watchKey(obj, _keyPath);
} else {
- watchPath(obj, keyPath);
+ watchPath(obj, _keyPath);
}
- });
+
};
Ember.isWatching = function isWatching(obj, key) {
var meta = obj[META_KEY];
return (meta && meta.watching[key]) > 0;
@@ -4098,17 +4082,17 @@
Ember.unwatch = function(obj, _keyPath) {
// can't watch length on Array - it is special...
if (_keyPath === 'length' && typeOf(obj) === 'array') { return; }
- expandProperties(_keyPath, function (keyPath) {
- if (isKeyName(keyPath)) {
- unwatchKey(obj, keyPath);
+
+ if (isKeyName(_keyPath)) {
+ unwatchKey(obj, _keyPath);
} else {
- unwatchPath(obj, keyPath);
+ unwatchPath(obj, _keyPath);
}
- });
+
};
/**
@private
@@ -4190,17 +4174,17 @@
var get = Ember.get,
set = Ember.set,
metaFor = Ember.meta,
- expandProperties = Ember.expandProperties,
a_slice = [].slice,
o_create = Ember.create,
META_KEY = Ember.META_KEY,
watch = Ember.watch,
unwatch = Ember.unwatch;
+
// ..........................................................
// DEPENDENT KEYS
//
// data structure:
@@ -4450,17 +4434,18 @@
@param {String} path* zero or more property paths
@return {Ember.ComputedProperty} this
@chainable
*/
ComputedPropertyPrototype.property = function() {
- function addArg(arg) {
- args.push(arg);
- }
+ var addArg;
+
var args = [];
for (var i = 0, l = arguments.length; i < l; i++) {
- expandProperties(arguments[i], addArg);
+
+ args.push(arguments[i]);
+
}
this._dependentKeys = args;
return this;
};
@@ -5310,13 +5295,13 @@
/**
@module ember-metal
*/
var AFTER_OBSERVERS = ':change',
- BEFORE_OBSERVERS = ':before',
- expandProperties = Ember.expandProperties;
+ BEFORE_OBSERVERS = ':before';
+
function changeEvent(keyName) {
return keyName+AFTER_OBSERVERS;
}
function beforeEvent(keyName) {
@@ -5329,14 +5314,14 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.addObserver = function(obj, _path, target, method) {
- expandProperties(_path, function (path) {
- 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) {
@@ -5349,14 +5334,14 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.removeObserver = function(obj, _path, target, method) {
- expandProperties(_path, function (path) {
- 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
@@ -5364,14 +5349,14 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.addBeforeObserver = function(obj, _path, target, method) {
- expandProperties(_path, function (path) {
- 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.
//
@@ -5407,14 +5392,14 @@
@param {String} path
@param {Object|Function} targetOrMethod
@param {Function|String} [method]
*/
Ember.removeBeforeObserver = function(obj, _path, target, method) {
- expandProperties(_path, function (path) {
- Ember.unwatch(obj, path);
- Ember.removeListener(obj, beforeEvent(path), target, method);
- });
+
+ Ember.unwatch(obj, _path);
+ Ember.removeListener(obj, beforeEvent(_path), target, method);
+
return this;
};
})();
@@ -7156,13 +7141,11 @@
return baseValue.concat(value);
} else {
return Ember.makeArray(baseValue).concat(value);
}
} else {
- // Make sure this mixin has its own array so it is not
- // accidentally mutated by another child's interactions
- return Ember.makeArray(value).slice();
+ return Ember.makeArray(value);
}
}
function applyMergedProperties(obj, key, value, values) {
var baseValue = values[key] || obj[key];
@@ -11208,10 +11191,15 @@
// a map of dependent array guids -> Ember.TrackedArray instances. We use
// this to lazily recompute indexes for item property observers.
this.trackedArraysByGuid = {};
+ // We suspend observers to ignore replacements from `reset` when totally
+ // recomputing. Unfortunately we cannot properly suspend the observers
+ // because we only have the key; instead we make the observers no-ops
+ this.suspended = false;
+
// This is used to coalesce item changes from property observers.
this.changedItems = {};
}
function ItemPropertyObserverContext (dependentArray, index, trackedArray) {
@@ -11261,10 +11249,17 @@
willChange: 'dependentArrayWillChange',
didChange: 'dependentArrayDidChange'
});
},
+ suspendArrayObservers: function (callback, binding) {
+ var oldSuspended = this.suspended;
+ this.suspended = true;
+ callback.call(binding);
+ this.suspended = oldSuspended;
+ },
+
setupPropertyObservers: function (dependentKey, itemPropertyKeys) {
var dependentArray = get(this.instanceMeta.context, dependentKey),
length = get(dependentArray, 'length'),
observerContexts = new Array(length);
@@ -11366,31 +11361,34 @@
});
});
},
dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) {
+ if (this.suspended) { return; }
+
var removedItem = this.callbacks.removedItem,
changeMeta,
guid = guidFor(dependentArray),
dependentKey = this.dependentKeysByGuid[guid],
itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || [],
length = get(dependentArray, 'length'),
- normalizedIndex = normalizeIndex(length, index, 1),
+ normalizedIndex = normalizeIndex(index, length, 0),
+ normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount),
item,
itemIndex,
sliceIndex,
observerContexts;
- observerContexts = this.trackRemove(dependentKey, normalizedIndex, removedCount);
+ observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount);
function removeObservers(propertyKey) {
observerContexts[sliceIndex].destroyed = true;
removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver);
removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer);
}
- for (sliceIndex = removedCount - 1; sliceIndex >= 0; --sliceIndex) {
+ for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) {
itemIndex = normalizedIndex + sliceIndex;
if (itemIndex >= length) { break; }
item = dependentArray.objectAt(itemIndex);
@@ -11401,17 +11399,19 @@
this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta));
}
},
dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) {
+ if (this.suspended) { return; }
+
var addedItem = this.callbacks.addedItem,
guid = guidFor(dependentArray),
dependentKey = this.dependentKeysByGuid[guid],
observerContexts = new Array(addedCount),
itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey],
length = get(dependentArray, 'length'),
- normalizedIndex = normalizeIndex(length, index, addedCount),
+ normalizedIndex = normalizeIndex(index, length, addedCount),
changeMeta,
observerContext;
forEach(dependentArray.slice(normalizedIndex, normalizedIndex + addedCount), function (item, sliceIndex) {
if (itemPropertyKeys) {
@@ -11468,20 +11468,24 @@
}
this.changedItems = {};
}
};
-function normalizeIndex(length, index, newItemsOffset) {
+function normalizeIndex(index, length, newItemsOffset) {
if (index < 0) {
return Math.max(0, length + index);
} else if (index < length) {
return index;
} else /* index > length */ {
return Math.min(length - newItemsOffset, index);
}
}
+function normalizeRemoveCount(index, length, removedCount) {
+ return Math.min(removedCount, length - index);
+}
+
function createChangeMeta(dependentArray, item, index, propertyName, property, previousValues) {
var meta = {
arrayChanged: dependentArray,
index: index,
item: item,
@@ -11596,34 +11600,36 @@
meta = cp._instanceMeta(this, propertyName),
callbacks = cp._callbacks();
reset.call(this, cp, propertyName);
- forEach(cp._dependentKeys, function (dependentKey) {
- var dependentArray = get(this, dependentKey),
- previousDependentArray = meta.dependentArrays[dependentKey];
+ meta.dependentArraysObserver.suspendArrayObservers(function () {
+ forEach(cp._dependentKeys, function (dependentKey) {
+ 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
- // changed, so we set them up again. We can't easily tell if they've
- // changed: the array may be the same object, but with different
- // contents.
- if (cp._previousItemPropertyKeys[dependentKey]) {
- delete cp._previousItemPropertyKeys[dependentKey];
- meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]);
- }
- } else {
- meta.dependentArrays[dependentKey] = dependentArray;
+ if (dependentArray === previousDependentArray) {
+ // The array may be the same, but our item property keys may have
+ // changed, so we set them up again. We can't easily tell if they've
+ // changed: the array may be the same object, but with different
+ // contents.
+ if (cp._previousItemPropertyKeys[dependentKey]) {
+ delete cp._previousItemPropertyKeys[dependentKey];
+ meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]);
+ }
+ } else {
+ meta.dependentArrays[dependentKey] = dependentArray;
- if (previousDependentArray) {
- meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey);
- }
+ if (previousDependentArray) {
+ meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey);
+ }
- if (dependentArray) {
- meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey);
+ if (dependentArray) {
+ meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey);
+ }
}
- }
+ }, this);
}, this);
forEach(cp._dependentKeys, function(dependentKey) {
var dependentArray = get(this, dependentKey);
if (dependentArray) {
@@ -15678,11 +15684,14 @@
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 (Ember.typeOf(properties) !== 'object') { continue; }
+ if (properties === null || typeof properties !== 'object') {
+ Ember.assert("Ember.Object.create only accepts objects.");
+ 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; }
@@ -15870,11 +15879,11 @@
are also concatenated, in addition to `classNames`.
This feature is available for you to use throughout the Ember object model,
although typical app developers are likely to use it infrequently. Since
it changes expectations about behavior of properties, you should properly
- document its usage in each individual concatenated property (to not
+ document its usage in each individual concatenated property (to not
mislead your users to think they can override the property in a subclass).
@property concatenatedProperties
@type Array
@default null
@@ -16171,14 +16180,14 @@
if (arguments.length>0) { this._initProperties(arguments); }
return new C();
},
/**
-
+
Augments a constructor's prototype with additional
properties and functions:
-
+
```javascript
MyObject = Ember.Object.extend({
name: 'an object'
});
@@ -16194,11 +16203,11 @@
o2 = MyObject.create();
o2.say("hello"); // logs "hello"
o.say("goodbye"); // logs "goodbye"
```
-
+
To add functions and properties to the constructor itself,
see `reopenClass`
@method reopen
*/
@@ -16208,26 +16217,26 @@
return this;
},
/**
Augments a constructor's own properties and functions:
-
+
```javascript
MyObject = Ember.Object.extend({
name: 'an object'
});
MyObject.reopenClass({
canBuild: false
});
-
+
MyObject.canBuild; // false
o = MyObject.create();
```
- In other words, this creates static properties and functions for the class. These are only available on the class
+ In other words, this creates static properties and functions for the class. These are only available on the class
and not on any instance of that class.
```javascript
App.Person = Ember.Object.extend({
name : "",
@@ -16253,18 +16262,18 @@
tom.sayHello(); // "Hello. My name is Tom Dale"
yehuda.sayHello(); // "Hello. My name is Yehuda Katz"
alert(App.Person.species); // "Homo sapiens"
```
- Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda`
+ Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda`
variables. They are only valid on `App.Person`.
-
+
To add functions and properties to instances of
a constructor by extending the constructor's prototype
see `reopen`
-
+
@method reopenClass
- */
+ */
reopenClass: function() {
reopen.apply(this.ClassMixin, arguments);
applyMixin(this, arguments, false);
return this;
},