@@ -33431,17 +33268,13 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
And application code
```javascript
- AController = Ember.Controller.extend({
- anActionName: function() {}
+ App.ApplicationController = Ember.Controller.extend({
+ actions: {
+ anActionName: function() {
+
+ }
+ }
});
-
- AView = Ember.View.extend({
- controller: AController.create(),
- templateName: 'a-template'
- });
-
- aView = AView.create();
- aView.appendTo('body');
```
Will result in the following rendered HTML
@@ -33454,8 +33287,8 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
```
- Clicking "click me" will trigger the `anActionName` method of the
- `AController`. In this case, no additional parameters will be passed.
+ Clicking "click me" will trigger the `anActionName` action of the
+ `App.ApplicationController`. In this case, no additional parameters will be passed.
If you provide additional parameters to the helper:
@@ -33488,11 +33321,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
supply an `on` option to the helper to specify a different DOM event name:
```handlebars
-
+
+ click me
+
```
See `Ember.View` 'Responding to Browser Events' for a list of
@@ -33510,11 +33341,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
keys. You can supply an `allowedKeys` option to specify which keys should not be ignored.
```handlebars
-
+
+ click me
+
```
This way the `{{action}}` will fire when clicking with the alt key pressed down.
@@ -33522,11 +33351,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys.
```handlebars
-
+
+ click me with any key pressed
+
```
### Specifying a Target
@@ -33542,43 +33369,21 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
to an object, accessible in the current context:
```handlebars
-
+ {{! the application template }}
+
+ click me
+
```
- Clicking "click me" in the rendered HTML of the above template will trigger
- the `anActionName` method of the object at `MyApplication.someObject`.
-
- If an action's target does not implement a method that matches the supplied
- action name an error will be thrown.
-
- ```handlebars
-
- ```
-
- With the following application code
-
```javascript
- AView = Ember.View.extend({
- templateName; 'a-template',
- // note: no method 'aMethodNameThatIsMissing'
- anActionName: function(event) {}
+ App.ApplicationView = Ember.View.extend({
+ actions: {
+ anActionName: function(){}
+ }
});
- aView = AView.create();
- aView.appendTo('body');
```
- Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when
- "click me" is clicked.
-
### Additional Parameters
You may specify additional parameters to the `{{action}}` helper. These
@@ -33586,17 +33391,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
implementing the action.
```handlebars
-
+ {{#each person in people}}
+
+ click me
+
+ {{/each}}
```
- Clicking "click me" will trigger the `edit` method on the current view's
- controller with the current person as a parameter.
+ Clicking "click me" will trigger the `edit` method on the current controller
+ with the value of `person` as a parameter.
@method action
@for Ember.Handlebars.helpers
@@ -33781,8 +33584,23 @@ Ember.ControllerMixin.reopen({
aController.transitionToRoute('blogPost', aPost);
```
+ Multiple models will be applied last to first recursively up the
+ resource tree.
+
+ ```javascript
+
+ this.resource('blogPost', {path:':blogPostId'}, function(){
+ this.resource('blogComment', {path: ':blogCommentId'});
+ });
+
+ aController.transitionToRoute('blogComment', aPost, aComment);
+ ```
+
+ See also 'replaceRoute'.
+
@param {String} name the name of the route
- @param {...Object} models the
+ @param {...Object} models the model(s) to be used while transitioning
+ to the route.
@for Ember.ControllerMixin
@method transitionToRoute
*/
@@ -33804,8 +33622,9 @@ Ember.ControllerMixin.reopen({
},
/**
- Alternative to `transitionToRoute`. Transition the application into another route. The route may
- be either a single route or route path:
+ Transition into another route while replacing the current URL, if possible.
+ This will replace the current history entry instead of adding a new one.
+ Beside that, it is identical to `transitionToRoute` in all other respects.
```javascript
aController.replaceRoute('blogPosts');
@@ -33820,8 +33639,21 @@ Ember.ControllerMixin.reopen({
aController.replaceRoute('blogPost', aPost);
```
+ Multiple models will be applied last to first recursively up the
+ resource tree.
+
+ ```javascript
+
+ this.resource('blogPost', {path:':blogPostId'}, function(){
+ this.resource('blogComment', {path: ':blogCommentId'});
+ });
+
+ aController.replaceRoute('blogComment', aPost, aComment);
+ ```
+
@param {String} name the name of the route
- @param {...Object} models the
+ @param {...Object} models the model(s) to be used while transitioning
+ to the route.
@for Ember.ControllerMixin
@method replaceRoute
*/
@@ -34624,7 +34456,7 @@ DAG.prototype.addEdge = function(fromName, toName) {
}
function checkCycle(vertex, path) {
if (vertex.name === toName) {
- throw new Error("cycle detected: " + toName + " <- " + path.join(" <- "));
+ throw new Ember.Error("cycle detected: " + toName + " <- " + path.join(" <- "));
}
}
visit(from, checkCycle);
@@ -35065,16 +34897,15 @@ DeprecatedContainer.prototype = {
example, the `keypress` event causes the `keyPress` method on the view to be
called, the `dblclick` event causes `doubleClick` to be called, and so on.
- If there is a browser event that Ember does not listen for by default, you
- can specify custom events and their corresponding view method names by
- setting the application's `customEvents` property:
+ If there is a bubbling browser event that Ember does not listen for by
+ default, you can specify custom events and their corresponding view method
+ names by setting the application's `customEvents` property:
```javascript
App = Ember.Application.create({
customEvents: {
- // add support for the loadedmetadata media
- // player event
- 'loadedmetadata': "loadedMetadata"
+ // add support for the paste event
+ 'paste: "paste"
}
});
```
@@ -35187,7 +35018,7 @@ var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin
`keyup`, and delegates them to your application's `Ember.View`
instances.
- If you would like additional events to be delegated to your
+ If you would like additional bubbling events to be delegated to your
views, set your `Ember.Application`'s `customEvents` property
to a hash containing the DOM event name as the key and the
corresponding view method name as the value. For example:
@@ -35195,9 +35026,8 @@ var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin
```javascript
App = Ember.Application.create({
customEvents: {
- // add support for the loadedmetadata media
- // player event
- 'loadedmetadata': "loadedMetadata"
+ // add support for the paste event
+ 'paste: "paste"
}
});
```
@@ -35438,7 +35268,9 @@ var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin
if (this.isDestroyed) { return; }
// At this point, the App.Router must already be assigned
- this.register('router:main', this.Router);
+ if (this.Router) {
+ this.register('router:main', this.Router);
+ }
this.runInitializers();
Ember.runLoadHooks('application', this);
@@ -35548,10 +35380,10 @@ var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin
container = this.__container__,
graph = new Ember.DAG(),
namespace = this,
- i, initializer;
+ name, initializer;
- for (i=0; i 0) {
+ Ember.assert(' `' + Ember.inspect(this) + ' specifies `needs`, but does not have a container. Please ensure this controller was instantiated with a container.', this.container);
+
verifyNeedsDependencies(this, this.container, needs);
// if needs then initialize controllers proxy
@@ -35863,6 +35704,11 @@ Ember.ControllerMixin.reopen({
this._super.apply(this, arguments);
},
+ /**
+ @method controllerFor
+ @see {Ember.Route#controllerFor}
+ @deprecated Use `needs` instead
+ */
controllerFor: function(controllerName) {
Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead");
return Ember.controllerFor(get(this, 'container'), controllerName);
@@ -36654,7 +36500,7 @@ function testCheckboxClick(handler) {
.css({ position: 'absolute', left: '-1000px', top: '-1000px' })
.appendTo('body')
.on('click', handler)
- .trigger('click')
+ .click()
.remove();
}
@@ -36793,6 +36639,7 @@ Test.onInjectHelpers(function() {
});
Ember.$(document).ajaxStop(function() {
+ Ember.assert("An ajaxStop event which would cause the number of pending AJAX requests to be negative has been triggered. This is most likely caused by AJAX events that were started before calling `injectTestHelpers()`.", Test.pendingAjaxRequests !== 0);
Test.pendingAjaxRequests--;
});
});
@@ -36811,7 +36658,16 @@ function click(app, selector, context) {
if ($el.is(':input')) {
var type = $el.prop('type');
if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') {
- Ember.run($el, 'focus');
+ Ember.run($el, function(){
+ // Firefox does not trigger the `focusin` event if the window
+ // does not have focus. If the document doesn't have focus just
+ // use trigger('focusin') instead.
+ if (!document.hasFocus || document.hasFocus()) {
+ this.focus();
+ } else {
+ this.trigger('focusin');
+ }
+ });
}
}
@@ -36850,7 +36706,7 @@ function fillIn(app, selector, context, text) {
function findWithAssert(app, selector, context) {
var $el = find(app, selector, context);
if ($el.length === 0) {
- throw new Error("Element " + selector + " not found.");
+ throw new Ember.Error("Element " + selector + " not found.");
}
return $el;
}
@@ -37106,7 +36962,7 @@ Ember
function throwWithMessage(msg) {
return function() {
- throw new Error(msg);
+ throw new Ember.Error(msg);
};
}
diff --git a/vendor/assets/javascripts/production/ember.js b/vendor/assets/javascripts/production/ember.js
index 209ece8f016..de9392edf35 100644
--- a/vendor/assets/javascripts/production/ember.js
+++ b/vendor/assets/javascripts/production/ember.js
@@ -1,17 +1,3 @@
-// ==========================================================================
-// Project: Ember - JavaScript Application Framework
-// Copyright: ©2011-2013 Tilde Inc. and contributors
-// Portions ©2006-2011 Strobe Inc.
-// Portions ©2008-2011 Apple Inc. All rights reserved.
-// License: Licensed under MIT license
-// See https://raw.github.com/emberjs/ember.js/master/LICENSE
-// ==========================================================================
-
-
-// Version: v1.0.0-rc.6-733-gd034d11
-// Last commit: d034d11 (2013-09-16 00:44:21 -0700)
-
-
(function() {
var define, requireModule;
@@ -75,7 +61,7 @@ var define, requireModule;
@class Ember
@static
- @version 1.0.0
+ @version 1.1.2
*/
if ('undefined' === typeof Ember) {
@@ -102,10 +88,10 @@ Ember.toString = function() { return "Ember"; };
/**
@property VERSION
@type String
- @default '1.0.0'
+ @default '1.1.2'
@final
*/
-Ember.VERSION = '1.0.0';
+Ember.VERSION = '1.1.2';
/**
Standard environmental variables. You can define these in a global `ENV`
@@ -1865,6 +1851,7 @@ Ember.getWithDefault = function(root, key, defaultValue) {
Ember.get = get;
+Ember.getPath = Ember.deprecateFunc('getPath is deprecated since get now supports paths', Ember.get);
})();
@@ -2701,6 +2688,7 @@ function setPath(root, path, value, tolerant) {
}
Ember.set = set;
+Ember.setPath = Ember.deprecateFunc('setPath is deprecated since set now supports paths', Ember.set);
/**
Error-tolerant form of `Ember.set`. Will not blow up if any part of the
@@ -2718,6 +2706,7 @@ Ember.set = set;
Ember.trySet = function(root, path, value) {
return set(root, path, value, true);
};
+Ember.trySetPath = Ember.deprecateFunc('trySetPath has been renamed to trySet', Ember.trySet);
})();
@@ -4467,14 +4456,14 @@ function registerComputedWithProperties(name, macro) {
property is null, an empty string, empty array, or empty function.
Note: When using `Ember.computed.empty` to watch an array make sure to
- use the `array.length` syntax so the computed can subscribe to transitions
+ use the `array.[]` syntax so the computed can subscribe to transitions
from empty to non-empty states.
Example
```javascript
var ToDoList = Ember.Object.extend({
- done: Ember.computed.empty('todos.length')
+ done: Ember.computed.empty('todos.[]') // detect array changes
});
var todoList = ToDoList.create({todos: ['Unit Test', 'Documentation', 'Release']});
todoList.get('done'); // false
@@ -4594,7 +4583,7 @@ registerComputed('not', function(dependentKey) {
@method computed.bool
@for Ember
@param {String} dependentKey
- @return {Ember.ComputedProperty} computed property which convert
+ @return {Ember.ComputedProperty} computed property which converts
to boolean the original value for property
*/
registerComputed('bool', function(dependentKey) {
@@ -4812,7 +4801,7 @@ registerComputedWithProperties('and', function(properties) {
});
/**
- A computed property that which performs a logical `or` on the
+ A computed property which performs a logical `or` on the
original values for the provided dependent properties.
Example
@@ -4979,7 +4968,7 @@ Ember.computed.alias = function(dependentKey) {
@method computed.oneWay
@for Ember
@param {String} dependentKey
- @return {Ember.ComputedProperty} computed property which creates an
+ @return {Ember.ComputedProperty} computed property which creates a
one way computed property to the original value for property.
*/
Ember.computed.oneWay = function(dependentKey) {
@@ -4991,7 +4980,7 @@ Ember.computed.oneWay = function(dependentKey) {
/**
A computed property that acts like a standard getter and setter,
- but retruns the value at the provided `defaultPath` if the
+ but returns the value at the provided `defaultPath` if the
property itself has not been set to a value
Example
@@ -5359,7 +5348,12 @@ define("backburner",
debouncees = [],
timers = [],
autorun, laterTimer, laterTimerExpiresAt,
- global = this;
+ global = this,
+ NUMBER = /\d+/;
+
+ function isCoercableNumber(number) {
+ return typeof number === 'number' || NUMBER.test(number);
+ }
function Backburner(queueNames, options) {
this.queueNames = queueNames;
@@ -5474,32 +5468,60 @@ define("backburner",
},
setTimeout: function() {
- var self = this,
- wait = pop.call(arguments),
- target = arguments[0],
- method = arguments[1],
- executeAt = (+new Date()) + wait;
+ var args = slice.call(arguments);
+ var length = args.length;
+ var method, wait, target;
+ var self = this;
+ var methodOrTarget, methodOrWait, methodOrArgs;
- if (!method) {
- method = target;
- target = null;
+ if (length === 0) {
+ return;
+ } else if (length === 1) {
+ method = args.shift();
+ wait = 0;
+ } else if (length === 2) {
+ methodOrTarget = args[0];
+ methodOrWait = args[1];
+
+ if (typeof methodOrWait === 'function' || typeof methodOrTarget[methodOrWait] === 'function') {
+ target = args.shift();
+ method = args.shift();
+ wait = 0;
+ } else if (isCoercableNumber(methodOrWait)) {
+ method = args.shift();
+ wait = args.shift();
+ } else {
+ method = args.shift();
+ wait = 0;
+ }
+ } else {
+ var last = args[args.length - 1];
+
+ if (isCoercableNumber(last)) {
+ wait = args.pop();
+ }
+
+ methodOrTarget = args[0];
+ methodOrArgs = args[1];
+
+ if (typeof methodOrArgs === 'function' || (typeof methodOrArgs === 'string' &&
+ methodOrTarget !== null &&
+ methodOrArgs in methodOrTarget)) {
+ target = args.shift();
+ method = args.shift();
+ } else {
+ method = args.shift();
+ }
}
+ var executeAt = (+new Date()) + parseInt(wait, 10);
+
if (typeof method === 'string') {
method = target[method];
}
- var fn, args;
- if (arguments.length > 2) {
- args = slice.call(arguments, 2);
-
- fn = function() {
- method.apply(target, args);
- };
- } else {
- fn = function() {
- method.call(target);
- };
+ function fn() {
+ method.apply(target, args);
}
// find position to insert - TODO: binary search
@@ -5700,6 +5722,7 @@ define("backburner",
__exports__.Backburner = Backburner;
});
+
})();
@@ -7316,11 +7339,10 @@ Alias.prototype = new Ember.Descriptor();
@deprecated Use `Ember.aliasMethod` or `Ember.computed.alias` instead
*/
Ember.alias = function(methodName) {
+
return new Alias(methodName);
};
-Ember.alias = Ember.deprecateFunc("Ember.alias is deprecated. Please use Ember.aliasMethod or Ember.computed.alias instead.", Ember.alias);
-
/**
Makes a method available via an additional name.
@@ -7464,6 +7486,8 @@ Ember.beforeObserver = function(func) {
(function() {
// Provides a way to register library versions with ember.
+var forEach = Ember.EnumerableUtils.forEach,
+ indexOf = Ember.EnumerableUtils.indexOf;
Ember.libraries = function() {
var libraries = [];
@@ -7491,14 +7515,15 @@ Ember.libraries = function() {
libraries.deRegister = function(name) {
var lib = getLibrary(name);
- if (lib) libraries.splice(libraries.indexOf(lib), 1);
+ if (lib) libraries.splice(indexOf(libraries, lib), 1);
};
libraries.each = function (callback) {
- libraries.forEach(function(lib) {
+ forEach(libraries, function(lib) {
callback(lib.name, lib.version);
});
};
+
return libraries;
}();
@@ -8418,25 +8443,25 @@ define("container",
```
@method register
- @param {String} type
- @param {String} name
+ @param {String} fullName
@param {Function} factory
@param {Object} options
*/
- register: function(type, name, factory, options) {
- var fullName;
+ register: function(fullName, factory, options) {
+ if (fullName.indexOf(':') === -1) {
+ throw new TypeError("malformed fullName, expected: `type:name` got: " + fullName + "");
+ }
- if (type.indexOf(':') !== -1) {
- options = factory;
- factory = name;
- fullName = type;
- } else {
-
- fullName = type + ":" + name;
+ if (factory === undefined) {
+ throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`');
}
var normalizedName = this.normalize(fullName);
+ if (this.cache.has(normalizedName)) {
+ throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.');
+ }
+
this.registry.set(normalizedName, factory);
this._options.set(normalizedName, options || {});
},
@@ -9327,16 +9352,39 @@ Ember.ORDER_DEFINITION = Ember.ENV.ORDER_DEFINITION || [
Ember.keys = Object.keys;
if (!Ember.keys || Ember.create.isSimulated) {
- Ember.keys = function(obj) {
- var ret = [];
- for(var key in obj) {
- // Prevents browsers that don't respect non-enumerability from
- // copying internal Ember properties
- if (key.substring(0,2) === '__') continue;
- if (key === '_super') continue;
+ var prototypeProperties = [
+ 'constructor',
+ 'hasOwnProperty',
+ 'isPrototypeOf',
+ 'propertyIsEnumerable',
+ 'valueOf',
+ 'toLocaleString',
+ 'toString'
+ ],
+ pushPropertyName = function(obj, array, key) {
+ // Prevents browsers that don't respect non-enumerability from
+ // copying internal Ember properties
+ if (key.substring(0,2) === '__') return;
+ if (key === '_super') return;
+ if (indexOf(array, key) >= 0) return;
+ if (!obj.hasOwnProperty(key)) return;
- if (obj.hasOwnProperty(key)) { ret.push(key); }
+ array.push(key);
+ };
+
+ Ember.keys = function(obj) {
+ var ret = [], key;
+ for (key in obj) {
+ pushPropertyName(obj, ret, key);
}
+
+ // IE8 doesn't enumerate property that named the same as prototype properties.
+ for (var i = 0, l = prototypeProperties.length; i < l; i++) {
+ key = prototypeProperties[i];
+
+ pushPropertyName(obj, ret, key);
+ }
+
return ret;
};
}
@@ -10772,10 +10820,12 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
(function() {
-var e_get = Ember.get,
+var get = Ember.get,
set = Ember.set,
guidFor = Ember.guidFor,
metaFor = Ember.meta,
+ propertyWillChange = Ember.propertyWillChange,
+ propertyDidChange = Ember.propertyDidChange,
addBeforeObserver = Ember.addBeforeObserver,
removeBeforeObserver = Ember.removeBeforeObserver,
addObserver = Ember.addObserver,
@@ -10789,16 +10839,6 @@ var e_get = Ember.get,
eachPropertyPattern = /^(.*)\.@each\.(.*)/,
doubleEachPropertyPattern = /(.*\.@each){2,}/;
-function get(obj, key) {
- if (Ember.FEATURES.isEnabled('reduceComputedSelf')) {
- if (key === '@self') {
- return obj;
- }
- }
-
- return e_get(obj, key);
-}
-
/*
Tracks changes to dependent arrays, as well as to properties of items in
dependent arrays.
@@ -10846,7 +10886,7 @@ function ItemPropertyObserverContext (dependentArray, index, trackedArray) {
DependentArraysObserver.prototype = {
setValue: function (newValue) {
- this.instanceMeta.setValue(newValue);
+ this.instanceMeta.setValue(newValue, true);
},
getValue: function () {
return this.instanceMeta.getValue();
@@ -10947,14 +10987,14 @@ DependentArraysObserver.prototype = {
this.trackedArraysByGuid[dependentKey] = new Ember.TrackedArray(observerContexts);
},
- addTransformation: function (dependentKey, index, newItems) {
+ trackAdd: function (dependentKey, index, newItems) {
var trackedArray = this.trackedArraysByGuid[dependentKey];
if (trackedArray) {
trackedArray.addItems(index, newItems);
}
},
- removeTransformation: function (dependentKey, index, removedCount) {
+ trackRemove: function (dependentKey, index, removedCount) {
var trackedArray = this.trackedArraysByGuid[dependentKey];
if (trackedArray) {
@@ -10995,7 +11035,7 @@ DependentArraysObserver.prototype = {
sliceIndex,
observerContexts;
- observerContexts = this.removeTransformation(dependentKey, index, removedCount);
+ observerContexts = this.trackRemove(dependentKey, index, removedCount);
function removeObservers(propertyKey) {
observerContexts[sliceIndex].destroyed = true;
@@ -11040,7 +11080,7 @@ DependentArraysObserver.prototype = {
this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta));
}, this);
- this.addTransformation(dependentKey, index, observerContexts);
+ this.trackAdd(dependentKey, index, observerContexts);
},
itemPropertyWillChange: function (obj, keyName, array, observerContext) {
@@ -11059,7 +11099,7 @@ DependentArraysObserver.prototype = {
},
itemPropertyDidChange: function(obj, keyName, array, observerContext) {
- Ember.run.once(this, 'flushChanges');
+ this.flushChanges();
},
flushChanges: function() {
@@ -11141,11 +11181,21 @@ ReduceComputedPropertyInstanceMeta.prototype = {
}
},
- setValue: function(newValue) {
+ setValue: function(newValue, triggerObservers) {
// This lets sugars force a recomputation, handy for very simple
// implementations of eg max.
if (newValue !== undefined) {
+ var fireObservers = triggerObservers && (newValue !== this.cache[this.propertyName]);
+
+ if (fireObservers) {
+ propertyWillChange(this.context, this.propertyName);
+ }
+
this.cache[this.propertyName] = newValue;
+
+ if (fireObservers) {
+ propertyDidChange(this.context, this.propertyName);
+ }
} else {
delete this.cache[this.propertyName];
}
@@ -11271,13 +11321,11 @@ ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName
};
ReduceComputedProperty.prototype.initialValue = function () {
- switch (typeof this.options.initialValue) {
- case 'undefined':
- throw new Error("reduce computed properties require an initial value: did you forget to pass one to Ember.reduceComputed?");
- case 'function':
- return this.options.initialValue();
- default:
- return this.options.initialValue;
+ if (typeof this.options.initialValue === 'function') {
+ return this.options.initialValue();
+ }
+ else {
+ return this.options.initialValue;
}
};
@@ -11300,25 +11348,25 @@ ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArra
ReduceComputedProperty.prototype.property = function () {
var cp = this,
args = a_slice.call(arguments),
- propertyArgs = [],
+ propertyArgs = new Ember.Set(),
match,
dependentArrayKey,
itemPropertyKey;
forEach(a_slice.call(arguments), function (dependentKey) {
if (doubleEachPropertyPattern.test(dependentKey)) {
- throw new Error("Nested @each properties not supported: " + 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);
- propertyArgs.push(dependentArrayKey);
+ propertyArgs.add(dependentArrayKey);
} else {
- propertyArgs.push(dependentKey);
+ propertyArgs.add(dependentKey);
}
});
- return ComputedProperty.prototype.property.apply(this, propertyArgs);
+ return ComputedProperty.prototype.property.apply(this, propertyArgs.toArray());
};
/**
@@ -11330,7 +11378,7 @@ ReduceComputedProperty.prototype.property = function () {
If there are more than one arguments the first arguments are
considered to be dependent property keys. The last argument is
required to be an options object. The options object can have the
- following four properties.
+ following four properties:
`initialValue` - A value or function that will be used as the initial
value for the computed. If this property is a function the result of calling
@@ -11411,6 +11459,12 @@ ReduceComputedProperty.prototype.property = function () {
to invalidate the computation. This is generally not a good idea for
arrayComputed but it's used in eg max and min.
+ Note that observers will be fired if either of these functions return a value
+ that differs from the accumulated value. When returning an object that
+ mutates in response to array changes, for example an array that maps
+ everything from some other array (see `Ember.computed.map`), it is usually
+ important that the *same* array be returned to avoid accidentally triggering observers.
+
Example
```javascript
@@ -11431,37 +11485,6 @@ ReduceComputedProperty.prototype.property = function () {
};
```
- Dependent keys may refer to `@self` to observe changes to the object itself,
- which must be array-like, rather than a property of the object. This is
- mostly useful for array proxies, to ensure objects are retrieved via
- `objectAtContent`. This is how you could sort items by properties defined on an item controller.
-
- Example
-
- ```javascript
- App.PeopleController = Ember.ArrayController.extend({
- itemController: 'person',
-
- sortedPeople: Ember.computed.sort('@self.@each.reversedName', function(personA, personB) {
- // `reversedName` isn't defined on Person, but we have access to it via
- // the item controller App.PersonController. If we'd used
- // `content.@each.reversedName` above, we would be getting the objects
- // directly and not have access to `reversedName`.
- //
- var reversedNameA = get(personA, 'reversedName'),
- reversedNameB = get(personB, 'reversedName');
-
- return Ember.compare(reversedNameA, reversedNameB);
- })
- });
-
- App.PersonController = Ember.ObjectController.extend({
- reversedName: function () {
- return reverse(get(this, 'name'));
- }.property('name')
- })
- ```
-
@method reduceComputed
@for Ember
@param {String} [dependentKeys*]
@@ -11477,11 +11500,11 @@ Ember.reduceComputed = function (options) {
}
if (typeof options !== "object") {
- throw new Error("Reduce Computed Property declared without an options hash");
+ throw new Ember.Error("Reduce Computed Property declared without an options hash");
}
- if (Ember.isNone(options.initialValue)) {
- throw new Error("Reduce Computed Property declared without an initial value");
+ if (!('initialValue' in options)) {
+ throw new Ember.Error("Reduce Computed Property declared without an initial value");
}
var cp = new ReduceComputedProperty(options);
@@ -11660,7 +11683,7 @@ Ember.arrayComputed = function (options) {
}
if (typeof options !== "object") {
- throw new Error("Array Computed Property declared without an options hash");
+ throw new Ember.Error("Array Computed Property declared without an options hash");
}
var cp = new ArrayComputedProperty(options);
@@ -12148,7 +12171,7 @@ Ember.computed.intersect = function () {
*/
Ember.computed.setDiff = function (setAProperty, setBProperty) {
if (arguments.length !== 2) {
- throw new Error("setDiff requires exactly two dependent arrays.");
+ throw new Ember.Error("setDiff requires exactly two dependent arrays.");
}
return Ember.arrayComputed.call(null, setAProperty, setBProperty, {
addedItem: function (array, item, changeMeta, instanceMeta) {
@@ -12263,7 +12286,7 @@ function binarySearch(array, item, low, high) {
]});
todoList.get('sortedTodos'); // [{name:'Documentation', priority:3}, {name:'Release', priority:1}, {name:'Unit Test', priority:2}]
- todoList.get('priroityTodos'); // [{name:'Release', priority:1}, {name:'Unit Test', priority:2}, {name:'Documentation', priority:3}]
+ todoList.get('priorityTodos'); // [{name:'Release', priority:1}, {name:'Unit Test', priority:2}, {name:'Documentation', priority:3}]
```
@method computed.sort
@@ -12403,7 +12426,7 @@ Ember.RSVP = requireModule('rsvp');
var STRING_DASHERIZE_REGEXP = (/[ _]/g);
var STRING_DASHERIZE_CACHE = {};
-var STRING_DECAMELIZE_REGEXP = (/([a-z])([A-Z])/g);
+var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g);
var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g);
var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g);
var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g);
@@ -13070,7 +13093,7 @@ Ember.Copyable = Ember.Mixin.create(/** @scope Ember.Copyable.prototype */ {
if (Ember.Freezable && Ember.Freezable.detect(this)) {
return get(this, 'isFrozen') ? this : this.copy().freeze();
} else {
- throw new Error(Ember.String.fmt("%@ does not support freezing", [this]));
+ throw new Ember.Error(Ember.String.fmt("%@ does not support freezing", [this]));
}
}
});
@@ -13379,7 +13402,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,/**
@return this
*/
insertAt: function(idx, object) {
- if (idx > get(this, 'length')) throw new Error(OUT_OF_RANGE_EXCEPTION) ;
+ if (idx > get(this, 'length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION) ;
this.replace(idx, 0, [object]) ;
return this ;
},
@@ -13407,7 +13430,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,/**
if ('number' === typeof start) {
if ((start < 0) || (start >= get(this, 'length'))) {
- throw new Error(OUT_OF_RANGE_EXCEPTION);
+ throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
}
// fast case
@@ -13994,6 +14017,29 @@ Ember.Observable = Ember.Mixin.create({
return Ember.hasListeners(this, key+':change');
},
+ /**
+ @deprecated
+ @method getPath
+ @param {String} path The property path to retrieve
+ @return {Object} The property value or undefined.
+ */
+ getPath: function(path) {
+
+ return this.get(path);
+ },
+
+ /**
+ @deprecated
+ @method setPath
+ @param {String} path The path to the property that will be set
+ @param {Object} value The value to set or `null`.
+ @return {Ember.Observable}
+ */
+ setPath: function(path, value) {
+
+ return this.set(path, value);
+ },
+
/**
Retrieves the value of a property, or a default value in the case that the
property returns `undefined`.
@@ -14201,6 +14247,13 @@ Ember.TargetActionSupport = Ember.Mixin.create({
target = opts.target || get(this, 'targetObject'),
actionContext = opts.actionContext;
+ function args(options, actionName) {
+ var ret = [];
+ if (actionName) { ret.push(actionName); }
+
+ return ret.concat(options);
+ }
+
if (typeof actionContext === 'undefined') {
actionContext = get(this, 'actionContextObject') || this;
}
@@ -14209,10 +14262,10 @@ Ember.TargetActionSupport = Ember.Mixin.create({
var ret;
if (target.send) {
- ret = target.send.apply(target, [action, actionContext]);
+ ret = target.send.apply(target, args(actionContext, action));
} else {
- ret = target[action].apply(target, [actionContext]);
+ ret = target[action].apply(target, args(actionContext));
}
if (ret !== false) ret = true;
@@ -14627,7 +14680,7 @@ Ember.PromiseProxyMixin = Ember.Mixin.create({
installPromise(this, promise);
return promise;
} else {
- throw new Error("PromiseProxy's promise must be set");
+ throw new Ember.Error("PromiseProxy's promise must be set");
}
}),
@@ -14670,9 +14723,9 @@ Ember.TrackedArray = function (items) {
var length = get(items, 'length');
if (length) {
- this._content = [new ArrayOperation(RETAIN, length, items)];
+ this._operations = [new ArrayOperation(RETAIN, length, items)];
} else {
- this._content = [];
+ this._operations = [];
}
};
@@ -14690,8 +14743,10 @@ Ember.TrackedArray.prototype = {
@param newItems
*/
addItems: function (index, newItems) {
- var count = get(newItems, 'length'),
- match = this._findArrayOperation(index),
+ var count = get(newItems, 'length');
+ if (count < 1) { return; }
+
+ var match = this._findArrayOperation(index),
arrayOperation = match.operation,
arrayOperationIndex = match.index,
arrayOperationRangeStart = match.rangeStart,
@@ -14706,7 +14761,7 @@ Ember.TrackedArray.prototype = {
if (arrayOperation) {
if (!match.split) {
// insert left of arrayOperation
- this._content.splice(arrayOperationIndex, 0, newArrayOperation);
+ this._operations.splice(arrayOperationIndex, 0, newArrayOperation);
composeIndex = arrayOperationIndex;
} else {
this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation);
@@ -14714,7 +14769,7 @@ Ember.TrackedArray.prototype = {
}
} else {
// insert at end
- this._content.push(newArrayOperation);
+ this._operations.push(newArrayOperation);
composeIndex = arrayOperationIndex;
}
@@ -14729,6 +14784,8 @@ Ember.TrackedArray.prototype = {
@param count
*/
removeItems: function (index, count) {
+ if (count < 1) { return; }
+
var match = this._findArrayOperation(index),
arrayOperation = match.operation,
arrayOperationIndex = match.index,
@@ -14739,7 +14796,7 @@ Ember.TrackedArray.prototype = {
newArrayOperation = new ArrayOperation(DELETE, count);
if (!match.split) {
// insert left of arrayOperation
- this._content.splice(arrayOperationIndex, 0, newArrayOperation);
+ this._operations.splice(arrayOperationIndex, 0, newArrayOperation);
composeIndex = arrayOperationIndex;
} else {
this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation);
@@ -14754,12 +14811,11 @@ Ember.TrackedArray.prototype = {
items in the array.
`callback` will be called for each operation and will be passed the following arguments:
-
-* {array} items The items for the given operation
-* {number} offset The computed offset of the items, ie the index in the
-array of the first item for this operation.
-* {string} operation The type of the operation. One of `Ember.TrackedArray.{RETAIN, DELETE, INSERT}`
-*
+ * {array} items The items for the given operation
+ * {number} offset The computed offset of the items, ie the index in the
+ array of the first item for this operation.
+ * {string} operation The type of the operation. One of
+ `Ember.TrackedArray.{RETAIN, DELETE, INSERT}`
@method apply
@param {function} callback
@@ -14768,16 +14824,16 @@ array of the first item for this operation.
var items = [],
offset = 0;
- forEach(this._content, function (arrayOperation) {
- callback(arrayOperation.items, offset, arrayOperation.operation);
+ forEach(this._operations, function (arrayOperation) {
+ callback(arrayOperation.items, offset, arrayOperation.type);
- if (arrayOperation.operation !== DELETE) {
+ if (arrayOperation.type !== DELETE) {
offset += arrayOperation.count;
items = items.concat(arrayOperation.items);
}
});
- this._content = [new ArrayOperation(RETAIN, items.length, items)];
+ this._operations = [new ArrayOperation(RETAIN, items.length, items)];
},
/**
@@ -14799,10 +14855,10 @@ array of the first item for this operation.
// OPTIMIZE: we could search these faster if we kept a balanced tree.
// find leftmost arrayOperation to the right of `index`
- for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._content.length; arrayOperationIndex < len; ++arrayOperationIndex) {
- arrayOperation = this._content[arrayOperationIndex];
+ for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) {
+ arrayOperation = this._operations[arrayOperationIndex];
- if (arrayOperation.operation === DELETE) { continue; }
+ if (arrayOperation.type === DELETE) { continue; }
arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1;
@@ -14820,25 +14876,24 @@ array of the first item for this operation.
},
_split: function (arrayOperationIndex, splitIndex, newArrayOperation) {
- var arrayOperation = this._content[arrayOperationIndex],
+ var arrayOperation = this._operations[arrayOperationIndex],
splitItems = arrayOperation.items.slice(splitIndex),
- splitArrayOperation = new ArrayOperation(arrayOperation.operation, splitItems.length, splitItems);
+ splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems);
// truncate LHS
arrayOperation.count = splitIndex;
arrayOperation.items = arrayOperation.items.slice(0, splitIndex);
- this._content.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation);
+ this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation);
},
- // TODO: unify _composeInsert, _composeDelete
// see SubArray for a better implementation.
_composeInsert: function (index) {
- var newArrayOperation = this._content[index],
- leftArrayOperation = this._content[index-1], // may be undefined
- rightArrayOperation = this._content[index+1], // may be undefined
- leftOp = leftArrayOperation && leftArrayOperation.operation,
- rightOp = rightArrayOperation && rightArrayOperation.operation;
+ var newArrayOperation = this._operations[index],
+ leftArrayOperation = this._operations[index-1], // may be undefined
+ rightArrayOperation = this._operations[index+1], // may be undefined
+ leftOp = leftArrayOperation && leftArrayOperation.type,
+ rightOp = rightArrayOperation && rightArrayOperation.type;
if (leftOp === INSERT) {
// merge left
@@ -14846,30 +14901,31 @@ array of the first item for this operation.
leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items);
if (rightOp === INSERT) {
- // also merge right
+ // also merge right (we have split an insert with an insert)
leftArrayOperation.count += rightArrayOperation.count;
leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items);
- this._content.splice(index, 2);
+ this._operations.splice(index, 2);
} else {
// only merge left
- this._content.splice(index, 1);
+ this._operations.splice(index, 1);
}
} else if (rightOp === INSERT) {
// merge right
newArrayOperation.count += rightArrayOperation.count;
newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items);
- this._content.splice(index + 1, 1);
+ this._operations.splice(index + 1, 1);
}
},
_composeDelete: function (index) {
- var arrayOperation = this._content[index],
+ var arrayOperation = this._operations[index],
deletesToGo = arrayOperation.count,
- leftArrayOperation = this._content[index-1], // may be undefined
- leftOp = leftArrayOperation && leftArrayOperation.operation,
+ leftArrayOperation = this._operations[index-1], // may be undefined
+ leftOp = leftArrayOperation && leftArrayOperation.type,
nextArrayOperation,
nextOp,
nextCount,
+ removeNewAndNextOp = false,
removedItems = [];
if (leftOp === DELETE) {
@@ -14878,8 +14934,8 @@ array of the first item for this operation.
}
for (var i = index + 1; deletesToGo > 0; ++i) {
- nextArrayOperation = this._content[i];
- nextOp = nextArrayOperation.operation;
+ nextArrayOperation = this._operations[i];
+ nextOp = nextArrayOperation.type;
nextCount = nextArrayOperation.count;
if (nextOp === DELETE) {
@@ -14888,6 +14944,7 @@ array of the first item for this operation.
}
if (nextCount > deletesToGo) {
+ // d:2 {r,i}:5 we reduce the retain or insert, but it stays
removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo));
nextArrayOperation.count -= deletesToGo;
@@ -14899,29 +14956,57 @@ array of the first item for this operation.
deletesToGo = 0;
} else {
+ if (nextCount === deletesToGo) {
+ // Handle edge case of d:2 i:2 in which case both operations go away
+ // during composition.
+ removeNewAndNextOp = true;
+ }
removedItems = removedItems.concat(nextArrayOperation.items);
deletesToGo -= nextCount;
}
if (nextOp === INSERT) {
+ // d:2 i:3 will result in delete going away
arrayOperation.count -= nextCount;
}
}
if (arrayOperation.count > 0) {
- this._content.splice(index+1, i-1-index);
+ // compose our new delete with possibly several operations to the right of
+ // disparate types
+ this._operations.splice(index+1, i-1-index);
} else {
// The delete operation can go away; it has merely reduced some other
- // operation, as in D:3 I:4
- this._content.splice(index, 1);
+ // operation, as in d:3 i:4; it may also have eliminated that operation,
+ // as in d:3 i:3.
+ this._operations.splice(index, removeNewAndNextOp ? 2 : 1);
}
return removedItems;
+ },
+
+ toString: function () {
+ var str = "";
+ forEach(this._operations, function (operation) {
+ str += " " + operation.type + ":" + operation.count;
+ });
+ return str.substring(1);
}
};
+/**
+ Internal data structure to represent an array operation.
+
+ @method ArrayOperation
+ @private
+ @property {string} type The type of the operation. One of
+ `Ember.TrackedArray.{RETAIN, INSERT, DELETE}`
+ @property {number} count The number of items in this operation.
+ @property {array} items The items of the operation, if included. RETAIN and
+ INSERT include their items, DELETE does not.
+*/
function ArrayOperation (operation, count, items) {
- this.operation = operation; // RETAIN | INSERT | DELETE
+ this.type = operation; // RETAIN | INSERT | DELETE
this.count = count;
this.items = items;
}
@@ -15059,6 +15144,8 @@ Ember.SubArray.prototype = {
self._operations.splice(operationIndex, 1);
self._composeAt(operationIndex);
}
+ }, function() {
+ throw new Ember.Error("Can't remove an item that has never been added.");
});
return returnValue;
@@ -15105,6 +15192,7 @@ Ember.SubArray.prototype = {
if (otherOp.type === op.type) {
op.count += otherOp.count;
this._operations.splice(index-1, 1);
+ --index;
}
}
@@ -15200,7 +15288,14 @@ function makeCtor() {
var properties = props[i];
- for (var keyName in properties) {
+ if (properties === null || typeof properties !== 'object') {
+
+ 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],
@@ -15387,7 +15482,7 @@ CoreObject.PrototypeMixin = Mixin.create({
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
@@ -15528,6 +15623,86 @@ var ClassMixin = Mixin.create({
isMethod: false,
+ /**
+ Creates a new subclass.
+
+ ```javascript
+ App.Person = Ember.Object.extend({
+ say: function(thing) {
+ alert(thing);
+ }
+ });
+ ```
+
+ This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`.
+
+ You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class:
+
+ ```javascript
+ App.PersonView = Ember.View.extend({
+ tagName: 'li',
+ classNameBindings: ['isAdministrator']
+ });
+ ```
+
+ When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method:
+
+ ```javascript
+ App.Person = Ember.Object.extend({
+ say: function(thing) {
+ var name = this.get('name');
+ alert(name + ' says: ' + thing);
+ }
+ });
+
+ App.Soldier = App.Person.extend({
+ say: function(thing) {
+ this._super(thing + ", sir!");
+ },
+ march: function(numberOfHours) {
+ alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.')
+ }
+ });
+
+ var yehuda = App.Soldier.create({
+ name: "Yehuda Katz"
+ });
+
+ yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!"
+ ```
+
+ The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method.
+
+ You can also pass `Ember.Mixin` classes to add additional properties to the subclass.
+
+ ```javascript
+ App.Person = Ember.Object.extend({
+ say: function(thing) {
+ alert(this.get('name') + ' says: ' + thing);
+ }
+ });
+
+ App.SingingMixin = Ember.Mixin.create({
+ sing: function(thing){
+ alert(this.get('name') + ' sings: la la la ' + thing);
+ }
+ });
+
+ App.BroadwayStar = App.Person.extend(App.SingingMixin, {
+ dance: function() {
+ alert(this.get('name') + ' dances: tap tap tap tap ');
+ }
+ });
+ ```
+
+ The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`.
+
+ @method extend
+ @static
+
+ @param {Ember.Mixin} [mixins]* One or more Ember.Mixin classes
+ @param {Object} [arguments]* Object containing values to use within the new class
+ */
extend: function() {
var Class = makeCtor(), proto;
Class.ClassMixin = Mixin.create(this.ClassMixin);
@@ -15608,10 +15783,10 @@ var ClassMixin = Mixin.create({
},
/**
-
+
Augments a constructor's prototype with additional
properties and functions:
-
+
```javascript
MyObject = Ember.Object.extend({
name: 'an object'
@@ -15631,7 +15806,7 @@ var ClassMixin = Mixin.create({
o.say("goodbye"); // logs "goodbye"
```
-
+
To add functions and properties to the constructor itself,
see `reopenClass`
@@ -15645,7 +15820,7 @@ var ClassMixin = Mixin.create({
/**
Augments a constructor's own properties and functions:
-
+
```javascript
MyObject = Ember.Object.extend({
name: 'an object'
@@ -15655,17 +15830,50 @@ var ClassMixin = Mixin.create({
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
+ and not on any instance of that class.
+
+ ```javascript
+ App.Person = Ember.Object.extend({
+ name : "",
+ sayHello : function(){
+ alert("Hello. My name is " + this.get('name'));
+ }
+ });
+
+ App.Person.reopenClass({
+ species : "Homo sapiens",
+ createPerson: function(newPersonsName){
+ return App.Person.create({
+ name:newPersonsName
+ });
+ }
+ });
+
+ var tom = App.Person.create({
+ name : "Tom Dale"
+ });
+ var yehuda = App.Person.createPerson("Yehuda Katz");
+
+ 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`
+ 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);
@@ -16221,7 +16429,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,/** @scope Ember.Array
},
_insertAt: function(idx, object) {
- if (idx > get(this, 'content.length')) throw new Error(OUT_OF_RANGE_EXCEPTION);
+ if (idx > get(this, 'content.length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
this._replace(idx, 0, [object]);
return this;
},
@@ -16241,7 +16449,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,/** @scope Ember.Array
indices = [], i;
if ((start < 0) || (start >= get(this, 'length'))) {
- throw new Error(OUT_OF_RANGE_EXCEPTION);
+ throw new Ember.Error(OUT_OF_RANGE_EXCEPTION);
}
if (len === undefined) len = 1;
@@ -17008,7 +17216,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
@return {Ember.Set} An empty Set
*/
clear: function() {
- if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); }
+ if (this.isFrozen) { throw new Ember.Error(Ember.FROZEN_ERROR); }
var len = get(this, 'length');
if (len === 0) { return this; }
@@ -17118,7 +17326,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
@return {Object} The removed object from the set or null.
*/
pop: function() {
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
+ if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR);
var obj = this.length > 0 ? this[this.length-1] : null;
this.remove(obj);
return obj;
@@ -17235,7 +17443,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
// implements Ember.MutableEnumerable
addObject: function(obj) {
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
+ if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR);
if (isNone(obj)) return this; // nothing to do
var guid = guidFor(obj),
@@ -17263,7 +17471,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
// implements Ember.MutableEnumerable
removeObject: function(obj) {
- if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR);
+ if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR);
if (isNone(obj)) return this; // nothing to do
var guid = guidFor(obj),
@@ -17969,7 +18177,7 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
fullName = "controller:" + controllerClass;
if (!container.has(fullName)) {
- throw new Error('Could not resolve itemController: "' + controllerClass + '"');
+ throw new Ember.Error('Could not resolve itemController: "' + controllerClass + '"');
}
subController = container.lookupFactory(fullName).create({
@@ -18291,6 +18499,19 @@ function escapeAttribute(value) {
return string.replace(BAD_CHARS_REGEXP, escapeChar);
}
+// IE 6/7 have bugs arond setting names on inputs during creation.
+// From http://msdn.microsoft.com/en-us/library/ie/ms536389(v=vs.85).aspx:
+// "To include the NAME attribute at run time on objects created with the createElement method, use the eTag."
+var canSetNameOnInputs = (function() {
+ var div = document.createElement('div'),
+ el = document.createElement('input');
+
+ el.setAttribute('name', 'foo');
+ div.appendChild(el);
+
+ return !!div.innerHTML.match('foo');
+})();
+
/**
`Ember.RenderBuffer` gathers information regarding the a view and generates the
final representation. `Ember.RenderBuffer` will generate HTML which can be pushed
@@ -18650,14 +18871,22 @@ Ember._RenderBuffer.prototype =
generateElement: function() {
var tagName = this.tagNames.pop(), // pop since we don't need to close
- element = document.createElement(tagName),
- $element = Ember.$(element),
id = this.elementId,
classes = this.classes,
attrs = this.elementAttributes,
props = this.elementProperties,
style = this.elementStyle,
- styleBuffer = '', attr, prop;
+ styleBuffer = '', attr, prop, tagString;
+
+ if (attrs && attrs.name && !canSetNameOnInputs) {
+ // IE allows passing a tag to createElement. See note on `canSetNameOnInputs` above as well.
+ tagString = '<'+stripTagName(tagName)+' name="'+escapeAttribute(attrs.name)+'">';
+ } else {
+ tagString = tagName;
+ }
+
+ var element = document.createElement(tagString),
+ $element = Ember.$(element);
if (id) {
$element.attr('id', id);
@@ -19071,7 +19300,7 @@ var childViewsProperty = Ember.computed(function() {
return view.replace(idx, removedCount, addedViews);
}
- throw new Error("childViews is immutable");
+ throw new Ember.Error("childViews is immutable");
};
return ret;
@@ -20757,8 +20986,8 @@ Ember.View = Ember.CoreView.extend(
If you write a `willDestroyElement()` handler, you can assume that your
`didInsertElement()` handler was called earlier for the same element.
- Normally you will not call or override this method yourself, but you may
- want to implement the above callbacks when it is run.
+ You should not call or override this method yourself, but you may
+ want to implement the above callbacks.
@method destroyElement
@return {Ember.View} receiver
@@ -21283,6 +21512,10 @@ Ember.View = Ember.CoreView.extend(
target = null;
}
+ if (!root || typeof root !== 'object') {
+ return;
+ }
+
var view = this,
stateCheckedObserver = function() {
view.currentState.invokeObserver(this, observer);
@@ -21819,7 +22052,7 @@ Ember.merge(inDOM, {
}
view.addBeforeObserver('elementId', function() {
- throw new Error("Changing a view's elementId after creation is not allowed");
+ throw new Ember.Error("Changing a view's elementId after creation is not allowed");
});
},
@@ -22059,30 +22292,6 @@ var ViewCollection = Ember._ViewCollection;
or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM
representation will only be the rendered HTML of its child views.
- ## Binding a View to Display
-
- If you would like to display a single view in your ContainerView, you can set
- its `currentView` property. When the `currentView` property is set to a view
- instance, it will be added to the ContainerView. If the `currentView` property
- is later changed to a different view, the new view will replace the old view.
- If `currentView` is set to `null`, the last `currentView` will be removed.
-
- This functionality is useful for cases where you want to bind the display of
- a ContainerView to a controller or state manager. For example, you can bind
- the `currentView` of a container to a controller like this:
-
- ```javascript
- App.appController = Ember.Object.create({
- view: Ember.View.create({
- templateName: 'person_template'
- })
- });
- ```
-
- ```handlebars
- {{view Ember.ContainerView currentViewBinding="App.appController.view"}}
- ```
-
@class ContainerView
@namespace Ember
@extends Ember.View
@@ -22267,7 +22476,7 @@ Ember.merge(states._default, {
Ember.merge(states.inBuffer, {
childViewsDidChange: function(parentView, views, start, added) {
- throw new Error('You cannot modify child views while in the inBuffer state');
+ throw new Ember.Error('You cannot modify child views while in the inBuffer state');
}
});
@@ -22758,7 +22967,9 @@ Ember.CollectionView.CONTAINER_MAP = {
(function() {
-var get = Ember.get, set = Ember.set, isNone = Ember.isNone;
+var get = Ember.get, set = Ember.set, isNone = Ember.isNone,
+ a_slice = Array.prototype.slice;
+
/**
@module ember
@@ -22949,8 +23160,9 @@ Ember.Component = Ember.View.extend(Ember.TargetActionSupport, {
@param [action] {String} the action to trigger
@param [context] {*} a context to send with the action
*/
- sendAction: function(action, context) {
- var actionName;
+ sendAction: function(action) {
+ var actionName,
+ contexts = a_slice.call(arguments, 1);
// Send the default action
if (action === undefined) {
@@ -22966,7 +23178,7 @@ Ember.Component = Ember.View.extend(Ember.TargetActionSupport, {
this.triggerAction({
action: actionName,
- actionContext: context
+ actionContext: contexts
});
}
});
@@ -23564,20 +23776,6 @@ if (!Handlebars && typeof require === 'function') {
*/
Ember.Handlebars = objectCreate(Handlebars);
-function makeBindings(options) {
- var hash = options.hash,
- hashType = options.hashTypes;
-
- for (var prop in hash) {
- if (hashType[prop] === 'ID') {
- hash[prop + 'Binding'] = hash[prop];
- hashType[prop + 'Binding'] = 'STRING';
- delete hash[prop];
- delete hashType[prop];
- }
- }
-}
-
/**
Register a bound helper or custom view helper.
@@ -23637,7 +23835,6 @@ Ember.Handlebars.helper = function(name, value) {
if (Ember.View.detect(value)) {
Ember.Handlebars.registerHelper(name, function(options) {
- makeBindings(options);
return Ember.Handlebars.helpers.view.call(this, value, options);
});
} else {
@@ -23873,6 +24070,7 @@ var handlebarsGet = Ember.Handlebars.get = function(root, path, options) {
}
return value;
};
+Ember.Handlebars.getPath = Ember.deprecateFunc('`Ember.Handlebars.getPath` has been changed to `Ember.Handlebars.get` for consistency.', Ember.Handlebars.get);
Ember.Handlebars.resolveParams = function(context, params, options) {
var resolvedParams = [], types = options.types, param, type;
@@ -24055,7 +24253,8 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) {
data = options.data,
hash = options.hash,
view = data.view,
- currentContext = (options.contexts && options.contexts[0]) || this,
+ contexts = options.contexts,
+ currentContext = (contexts && contexts.length) ? contexts[0] : this,
prefixPathForDependentKeys = '',
loc, len, hashOption,
boundOption, property,
@@ -24179,7 +24378,7 @@ function evaluateUnboundHelper(context, fn, normalizedProperties, options) {
for(loc = 0, len = normalizedProperties.length; loc < len; ++loc) {
property = normalizedProperties[loc];
- args.push(Ember.Handlebars.get(context, property.path, options));
+ args.push(Ember.Handlebars.get(property.root, property.path, options));
}
args.push(options);
return fn.apply(context, args);
@@ -24823,16 +25022,16 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
}
}
-function simpleBind(property, options) {
+function simpleBind(currentContext, property, options) {
var data = options.data,
view = data.view,
- currentContext = this,
- normalized, observer;
+ normalized, observer, pathRoot, output;
normalized = normalizePath(currentContext, property, data);
+ pathRoot = normalized.root;
// Set up observers for observable objects
- if ('object' === typeof this) {
+ if (pathRoot && ('object' === typeof pathRoot)) {
if (data.insideGroup) {
observer = function() {
Ember.run.once(view, 'rerender');
@@ -24864,7 +25063,8 @@ function simpleBind(property, options) {
} else {
// The object is not observable, so just render it out and
// be done with it.
- data.buffer.push(handlebarsGet(currentContext, property, options));
+ output = handlebarsGet(currentContext, property, options);
+ data.buffer.push((output === null || typeof output === 'undefined') ? '' : output);
}
}
@@ -24921,10 +25121,10 @@ EmberHandlebars.registerHelper('_triageMustache', function(property, fn) {
EmberHandlebars.registerHelper('bind', function(property, options) {
- var context = (options.contexts && options.contexts[0]) || this;
+ var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this;
if (!options.fn) {
- return simpleBind.call(context, property, options);
+ return simpleBind(context, property, options);
}
return bind.call(context, property, options, false, exists);
@@ -24949,7 +25149,7 @@ EmberHandlebars.registerHelper('bind', function(property, options) {
@return {String} HTML string
*/
EmberHandlebars.registerHelper('boundIf', function(property, fn) {
- var context = (fn.contexts && fn.contexts[0]) || this;
+ var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this;
var func = function(result) {
var truthy = result && get(result, 'isTruthy');
if (typeof truthy === 'boolean') { return truthy; }
@@ -25393,6 +25593,35 @@ var EmberHandlebars = Ember.Handlebars;
var LOWERCASE_A_Z = /^[a-z]/;
var VIEW_PREFIX = /^view\./;
+function makeBindings(thisContext, options) {
+ var hash = options.hash,
+ hashType = options.hashTypes;
+
+ for (var prop in hash) {
+ if (hashType[prop] === 'ID') {
+
+ var value = hash[prop];
+
+ if (Ember.IS_BINDING.test(prop)) {
+
+ } else {
+ hash[prop + 'Binding'] = value;
+ hashType[prop + 'Binding'] = 'STRING';
+ delete hash[prop];
+ delete hashType[prop];
+ }
+ }
+ }
+
+ if (hash.hasOwnProperty('idBinding')) {
+ // id can't be bound, so just perform one-time lookup.
+ hash.id = EmberHandlebars.get(thisContext, hash.idBinding, options);
+ hashType.id = 'STRING';
+ delete hash.idBinding;
+ delete hashType.idBinding;
+ }
+}
+
EmberHandlebars.ViewHelper = Ember.Object.create({
propertiesFromHTMLOptions: function(options, thisContext) {
@@ -25502,6 +25731,8 @@ EmberHandlebars.ViewHelper = Ember.Object.create({
fn = options.fn,
newView;
+ makeBindings(thisContext, options);
+
if ('string' === typeof path) {
// TODO: this is a lame conditional, this should likely change
@@ -25989,7 +26220,7 @@ Ember.Handlebars.registerHelper('unbound', function(property, fn) {
return out;
}
- context = (fn.contexts && fn.contexts[0]) || this;
+ context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this;
return handlebarsGet(context, property, fn);
});
@@ -26019,7 +26250,7 @@ var handlebarsGet = Ember.Handlebars.get, normalizePath = Ember.Handlebars.norma
@param {String} property
*/
Ember.Handlebars.registerHelper('log', function(property, options) {
- var context = (options.contexts && options.contexts[0]) || this,
+ var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this,
normalized = normalizePath(context, property, options.data),
pathRoot = normalized.root,
path = normalized.path,
@@ -26632,11 +26863,11 @@ var get = Ember.get, set = Ember.set;
{{#labeled-textfield value=someProperty}}
First name:
- {{/my-component}}
+ {{/labeled-textfield}}
```
```handlebars
-
+
@@ -26799,7 +27030,7 @@ var get = Ember.get, set = Ember.set;
Ember.TextSupport = Ember.Mixin.create({
value: "",
- attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly'],
+ attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex'],
placeholder: null,
disabled: false,
maxlength: null,
@@ -26833,7 +27064,7 @@ Ember.TextSupport = Ember.Mixin.create({
Options are:
* `enter`: the user pressed enter
- * `keypress`: the user pressed a key
+ * `keyPress`: the user pressed a key
@property onEvent
@type String
@@ -26876,7 +27107,7 @@ Ember.TextSupport = Ember.Mixin.create({
Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13.
Uses sendAction to send the `enter` action to the controller.
- @method insertNewLine
+ @method insertNewline
@param {Event} event
*/
insertNewline: function(event) {
@@ -26887,8 +27118,8 @@ Ember.TextSupport = Ember.Mixin.create({
/**
Called when the user hits escape.
- Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13.
- Uses sendAction to send the `enter` action to the controller.
+ Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27.
+ Uses sendAction to send the `escape-press` action to the controller.
@method cancel
@param {Event} event
@@ -27324,7 +27555,7 @@ Ember.SelectOptgroup = Ember.CollectionView.extend({
```
```handlebars
- {{view Ember.Select contentBinding="names"}}
+ {{view Ember.Select content=names}}
```
Would result in the following HTML:
@@ -27337,7 +27568,7 @@ Ember.SelectOptgroup = Ember.CollectionView.extend({
```
You can control which `