dist/ember.prod.js in ember-source-1.3.0.beta.3 vs dist/ember.prod.js in ember-source-1.3.0.beta.4
- old
+ new
@@ -1,17 +1,16 @@
-// ==========================================================================
-// Project: Ember - JavaScript Application Framework
-// Copyright: Copyright 2011-2013 Tilde Inc. and contributors
-// Portions Copyright 2006-2011 Strobe Inc.
-// Portions Copyright 2008-2011 Apple Inc. All rights reserved.
-// License: Licensed under MIT license
-// See https://raw.github.com/emberjs/ember.js/master/LICENSE
-// ==========================================================================
+/*!
+ * @overview Ember - JavaScript Application Framework
+ * @copyright Copyright 2011-2013 Tilde Inc. and contributors
+ * Portions Copyright 2006-2011 Strobe Inc.
+ * Portions Copyright 2008-2011 Apple Inc. All rights reserved.
+ * @license Licensed under MIT license
+ * See https://raw.github.com/emberjs/ember.js/master/LICENSE
+ * @version 1.4.0-beta.1+canary.dc0dc0ce
+ */
- // Version: 1.3.0-beta.3
-
(function() {
var define, requireModule, require, requirejs;
(function() {
var registry = {}, seen = {};
@@ -87,11 +86,11 @@
The core Runtime framework is based on the jQuery API with a number of
performance optimizations.
@class Ember
@static
- @version 1.3.0-beta.3
+ @version 1.4.0-beta.1+canary.dc0dc0ce
*/
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.
@@ -114,14 +113,14 @@
/**
@property VERSION
@type String
- @default '1.3.0-beta.3'
+ @default '1.4.0-beta.1+canary.dc0dc0ce'
@final
*/
-Ember.VERSION = '1.3.0-beta.3';
+Ember.VERSION = '1.4.0-beta.1+canary.dc0dc0ce';
/**
Standard environmental variables. You can define these in a global `ENV`
variable before loading Ember to control various configuration
settings.
@@ -1358,10 +1357,45 @@
}
return ret;
};
+/**
+ Convenience method to inspect an object. This method will attempt to
+ convert the object into a useful string description.
+
+ It is a pretty simple implementation. If you want something more robust,
+ use something like JSDump: https://github.com/NV/jsDump
+
+ @method inspect
+ @for Ember
+ @param {Object} obj The object you want to inspect.
+ @return {String} A description of the object
+*/
+Ember.inspect = function(obj) {
+ var type = Ember.typeOf(obj);
+ if (type === 'array') {
+ return '[' + obj + ']';
+ }
+ if (type !== 'object') {
+ return obj + '';
+ }
+
+ var v, ret = [];
+ for(var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ v = obj[key];
+ if (v === 'toString') { continue; } // ignore useless items
+ if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; }
+ ret.push(key + ": " + v);
+ }
+ }
+ return "{" + ret.join(", ") + "}";
+};
+
+
+
})();
(function() {
@@ -1768,11 +1802,11 @@
target = get(target, key);
path = path.slice(key.length+1);
}
// must return some kind of path to be valid else other things will break.
- if (!path || path.length===0) throw new Ember.Error('Invalid Path');
+ if (!path || path.length===0) throw new Ember.Error('Path cannot be empty');
return [ target, path ];
};
var getPath = Ember._getPath = function(root, path) {
@@ -3819,11 +3853,57 @@
})();
(function() {
+if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ /**
+ @module ember-metal
+ */
+ var forEach = Ember.EnumerableUtils.forEach,
+ 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. Brace expansion can only appear at the end of a
+ pattern, for example as the last item in a chain.
+
+ 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', 'foo.baz'
+ 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) {
+ var match, prefix, list;
+
+ if (match = BRACE_EXPANSION.exec(pattern)) {
+ prefix = match[1];
+ list = match[2];
+
+ forEach(list.split(','), function (suffix) {
+ callback(prefix + suffix);
+ });
+ } else {
+ callback(pattern);
+ }
+ };
+}
+
})();
(function() {
@@ -4023,10 +4103,13 @@
o_create = Ember.create,
META_KEY = Ember.META_KEY,
watch = Ember.watch,
unwatch = Ember.unwatch;
+if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var expandProperties = Ember.expandProperties;
+}
// ..........................................................
// DEPENDENT KEYS
//
@@ -4287,13 +4370,22 @@
@chainable
*/
ComputedPropertyPrototype.property = function() {
var args;
-
+ if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var addArg = function (property) {
+ args.push(property);
+ };
+
+ args = [];
+ for (var i = 0, l = arguments.length; i < l; i++) {
+ expandProperties(arguments[i], addArg);
+ }
+ } else {
args = a_slice.call(arguments);
-
+ }
this._dependentKeys = args;
return this;
};
@@ -4418,11 +4510,11 @@
hadCachedValue = false,
cache = meta.cache,
funcArgLength, cachedValue, ret;
if (this._readOnly) {
- throw new Ember.Error('Cannot Set: ' + keyName + ' on: ' + obj.toString() );
+ throw new Ember.Error('Cannot Set: ' + keyName + ' on: ' + Ember.inspect(obj));
}
this._suspended = obj;
try {
@@ -5095,11 +5187,55 @@
return Ember.computed(dependentKey, function() {
return get(this, dependentKey);
});
};
+if (Ember.FEATURES.isEnabled('computed-read-only')) {
+/**
+ Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides
+ a readOnly one way binding. Very often when using `computed.oneWay` one does
+ not also want changes to propogate back up, as they will replace the value.
+ This prevents the reverse flow, and also throws an exception when it occurs.
+
+ Example
+
+ ```javascript
+ User = Ember.Object.extend({
+ firstName: null,
+ lastName: null,
+ nickName: Ember.computed.readOnly('firstName')
+ });
+
+ user = User.create({
+ firstName: 'Teddy',
+ lastName: 'Zeenny'
+ });
+
+ user.get('nickName');
+ # 'Teddy'
+
+ user.set('nickName', 'TeddyBear');
+ # throws Exception
+ # throw new Ember.Error('Cannot Set: nickName on: <User:ember27288>' );`
+
+ user.get('firstName');
+ # 'Teddy'
+ ```
+
+ @method computed.readOnly
+ @for Ember
+ @param {String} dependentKey
+ @return {Ember.ComputedProperty} computed property which creates a
+ one way computed property to the original value for property.
+*/
+Ember.computed.readOnly = function(dependentKey) {
+ return Ember.computed(dependentKey, function() {
+ return get(this, dependentKey);
+ }).readOnly();
+};
+}
/**
A computed property that acts like a standard getter and setter,
but returns the value at the provided `defaultPath` if the
property itself has not been set to a value
@@ -6173,11 +6309,11 @@
@param {Object} [target] The target of the method to invoke.
@param {Function|String} method The method to invoke.
If you pass a string it will be resolved on the
target at the time the method is invoked.
@param {Object} [args*] Optional arguments to pass to the timeout.
- @return {Object} timer
+ @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
*/
Ember.run.once = function(target, method) {
checkAutoRun();
var args = slice.call(arguments);
args.unshift('actions');
@@ -6224,11 +6360,11 @@
@param {Object} [target] The target of the method to invoke.
@param {Function|String} method The method to invoke.
If you pass a string it will be resolved on the
target at the time the method is invoked.
@param {Object} [args*] Optional arguments to pass to the timeout.
- @return {Object} timer
+ @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
*/
Ember.run.scheduleOnce = function(queue, target, method) {
checkAutoRun();
return backburner.scheduleOnce.apply(backburner, arguments);
};
@@ -6286,21 +6422,22 @@
@param {Object} [target] target of method to invoke
@param {Function|String} method The method to invoke.
If you pass a string it will be resolved on the
target at the time the method is invoked.
@param {Object} [args*] Optional arguments to pass to the timeout.
- @return {Object} timer
+ @return {Object} Timer information for use in cancelling, see `Ember.run.cancel`.
*/
Ember.run.next = function() {
var args = slice.call(arguments);
args.push(1);
return backburner.later.apply(backburner, args);
};
/**
Cancels a scheduled item. Must be a value returned by `Ember.run.later()`,
- `Ember.run.once()`, or `Ember.run.next()`.
+ `Ember.run.once()`, `Ember.run.next()`, `Ember.run.debounce()`, or
+ `Ember.run.throttle()`.
```javascript
var runNext = Ember.run.next(myContext, function() {
// will not be executed
});
@@ -6313,15 +6450,33 @@
var runOnce = Ember.run.once(myContext, function() {
// will not be executed
});
Ember.run.cancel(runOnce);
+
+ var throttle = Ember.run.throttle(myContext, function() {
+ // will not be executed
+ }, 1);
+ Ember.run.cancel(throttle);
+
+ var debounce = Ember.run.debounce(myContext, function() {
+ // will not be executed
+ }, 1);
+ Ember.run.cancel(debounce);
+
+ var debounceImmediate = Ember.run.debounce(myContext, function() {
+ // will be executed since we passed in true (immediate)
+ }, 100, true);
+ // the 100ms delay until this method can be called again will be cancelled
+ Ember.run.cancel(debounceImmediate);
```
+ ```
+ ```
@method cancel
@param {Object} timer Timer object to cancel
- @return {void}
+ @return {Boolean} true if cancelled or false/undefined if it wasn't found
*/
Ember.run.cancel = function(timer) {
return backburner.cancel(timer);
};
@@ -6349,19 +6504,47 @@
// 150ms passes
// myFunc is invoked with context myContext
// console logs 'debounce ran.' one time.
```
+ Immediate allows you to run the function immediately, but debounce
+ other calls for this function until the wait time has elapsed. If
+ `debounce` is called again before the specified time has elapsed,
+ the timer is reset and the entire period msut pass again before
+ the method can be called again.
+
+ ```javascript
+ var myFunc = function() { console.log(this.name + ' ran.'); };
+ var myContext = {name: 'debounce'};
+
+ Ember.run.debounce(myContext, myFunc, 150, true);
+
+ // console logs 'debounce ran.' one time immediately.
+ // 100ms passes
+
+ Ember.run.debounce(myContext, myFunc, 150, true);
+
+ // 150ms passes and nothing else is logged to the console and
+ // the debouncee is no longer being watched
+
+ Ember.run.debounce(myContext, myFunc, 150, true);
+
+ // console logs 'debounce ran.' one time immediately.
+ // 150ms passes and nothing else is logged tot he console and
+ // the debouncee is no longer being watched
+
+ ```
+
@method debounce
@param {Object} [target] target of method to invoke
@param {Function|String} method The method to invoke.
May be a function or a string. If you pass a string
then it will be looked up on the passed target.
@param {Object} [args*] Optional arguments to pass to the timeout.
@param {Number} wait Number of milliseconds to wait.
@param {Boolean} immediate Trigger the function on the leading instead of the trailing edge of the wait interval.
- @return {void}
+ @return {Array} Timer information for use in cancelling, see `Ember.run.cancel`.
*/
Ember.run.debounce = function() {
return backburner.debounce.apply(backburner, arguments);
};
@@ -6394,11 +6577,11 @@
@param {Function|String} method The method to invoke.
May be a function or a string. If you pass a string
then it will be looked up on the passed target.
@param {Object} [args*] Optional arguments to pass to the timeout.
@param {Number} spacing Number of milliseconds to space out requests.
- @return {void}
+ @return {Array} Timer information for use in cancelling, see `Ember.run.cancel`.
*/
Ember.run.throttle = function() {
return backburner.throttle.apply(backburner, arguments);
};
@@ -6904,10 +7087,13 @@
a_slice = [].slice,
o_create = Ember.create,
defineProperty = Ember.defineProperty,
guidFor = Ember.guidFor;
+if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var expandProperties = Ember.expandProperties;
+}
function mixinsMeta(obj) {
var m = Ember.meta(obj, true), ret = m.mixins;
if (!ret) {
ret = m.mixins = {};
@@ -7478,39 +7664,10 @@
this.methodName = methodName;
};
Alias.prototype = new Ember.Descriptor();
/**
- Makes a property or method available via an additional name.
-
- ```javascript
- App.PaintSample = Ember.Object.extend({
- color: 'red',
- colour: Ember.alias('color'),
- name: function() {
- return "Zed";
- },
- moniker: Ember.alias("name")
- });
-
- var paintSample = App.PaintSample.create()
- paintSample.get('colour'); // 'red'
- paintSample.moniker(); // 'Zed'
- ```
-
- @method alias
- @for Ember
- @param {String} methodName name of the method or property to alias
- @return {Ember.Descriptor}
- @deprecated Use `Ember.aliasMethod` or `Ember.computed.alias` instead
-*/
-Ember.alias = function(methodName) {
-
- return new Alias(methodName);
-};
-
-/**
Makes a method available via an additional name.
```javascript
App.Person = Ember.Object.extend({
name: function() {
@@ -7560,20 +7717,36 @@
*/
Ember.observer = function() {
var func = a_slice.call(arguments, -1)[0];
var paths;
-
+ if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var addWatchedProperty = function (path) { paths.push(path); };
+ var _paths = a_slice.call(arguments, 0, -1);
+
+ if (typeof func !== "function") {
+ // revert to old, soft-deprecated argument ordering
+
+ func = arguments[0];
+ _paths = a_slice.call(arguments, 1);
+ }
+
+ paths = [];
+
+ for (var i=0; i<_paths.length; ++i) {
+ expandProperties(_paths[i], addWatchedProperty);
+ }
+ } else {
paths = a_slice.call(arguments, 0, -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");
}
@@ -7658,20 +7831,37 @@
*/
Ember.beforeObserver = function() {
var func = a_slice.call(arguments, -1)[0];
var paths;
-
+ if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var addWatchedProperty = function(path) { paths.push(path); };
+
+ var _paths = a_slice.call(arguments, 0, -1);
+
+ if (typeof func !== "function") {
+ // revert to old, soft-deprecated argument ordering
+
+ func = arguments[0];
+ _paths = a_slice.call(arguments, 1);
+ }
+
+ paths = [];
+
+ for (var i=0; i<_paths.length; ++i) {
+ expandProperties(_paths[i], addWatchedProperty);
+ }
+ } else {
paths = a_slice.call(arguments, 0, -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");
}
@@ -7745,11 +7935,11 @@
(function() {
/**
@class RSVP
@module RSVP
*/
-define("rsvp/all",
+define("rsvp/all",
["./promise","./utils","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/* global toString */
@@ -7841,11 +8031,11 @@
}
__exports__.all = all;
});
-define("rsvp/cast",
+define("rsvp/cast",
["exports"],
function(__exports__) {
"use strict";
/**
`RSVP.Promise.cast` returns the same promise if that promise shares a constructor
@@ -7912,11 +8102,11 @@
});
}
__exports__.cast = cast;
});
-define("rsvp/config",
+define("rsvp/config",
["./events","exports"],
function(__dependency1__, __exports__) {
"use strict";
var EventTarget = __dependency1__.EventTarget;
@@ -7943,11 +8133,11 @@
}
__exports__.config = config;
__exports__.configure = configure;
});
-define("rsvp/defer",
+define("rsvp/defer",
["./promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
@@ -7998,11 +8188,11 @@
return deferred;
}
__exports__.defer = defer;
});
-define("rsvp/events",
+define("rsvp/events",
["exports"],
function(__exports__) {
"use strict";
var indexOf = function(callbacks, callback) {
for (var i=0, l=callbacks.length; i<l; i++) {
@@ -8207,11 +8397,11 @@
}
};
__exports__.EventTarget = EventTarget;
});
-define("rsvp/hash",
+define("rsvp/hash",
["./promise","./utils","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
var isFunction = __dependency2__.isFunction;
@@ -8352,11 +8542,11 @@
});
}
__exports__.hash = hash;
});
-define("rsvp/instrument",
+define("rsvp/instrument",
["./config","./utils","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var config = __dependency1__.config;
var now = __dependency2__.now;
@@ -8379,11 +8569,11 @@
}
}
__exports__.instrument = instrument;
});
-define("rsvp/node",
+define("rsvp/node",
["./promise","./all","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
var all = __dependency2__.all;
@@ -8494,11 +8684,11 @@
};
}
__exports__.denodeify = denodeify;
});
-define("rsvp/promise",
+define("rsvp/promise",
["./config","./events","./cast","./instrument","./utils","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
var config = __dependency1__.config;
var EventTarget = __dependency2__.EventTarget;
@@ -8743,11 +8933,11 @@
publish(promise, promise._state = REJECTED);
}
__exports__.Promise = Promise;
});
-define("rsvp/race",
+define("rsvp/race",
["./promise","./utils","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/* global toString */
@@ -8835,11 +9025,11 @@
}, label);
}
__exports__.race = race;
});
-define("rsvp/reject",
+define("rsvp/reject",
["./promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
@@ -8885,11 +9075,11 @@
}, label);
}
__exports__.reject = reject;
});
-define("rsvp/resolve",
+define("rsvp/resolve",
["./promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
@@ -8931,11 +9121,11 @@
}, label);
}
__exports__.resolve = resolve;
});
-define("rsvp/rethrow",
+define("rsvp/rethrow",
["exports"],
function(__exports__) {
"use strict";
var local = (typeof global === "undefined") ? this : global;
@@ -8984,11 +9174,11 @@
throw reason;
}
__exports__.rethrow = rethrow;
});
-define("rsvp/utils",
+define("rsvp/utils",
["exports"],
function(__exports__) {
"use strict";
function objectOrFunction(x) {
return isFunction(x) || (typeof x === "object" && x !== null);
@@ -9010,11 +9200,11 @@
__exports__.objectOrFunction = objectOrFunction;
__exports__.isFunction = isFunction;
__exports__.isArray = isArray;
__exports__.now = now;
});
-define("rsvp",
+define("rsvp",
["./rsvp/events","./rsvp/promise","./rsvp/node","./rsvp/all","./rsvp/race","./rsvp/hash","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/resolve","./rsvp/reject", "exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) {
"use strict";
var EventTarget = __dependency1__.EventTarget;
var Promise = __dependency2__.Promise;
@@ -9054,10 +9244,11 @@
__exports__.off = off;
__exports__.resolve = resolve;
__exports__.reject = reject;
__exports__.async = async;
});
+
})();
(function() {
/**
@private
@@ -9074,10 +9265,11 @@
Ember.MODEL_FACTORY_INJECTIONS = false || !!Ember.ENV.MODEL_FACTORY_INJECTIONS;
define("container",
[],
function() {
+ "use strict";
// A safe and simple inheriting object.
function InheritingDict(parent) {
this.parent = parent;
this.dict = {};
@@ -9195,11 +9387,12 @@
this.resolver = parent && parent.resolver || function() {};
this.registry = new InheritingDict(parent && parent.registry);
this.cache = new InheritingDict(parent && parent.cache);
- this.factoryCache = new InheritingDict(parent && parent.cache);
+ this.factoryCache = new InheritingDict(parent && parent.factoryCache);
+ this.resolveCache = new InheritingDict(parent && parent.resolveCache);
this.typeInjections = new InheritingDict(parent && parent.typeInjections);
this.injections = {};
this.factoryTypeInjections = new InheritingDict(parent && parent.factoryTypeInjections);
this.factoryInjections = {};
@@ -9316,13 +9509,11 @@
@param {String} fullName
@param {Function} factory
@param {Object} options
*/
register: function(fullName, factory, options) {
- if (fullName.indexOf(':') === -1) {
- throw new TypeError("malformed fullName, expected: `type:name` got: " + fullName + "");
- }
+ validateFullName(fullName);
if (factory === undefined) {
throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`');
}
@@ -9351,15 +9542,18 @@
@method unregister
@param {String} fullName
*/
unregister: function(fullName) {
+ validateFullName(fullName);
+
var normalizedName = this.normalize(fullName);
this.registry.remove(normalizedName);
this.cache.remove(normalizedName);
this.factoryCache.remove(normalizedName);
+ this.resolveCache.remove(normalizedName);
this._options.remove(normalizedName);
},
/**
Given a fullName return the corresponding factory.
@@ -9392,11 +9586,22 @@
@method resolve
@param {String} fullName
@return {Function} fullName's factory
*/
resolve: function(fullName) {
- return this.resolver(fullName) || this.registry.get(fullName);
+ validateFullName(fullName);
+
+ var normalizedName = this.normalize(fullName);
+ var cached = this.resolveCache.get(normalizedName);
+
+ if (cached) { return cached; }
+
+ var resolved = this.resolver(normalizedName) || this.registry.get(normalizedName);
+
+ this.resolveCache.set(normalizedName, resolved);
+
+ return resolved;
},
/**
A hook that can be used to describe how the resolver will
attempt to find the factory.
@@ -9473,38 +9678,24 @@
@param {String} fullName
@param {Object} options
@return {any}
*/
lookup: function(fullName, options) {
- fullName = this.normalize(fullName);
-
- options = options || {};
-
- if (this.cache.has(fullName) && options.singleton !== false) {
- return this.cache.get(fullName);
- }
-
- var value = instantiate(this, fullName);
-
- if (value === undefined) { return; }
-
- if (isSingleton(this, fullName) && options.singleton !== false) {
- this.cache.set(fullName, value);
- }
-
- return value;
+ validateFullName(fullName);
+ return lookup(this, this.normalize(fullName), options);
},
/**
Given a fullName return the corresponding factory.
@method lookupFactory
@param {String} fullName
@return {any}
*/
lookupFactory: function(fullName) {
- return factoryFor(this, fullName);
+ validateFullName(fullName);
+ return factoryFor(this, this.normalize(fullName));
},
/**
Given a fullName check if the container is aware of its factory
or singleton instance.
@@ -9512,15 +9703,12 @@
@method has
@param {String} fullName
@return {Boolean}
*/
has: function(fullName) {
- if (this.cache.has(fullName)) {
- return true;
- }
-
- return !!this.resolve(fullName);
+ validateFullName(fullName);
+ return has(this, this.normalize(fullName));
},
/**
Allow registering options for all factories of a type.
@@ -9598,10 +9786,11 @@
@param {String} type
@param {String} property
@param {String} fullName
*/
typeInjection: function(type, property, fullName) {
+ validateFullName(fullName);
if (this.parent) { illegalChildOperation('typeInjection'); }
addTypeInjection(this.typeInjections, type, property, fullName);
},
@@ -9647,18 +9836,24 @@
@method injection
@param {String} factoryName
@param {String} property
@param {String} injectionName
*/
- injection: function(factoryName, property, injectionName) {
+ injection: function(fullName, property, injectionName) {
if (this.parent) { illegalChildOperation('injection'); }
- if (factoryName.indexOf(':') === -1) {
- return this.typeInjection(factoryName, property, injectionName);
+ validateFullName(injectionName);
+ var normalizedInjectionName = this.normalize(injectionName);
+
+ if (fullName.indexOf(':') === -1) {
+ return this.typeInjection(fullName, property, normalizedInjectionName);
}
- addInjection(this.injections, factoryName, property, injectionName);
+ validateFullName(fullName);
+ var normalizedName = this.normalize(fullName);
+
+ addInjection(this.injections, normalizedName, property, normalizedInjectionName);
},
/**
@private
@@ -9691,11 +9886,11 @@
@param {String} fullName
*/
factoryTypeInjection: function(type, property, fullName) {
if (this.parent) { illegalChildOperation('factoryTypeInjection'); }
- addTypeInjection(this.factoryTypeInjections, type, property, fullName);
+ addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName));
},
/**
Defines factory injection rules.
@@ -9743,28 +9938,34 @@
@method factoryInjection
@param {String} factoryName
@param {String} property
@param {String} injectionName
*/
- factoryInjection: function(factoryName, property, injectionName) {
+ factoryInjection: function(fullName, property, injectionName) {
if (this.parent) { illegalChildOperation('injection'); }
- if (factoryName.indexOf(':') === -1) {
- return this.factoryTypeInjection(factoryName, property, injectionName);
+ var normalizedName = this.normalize(fullName);
+ var normalizedInjectionName = this.normalize(injectionName);
+
+ validateFullName(injectionName);
+
+ if (fullName.indexOf(':') === -1) {
+ return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName);
}
- addInjection(this.factoryInjections, factoryName, property, injectionName);
+ validateFullName(fullName);
+
+ addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName);
},
/**
A depth first traversal, destroying the container, its descendant containers and all
their managed objects.
@method destroy
*/
destroy: function() {
-
for (var i=0, l=this.children.length; i<l; i++) {
this.children[i].destroy();
}
this.children = [];
@@ -9786,10 +9987,36 @@
}
resetCache(this);
}
};
+ function has(container, fullName){
+ if (container.cache.has(fullName)) {
+ return true;
+ }
+
+ return !!container.resolve(fullName);
+ }
+
+ function lookup(container, fullName, options) {
+ options = options || {};
+
+ if (container.cache.has(fullName) && options.singleton !== false) {
+ return container.cache.get(fullName);
+ }
+
+ var value = instantiate(container, fullName);
+
+ if (value === undefined) { return; }
+
+ if (isSingleton(container, fullName) && options.singleton !== false) {
+ container.cache.set(fullName, value);
+ }
+
+ return value;
+ }
+
function illegalChildOperation(operation) {
throw new Error(operation + " is not currently supported on child containers");
}
function isSingleton(container, fullName) {
@@ -9801,18 +10028,18 @@
function buildInjections(container, injections) {
var hash = {};
if (!injections) { return hash; }
- var injection, lookup;
+ var injection, injectable;
for (var i=0, l=injections.length; i<l; i++) {
injection = injections[i];
- lookup = container.lookup(injection.fullName);
+ injectable = lookup(container, injection.fullName);
- if (lookup !== undefined) {
- hash[injection.property] = lookup;
+ if (injectable !== undefined) {
+ hash[injection.property] = injectable;
} else {
throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`');
}
}
@@ -9833,11 +10060,11 @@
return options[optionName];
}
}
function factoryFor(container, fullName) {
- var name = container.normalize(fullName);
+ var name = fullName;
var factory = container.resolve(name);
var injectedFactory;
var cache = container.factoryCache;
var type = fullName.split(":")[0];
@@ -9943,10 +10170,17 @@
property: property,
fullName: fullName
});
}
+ var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/;
+ function validateFullName(fullName) {
+ if (!VALID_FULL_NAME_REGEXP.test(fullName)) {
+ throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName);
+ }
+ }
+
function addInjection(rules, factoryName, property, injectionName) {
var injections = rules[factoryName] = rules[factoryName] || [];
injections.push({ property: property, fullName: injectionName });
}
@@ -10137,43 +10371,10 @@
if (Ember.Copyable && Ember.Copyable.detect(obj)) return obj.copy(deep);
return _copy(obj, deep, deep ? [] : null, deep ? [] : null);
};
/**
- Convenience method to inspect an object. This method will attempt to
- convert the object into a useful string description.
-
- It is a pretty simple implementation. If you want something more robust,
- use something like JSDump: https://github.com/NV/jsDump
-
- @method inspect
- @for Ember
- @param {Object} obj The object you want to inspect.
- @return {String} A description of the object
-*/
-Ember.inspect = function(obj) {
- var type = Ember.typeOf(obj);
- if (type === 'array') {
- return '[' + obj + ']';
- }
- if (type !== 'object') {
- return obj + '';
- }
-
- var v, ret = [];
- for(var key in obj) {
- if (obj.hasOwnProperty(key)) {
- v = obj[key];
- if (v === 'toString') { continue; } // ignore useless items
- if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; }
- ret.push(key + ": " + v);
- }
- }
- return "{" + ret.join(", ") + "}";
-};
-
-/**
Compares two objects, returning true if they are logically equal. This is
a deeper comparison than a simple triple equal. For sets it will compare the
internal objects. For any other object that implements `isEqual()` it will
respect that method.
@@ -10273,10 +10474,14 @@
var STRING_DASHERIZE_CACHE = {};
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);
+var STRING_PARAMETERIZE_REGEXP_1 = (/[_|\/|\s]+/g);
+var STRING_PARAMETERIZE_REGEXP_2 = (/[^a-z0-9\-]+/gi);
+var STRING_PARAMETERIZE_REGEXP_3 = (/[\-]+/g);
+var STRING_PARAMETERIZE_REGEXP_4 = (/^-+|-+$/g);
/**
Defines the hash of localized strings for the current language. Used by
the `Ember.String.loc()` helper. To localize, add string values to this
hash.
@@ -10511,12 +10716,60 @@
capitalize: function(str) {
return str.charAt(0).toUpperCase() + str.substr(1);
}
};
+if (Ember.FEATURES.isEnabled("string-humanize")) {
+ /**
+ Returns the Humanized form of a string
+ Replaces underscores with spaces, and capitializes first character
+ of string. Also strips "_id" suffixes.
+ ```javascript
+ 'first_name'.humanize() // 'First name'
+ 'user_id'.humanize() // 'User'
+ ```
+
+ @method humanize
+ @param {String} str The string to humanize.
+ @return {String} The humanized string.
+ */
+
+ Ember.String.humanize = function(str) {
+ return str.replace(/_id$/, '').
+ replace(/_/g, ' ').
+ replace(/^\w/g, function(s){
+ return s.toUpperCase();
+ });
+ };
+}
+
+if (Ember.FEATURES.isEnabled("string-parameterize")) {
+ /**
+ Transforms a string so that it may be used as part of a 'pretty' / SEO friendly URL.
+
+ ```javascript
+ 'My favorite items.'.parameterize(); // 'my-favorite-items'
+ 'action_name'.parameterize(); // 'action-name'
+ '100 ways Ember.js is better than Angular.'.parameterize(); // '100-ways-emberjs-is-better-than-angular'
+ ```
+
+ @method parameterize
+ @param {String} str The string to parameterize.
+ @return {String} the parameterized string.
+ */
+ Ember.String.parameterize = function(str) {
+ return str.replace(STRING_PARAMETERIZE_REGEXP_1, '-') // replace underscores, slashes and spaces with separator
+ .replace(STRING_PARAMETERIZE_REGEXP_2, '') // remove non-alphanumeric characters except the separator
+ .replace(STRING_PARAMETERIZE_REGEXP_3, '-') // replace multiple occurring separators
+ .replace(STRING_PARAMETERIZE_REGEXP_4, '') // trim leading and trailing separators
+ .toLowerCase();
+ };
+}
+
+
})();
(function() {
@@ -10535,11 +10788,18 @@
dasherize = Ember.String.dasherize,
underscore = Ember.String.underscore,
capitalize = Ember.String.capitalize,
classify = Ember.String.classify;
+if (Ember.FEATURES.isEnabled("string-humanize")) {
+ var humanize = Ember.String.humanize;
+}
+if (Ember.FEATURES.isEnabled("string-parameterize")) {
+ var parameterize = Ember.String.parameterize;
+}
+
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
/**
See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt).
@@ -10628,11 +10888,34 @@
*/
String.prototype.capitalize = function() {
return capitalize(this);
};
-
+ if (Ember.FEATURES.isEnabled("string-humanize")) {
+ /**
+ See [Ember.String.humanize](/api/classes/Ember.String.html#method_humanize).
+
+ @method humanize
+ @for String
+ */
+ String.prototype.humanize = function() {
+ return humanize(this);
+ };
+ }
+
+ if (Ember.FEATURES.isEnabled("string-parameterize")) {
+ /**
+ See [Ember.String.parameterize](/api/classes/Ember.String.html#method_parameterize).
+
+ @method parameterize
+ @for String
+ */
+ String.prototype.parameterize = function() {
+ return parameterize(this);
+ };
+ }
+
}
})();
@@ -12998,11 +13281,11 @@
if (typeof callback !== "function") { throw new TypeError(); }
var ret = initialValue;
this.forEach(function(item, i) {
- ret = callback.call(null, ret, item, i, this, reducerProperty);
+ ret = callback(ret, item, i, this, reducerProperty);
}, this);
return ret;
},
@@ -13021,11 +13304,11 @@
if (arguments.length>1) args = a_slice.call(arguments, 1);
this.forEach(function(x, idx) {
var method = x && x[methodName];
if ('function' === typeof method) {
- ret[idx] = args ? method.apply(x, args) : method.call(x);
+ ret[idx] = args ? method.apply(x, args) : x[methodName]();
}
}, this);
return ret;
},
@@ -13216,12 +13499,10 @@
implementing an ordered enumerable (such as an array), also pass the
start and end values where the content changed so that it can be used to
notify range observers.
@method enumerableContentDidChange
- @param {Number} [start] optional start offset for the content change.
- For unordered enumerables, you should always pass -1.
@param {Ember.Enumerable|Number} removing An enumerable of the objects to
be removed or the number of items to be removed.
@param {Ember.Enumerable|Number} adding An enumerable of the objects to
be added or the number of items to be added.
@chainable
@@ -13427,11 +13708,11 @@
arr.slice(1, 100); // ['green', 'blue']
```
@method slice
@param {Integer} beginIndex (Optional) index to begin slicing from.
- @param {Integer} endIndex (Optional) index to end the slice at.
+ @param {Integer} endIndex (Optional) index to end the slice at (but not included).
@return {Array} New array with specified slice
*/
slice: function(beginIndex, endIndex) {
var ret = Ember.A();
var length = get(this, 'length') ;
@@ -13578,11 +13859,11 @@
/**
Becomes true whenever the array currently has observers watching changes
on the array.
- @property Boolean
+ @property {Boolean} hasArrayObservers
*/
hasArrayObservers: Ember.computed(function() {
return Ember.hasListeners(this, '@array:change') || Ember.hasListeners(this, '@array:before');
}),
@@ -13727,10 +14008,13 @@
// testing, but there's no particular reason why it should be disallowed.
eachPropertyPattern = /^(.*)\.@each\.(.*)/,
doubleEachPropertyPattern = /(.*\.@each){2,}/,
arrayBracketPattern = /\.\[\]$/;
+if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var expandProperties = Ember.expandProperties;
+}
function get(obj, key) {
if (key === '@this') {
return obj;
}
@@ -14312,14 +14596,21 @@
if (doubleEachPropertyPattern.test(dependentKey)) {
throw new Ember.Error("Nested @each properties not supported: " + dependentKey);
} else if (match = eachPropertyPattern.exec(dependentKey)) {
dependentArrayKey = match[1];
-
+ if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var itemPropertyKeyPattern = match[2],
+ addItemPropertyKey = function (itemPropertyKey) {
+ cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
+ };
+
+ expandProperties(itemPropertyKeyPattern, addItemPropertyKey);
+ } else {
itemPropertyKey = match[2];
cp.itemPropertyKey(dependentArrayKey, itemPropertyKey);
-
+ }
propertyArgs.add(dependentArrayKey);
} else {
propertyArgs.add(dependentKey);
}
});
@@ -14426,11 +14717,11 @@
Example
```javascript
Ember.computed.max = function (dependentKey) {
- return Ember.reduceComputed.call(null, dependentKey, {
+ return Ember.reduceComputed(dependentKey, {
initialValue: -Infinity,
addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
return Math.max(accumulatedValue, item);
},
@@ -14735,33 +15026,39 @@
/**
A computed property that calculates the maximum value in the
dependent array. This will return `-Infinity` when the dependent
array is empty.
- Example
-
```javascript
App.Person = Ember.Object.extend({
childAges: Ember.computed.mapBy('children', 'age'),
maxChildAge: Ember.computed.max('childAges')
});
var lordByron = App.Person.create({children: []});
lordByron.get('maxChildAge'); // -Infinity
- lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
+ lordByron.get('children').pushObject({
+ name: 'Augusta Ada Byron', age: 7
+ });
lordByron.get('maxChildAge'); // 7
- lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]);
+ lordByron.get('children').pushObjects([{
+ name: 'Allegra Byron',
+ age: 5
+ }, {
+ name: 'Elizabeth Medora Leigh',
+ age: 8
+ }]);
lordByron.get('maxChildAge'); // 8
```
@method computed.max
@for Ember
@param {String} dependentKey
@return {Ember.ComputedProperty} computes the largest value in the dependentKey's array
*/
Ember.computed.max = function (dependentKey) {
- return Ember.reduceComputed.call(null, dependentKey, {
+ return Ember.reduceComputed(dependentKey, {
initialValue: -Infinity,
addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
return Math.max(accumulatedValue, item);
},
@@ -14777,33 +15074,39 @@
/**
A computed property that calculates the minimum value in the
dependent array. This will return `Infinity` when the dependent
array is empty.
- Example
-
```javascript
App.Person = Ember.Object.extend({
childAges: Ember.computed.mapBy('children', 'age'),
minChildAge: Ember.computed.min('childAges')
});
var lordByron = App.Person.create({children: []});
lordByron.get('minChildAge'); // Infinity
- lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
+ lordByron.get('children').pushObject({
+ name: 'Augusta Ada Byron', age: 7
+ });
lordByron.get('minChildAge'); // 7
- lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]);
+ lordByron.get('children').pushObjects([{
+ name: 'Allegra Byron',
+ age: 5
+ }, {
+ name: 'Elizabeth Medora Leigh',
+ age: 8
+ }]);
lordByron.get('minChildAge'); // 5
```
@method computed.min
@for Ember
@param {String} dependentKey
@return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array
*/
Ember.computed.min = function (dependentKey) {
- return Ember.reduceComputed.call(null, dependentKey, {
+ return Ember.reduceComputed(dependentKey, {
initialValue: Infinity,
addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
return Math.min(accumulatedValue, item);
},
@@ -14817,29 +15120,30 @@
};
/**
Returns an array mapped via the callback
- The callback method you provide should have the following signature:
+ The callback method you provide should have the following signature.
+ `item` is the current item in the iteration.
```javascript
function(item);
```
- - `item` is the current item in the iteration.
-
Example
```javascript
App.Hamster = Ember.Object.extend({
excitingChores: Ember.computed.map('chores', function(chore) {
return chore.toUpperCase() + '!';
})
});
- var hamster = App.Hamster.create({chores: ['cook', 'clean', 'write more unit tests']});
- hamster.get('excitingChores'); // ['COOK!', 'CLEAN!', 'WRITE MORE UNIT TESTS!']
+ var hamster = App.Hamster.create({
+ chores: ['clean', 'write more unit tests']
+ });
+ hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!']
```
@method computed.map
@for Ember
@param {String} dependentKey
@@ -14863,22 +15167,26 @@
};
/**
Returns an array mapped to the specified key.
- Example
-
```javascript
App.Person = Ember.Object.extend({
childAges: Ember.computed.mapBy('children', 'age')
});
var lordByron = App.Person.create({children: []});
lordByron.get('childAges'); // []
lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
lordByron.get('childAges'); // [7]
- lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]);
+ lordByron.get('children').pushObjects([{
+ name: 'Allegra Byron',
+ age: 5
+ }, {
+ name: 'Elizabeth Medora Leigh',
+ age: 8
+ }]);
lordByron.get('childAges'); // [7, 5, 8]
```
@method computed.mapBy
@for Ember
@@ -14901,20 +15209,17 @@
Ember.computed.mapProperty = Ember.computed.mapBy;
/**
Filters the array by the callback.
- The callback method you provide should have the following signature:
+ The callback method you provide should have the following signature.
+ `item` is the current item in the iteration.
```javascript
function(item);
```
- - `item` is the current item in the iteration.
-
- Example
-
```javascript
App.Hamster = Ember.Object.extend({
remainingChores: Ember.computed.filter('chores', function(chore) {
return !chore.done;
})
@@ -14966,12 +15271,10 @@
};
/**
Filters the array by the property and value
- Example
-
```javascript
App.Hamster = Ember.Object.extend({
remainingChores: Ember.computed.filterBy('chores', 'done', false)
});
@@ -15190,11 +15493,11 @@
*/
Ember.computed.setDiff = function (setAProperty, setBProperty) {
if (arguments.length !== 2) {
throw new Ember.Error("setDiff requires exactly two dependent arrays.");
}
- return Ember.arrayComputed.call(null, setAProperty, setBProperty, {
+ return Ember.arrayComputed(setAProperty, setBProperty, {
addedItem: function (array, item, changeMeta, instanceMeta) {
var setA = get(this, setAProperty),
setB = get(this, setBProperty);
if (changeMeta.arrayChanged === setA) {
@@ -15391,11 +15694,11 @@
instanceMeta.binarySearch = binarySearch;
};
}
- return Ember.arrayComputed.call(null, itemsKey, {
+ return Ember.arrayComputed(itemsKey, {
initialize: initFn,
addedItem: function (array, item, changeMeta, instanceMeta) {
var index = instanceMeta.binarySearch(array, item);
array.insertAt(index, item);
@@ -15454,10 +15757,13 @@
@submodule ember-runtime
*/
var a_slice = Array.prototype.slice;
+if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var expandProperties = Ember.expandProperties;
+}
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
/**
The `property` extension of Javascript's Function prototype is available
@@ -15550,13 +15856,22 @@
@method observes
@for Function
*/
Function.prototype.observes = function() {
-
+ if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var addWatchedProperty = function (obs) { watched.push(obs); };
+ var watched = [];
+
+ for (var i=0; i<arguments.length; ++i) {
+ expandProperties(arguments[i], addWatchedProperty);
+ }
+
+ this.__ember_observes__ = watched;
+ } else {
this.__ember_observes__ = a_slice.call(arguments);
-
+ }
return this;
};
/**
@@ -15615,13 +15930,22 @@
@method observesBefore
@for Function
*/
Function.prototype.observesBefore = function() {
-
+ if (Ember.FEATURES.isEnabled('propertyBraceExpansion')) {
+ var addWatchedProperty = function (obs) { watched.push(obs); };
+ var watched = [];
+
+ for (var i=0; i<arguments.length; ++i) {
+ expandProperties(arguments[i], addWatchedProperty);
+ }
+
+ this.__ember_observesBefore__ = watched;
+ } else {
this.__ember_observesBefore__ = a_slice.call(arguments);
-
+ }
return this;
};
/**
@@ -16588,10 +16912,15 @@
RSVP.configure('async', function(callback, promise) {
Ember.run.schedule('actions', promise, callback, promise);
});
+RSVP.Promise.prototype.fail = function(callback, label){
+
+ return this['catch'](callback, label);
+};
+
/**
@module ember
@submodule ember-runtime
*/
@@ -16697,10 +17026,12 @@
*/
willMergeMixin: function(props) {
var hashName;
if (!props._actions) {
+
+
if (typeOf(props.actions) === 'object') {
hashName = 'actions';
} else if (typeOf(props.events) === 'object') {
hashName = 'events';
@@ -16743,28 +17074,27 @@
(function() {
var set = Ember.set, get = Ember.get,
- resolve = Ember.RSVP.resolve,
- rethrow = Ember.RSVP.rethrow,
not = Ember.computed.not,
or = Ember.computed.or;
/**
@module ember
@submodule ember-runtime
*/
-function observePromise(proxy, promise) {
- promise.then(function(value) {
+function tap(proxy, promise) {
+ return promise.then(function(value) {
set(proxy, 'isFulfilled', true);
set(proxy, 'content', value);
+ return value;
}, function(reason) {
set(proxy, 'isRejected', true);
set(proxy, 'reason', reason);
- // don't re-throw, as we are merely observing
+ throw reason;
});
}
/**
A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware.
@@ -16838,13 +17168,11 @@
isRejected: false,
isFulfilled: false,
promise: Ember.computed(function(key, promise) {
if (arguments.length === 2) {
- promise = resolve(promise);
- observePromise(this, promise);
- return promise.then(); // fork the promise.
+ return tap(this, promise);
} else {
throw new Ember.Error("PromiseProxy's promise must be set");
}
}),
@@ -19295,11 +19623,11 @@
/**
@module ember
@submodule ember-views
*/
-var jQuery = this.jQuery || (Ember.imports && Ember.imports.jQuery);
+var jQuery = (this && this.jQuery) || (Ember.imports && Ember.imports.jQuery);
if (!jQuery && typeof require === 'function') {
jQuery = require('jquery');
}
@@ -19345,21 +19673,21 @@
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use ­
-var needsShy = this.document && (function() {
+var needsShy = typeof document !== 'undefined' && (function() {
var testEl = document.createElement('div');
testEl.innerHTML = "<div></div>";
testEl.firstChild.innerHTML = "<script></script>";
return testEl.firstChild.innerHTML === '';
})();
// IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph.
-var movesWhitespace = this.document && (function() {
+var movesWhitespace = typeof document !== 'undefined' && (function() {
var testEl = document.createElement('div');
testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
return testEl.childNodes[0].nodeValue === 'Test:' &&
testEl.childNodes[2].nodeValue === ' Value';
})();
@@ -22587,10 +22915,12 @@
* preRender: when a view is first instantiated, and after its
element was destroyed, it is in the preRender state
* inBuffer: once a view has been rendered, but before it has
been inserted into the DOM, it is in the inBuffer state
+ * hasElement: the DOM representation of the view is created,
+ and is ready to be inserted
* inDOM: once a view has been inserted into the DOM it is in
the inDOM state. A view spends the vast majority of its
existence in this state.
* destroyed: once a view has been destroyed (using the destroy
method), it is in this state. No further actions can be invoked
@@ -23085,11 +23415,21 @@
invokeObserver: function(target, observer) {
observer.call(target);
}
});
+})();
+
+
+(function() {
+/**
+@module ember
+@submodule ember-views
+*/
+
+var hasElement = Ember.View.states.hasElement;
var inDOM = Ember.View.states.inDOM = Ember.create(hasElement);
Ember.merge(inDOM, {
enter: function(view) {
// Register the view for event handling. This hash is used by
@@ -23652,19 +23992,19 @@
in the item views receiving an appropriately matched `tagName` property.
Given an empty `<body>` and the following code:
```javascript
- anUndorderedListView = Ember.CollectionView.create({
+ anUnorderedListView = Ember.CollectionView.create({
tagName: 'ul',
content: ['A','B','C'],
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile("the letter: {{view.content}}")
})
});
- anUndorderedListView.appendTo('body');
+ anUnorderedListView.appendTo('body');
```
Will result in the following HTML structure
```html
@@ -24360,20 +24700,19 @@
// Copyright: ©2011 My Company Inc. All rights reserved.
// ==========================================================================
var K = function() {},
guid = 0,
- document = this.document,
disableRange = ('undefined' === typeof ENV ? {} : ENV).DISABLE_RANGE_API,
// Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
- supportsRange = (!disableRange) && document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
+ supportsRange = (!disableRange) && typeof document !== 'undefined' && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use ­
- needsShy = document && (function() {
+ needsShy = typeof document !== 'undefined' && (function() {
var testEl = document.createElement('div');
testEl.innerHTML = "<div></div>";
testEl.firstChild.innerHTML = "<script></script>";
return testEl.firstChild.innerHTML === '';
})(),
@@ -25189,20 +25528,34 @@
var handlebarsGet = Ember.Handlebars.get = function(root, path, options) {
var data = options && options.data,
normalizedPath = normalizePath(root, path, data),
value;
-
+ if (Ember.FEATURES.isEnabled("ember-handlebars-caps-lookup")) {
+
+ // If the path starts with a capital letter, look it up on Ember.lookup,
+ // which defaults to the `window` object in browsers.
+ if (Ember.isGlobalPath(path)) {
+ value = Ember.get(Ember.lookup, path);
+ } else {
+
+ // In cases where the path begins with a keyword, change the
+ // root to the value represented by that keyword, and ensure
+ // the path is relative to it.
+ value = Ember.get(normalizedPath.root, normalizedPath.path);
+ }
+
+ } else {
root = normalizedPath.root;
path = normalizedPath.path;
value = Ember.get(root, path);
if (value === undefined && root !== Ember.lookup && Ember.isGlobalPath(path)) {
value = Ember.get(Ember.lookup, path);
}
-
+ }
return value;
};
Ember.Handlebars.resolveParams = function(context, params, options) {
@@ -26080,10 +26433,16 @@
var shouldDisplay = get(this, 'shouldDisplayFunc'),
preserveContext = get(this, 'preserveContext'),
context = get(this, 'previousContext');
+ var contextController;
+
+ if (Ember.FEATURES.isEnabled('with-controller')) {
+ contextController = get(this, 'contextController');
+ }
+
var inverseTemplate = get(this, 'inverseTemplate'),
displayTemplate = get(this, 'displayTemplate');
var result = this.normalizedValue();
this._lastNormalizedValue = result;
@@ -26099,10 +26458,16 @@
set(this, '_context', context);
} else {
// Otherwise, determine if this is a block bind or not.
// If so, pass the specified object to the template
if (displayTemplate) {
+ if (Ember.FEATURES.isEnabled('with-controller')) {
+ if (contextController) {
+ set(contextController, 'content', result);
+ result = contextController;
+ }
+ }
set(this, '_context', result);
} else {
// This is not a bind block, just push the result of the
// expression to the render context and return.
if (result === null || result === undefined) {
@@ -26199,10 +26564,18 @@
previousContext: currentContext,
isEscaped: !options.hash.unescaped,
templateData: options.data
});
+ if (Ember.FEATURES.isEnabled('with-controller')) {
+ if (options.hash.controller) {
+ bindView.set('contextController', this.container.lookupFactory('controller:'+options.hash.controller).create({
+ container: currentContext
+ }));
+ }
+ }
+
view.appendChild(bindView);
observer = function() {
Ember.run.scheduleOnce('render', bindView, 'rerenderIfNeeded');
};
@@ -26273,10 +26646,21 @@
output = handlebarsGet(currentContext, property, options);
data.buffer.push((output === null || typeof output === 'undefined') ? '' : output);
}
}
+function shouldDisplayIfHelperContent(result) {
+ var truthy = result && get(result, 'isTruthy');
+ if (typeof truthy === 'boolean') { return truthy; }
+
+ if (Ember.isArray(result)) {
+ return get(result, 'length') !== 0;
+ } else {
+ return !!result;
+ }
+}
+
/**
@private
'_triageMustache' is used internally select between a binding, helper, or component for
the given context. Until this point, it would be hard to determine if the
@@ -26380,22 +26764,47 @@
@param {Function} fn Context to provide for rendering
@return {String} HTML string
*/
EmberHandlebars.registerHelper('boundIf', function boundIfHelper(property, fn) {
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; }
- if (Ember.isArray(result)) {
- return get(result, 'length') !== 0;
- } else {
- return !!result;
- }
- };
+ return bind.call(context, property, fn, true, shouldDisplayIfHelperContent, shouldDisplayIfHelperContent, ['isTruthy', 'length']);
+});
- return bind.call(context, property, fn, true, func, func, ['isTruthy', 'length']);
+
+/**
+ @private
+
+ Use the `unboundIf` helper to create a conditional that evaluates once.
+
+ ```handlebars
+ {{#unboundIf "content.shouldDisplayTitle"}}
+ {{content.title}}
+ {{/unboundIf}}
+ ```
+
+ @method unboundIf
+ @for Ember.Handlebars.helpers
+ @param {String} property Property to bind
+ @param {Function} fn Context to provide for rendering
+ @return {String} HTML string
+*/
+EmberHandlebars.registerHelper('unboundIf', function unboundIfHelper(property, fn) {
+ var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this,
+ data = fn.data,
+ template = fn.fn,
+ inverse = fn.inverse,
+ normalized, propertyValue, result;
+
+ normalized = normalizePath(context, property, data);
+ propertyValue = handlebarsGet(context, property, fn);
+
+ if (!shouldDisplayIfHelperContent(propertyValue)) {
+ template = inverse;
+ }
+
+ template(context, { data: data });
});
/**
@method with
@for Ember.Handlebars.helpers
@@ -26442,22 +26851,26 @@
});
/**
See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf)
+ and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf)
@method if
@for Ember.Handlebars.helpers
@param {Function} context
@param {Hash} options
@return {String} HTML string
*/
EmberHandlebars.registerHelper('if', function ifHelper(context, options) {
-
- return helpers.boundIf.call(options.contexts[0], context, options);
+ if (options.data.isUnbound) {
+ return helpers.unboundIf.call(options.contexts[0], context, options);
+ } else {
+ return helpers.boundIf.call(options.contexts[0], context, options);
+ }
});
/**
@method unless
@for Ember.Handlebars.helpers
@@ -26472,11 +26885,15 @@
var fn = options.fn, inverse = options.inverse;
options.fn = inverse;
options.inverse = fn;
- return helpers.boundIf.call(options.contexts[0], context, options);
+ if (options.data.isUnbound) {
+ return helpers.unboundIf.call(options.contexts[0], context, options);
+ } else {
+ return helpers.boundIf.call(options.contexts[0], context, options);
+ }
});
/**
`bind-attr` allows you to create a binding between DOM element attributes and
Ember objects. For example:
@@ -27241,11 +27658,11 @@
<div class="ember-view">Hi Mary</div>
<div class="ember-view">Hi Sara</div>
</div>
```
- ### Blockless Use
+ ### Blockless use in a collection
If you provide an `itemViewClass` option that has its own `template` you can
omit the block.
The following template:
@@ -27549,10 +27966,11 @@
@module ember
@submodule ember-handlebars
*/
var get = Ember.get, set = Ember.set;
+var fmt = Ember.String.fmt;
Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
init: function() {
var itemController = get(this, 'itemController');
var binding;
@@ -28540,11 +28958,11 @@
Ember.TextField = Ember.Component.extend(Ember.TextSupport,
/** @scope Ember.TextField.prototype */ {
classNames: ['ember-text-field'],
tagName: "input",
- attributeBindings: ['type', 'value', 'size', 'pattern', 'name'],
+ attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max'],
/**
The `value` attribute of the input element. As the user inputs text, this
property is updated live.
@@ -28571,145 +28989,35 @@
@default null
*/
size: null,
/**
- The `pattern` the pattern attribute of input element.
+ The `pattern` attribute of input element.
@property pattern
@type String
@default null
*/
- pattern: null
-});
+ pattern: null,
-})();
+ /**
+ The `min` attribute of input element used with `type="number"` or `type="range"`.
-
-
-(function() {
-/*
-@module ember
-@submodule ember-handlebars
-*/
-
-var get = Ember.get, set = Ember.set;
-
-/*
- @class Button
- @namespace Ember
- @extends Ember.View
- @uses Ember.TargetActionSupport
- @deprecated
-*/
-Ember.Button = Ember.View.extend(Ember.TargetActionSupport, {
- classNames: ['ember-button'],
- classNameBindings: ['isActive'],
-
- tagName: 'button',
-
- propagateEvents: false,
-
- attributeBindings: ['type', 'disabled', 'href', 'tabindex'],
-
- /*
- @private
-
- Overrides `TargetActionSupport`'s `targetObject` computed
- property to use Handlebars-specific path resolution.
-
- @property targetObject
+ @property min
+ @type String
+ @default null
*/
- targetObject: Ember.computed(function() {
- var target = get(this, 'target'),
- root = get(this, 'context'),
- data = get(this, 'templateData');
+ min: null,
- if (typeof target !== 'string') { return target; }
+ /**
+ The `max` attribute of input element used with `type="number"` or `type="range"`.
- return Ember.Handlebars.get(root, target, { data: data });
- }).property('target'),
-
- // Defaults to 'button' if tagName is 'input' or 'button'
- type: Ember.computed(function(key) {
- var tagName = this.tagName;
- if (tagName === 'input' || tagName === 'button') { return 'button'; }
- }),
-
- disabled: false,
-
- // Allow 'a' tags to act like buttons
- href: Ember.computed(function() {
- return this.tagName === 'a' ? '#' : null;
- }),
-
- mouseDown: function() {
- if (!get(this, 'disabled')) {
- set(this, 'isActive', true);
- this._mouseDown = true;
- this._mouseEntered = true;
- }
- return get(this, 'propagateEvents');
- },
-
- mouseLeave: function() {
- if (this._mouseDown) {
- set(this, 'isActive', false);
- this._mouseEntered = false;
- }
- },
-
- mouseEnter: function() {
- if (this._mouseDown) {
- set(this, 'isActive', true);
- this._mouseEntered = true;
- }
- },
-
- mouseUp: function(event) {
- if (get(this, 'isActive')) {
- // Actually invoke the button's target and action.
- // This method comes from the Ember.TargetActionSupport mixin.
- this.triggerAction();
- set(this, 'isActive', false);
- }
-
- this._mouseDown = false;
- this._mouseEntered = false;
- return get(this, 'propagateEvents');
- },
-
- keyDown: function(event) {
- // Handle space or enter
- if (event.keyCode === 13 || event.keyCode === 32) {
- this.mouseDown();
- }
- },
-
- keyUp: function(event) {
- // Handle space or enter
- if (event.keyCode === 13 || event.keyCode === 32) {
- this.mouseUp();
- }
- },
-
- // TODO: Handle proper touch behavior. Including should make inactive when
- // finger moves more than 20x outside of the edge of the button (vs mouse
- // which goes inactive as soon as mouse goes out of edges.)
-
- touchStart: function(touch) {
- return this.mouseDown(touch);
- },
-
- touchEnd: function(touch) {
- return this.mouseUp(touch);
- },
-
- init: function() {
-
- this._super();
- }
+ @property max
+ @type String
+ @default null
+ */
+ max: null
});
})();
@@ -31992,22 +32300,34 @@
} else {
this.push(options.path, name, null, options.queryParams);
}
- },
+ if (Ember.FEATURES.isEnabled("ember-routing-named-substates")) {
+ // For namespace-preserving nested resource (e.g. resource('foo.bar') within
+ // resource('foo')) we only want to use the last route name segment to determine
+ // the names of the error/loading substates (e.g. 'bar_loading')
+ name = name.split('.').pop();
+ route(this, name + '_loading');
+ route(this, name + '_error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" });
+ }
+ },
push: function(url, name, callback, queryParams) {
var parts = name.split('.');
if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; }
this.matches.push([url, name, callback, queryParams]);
},
route: function(name, options) {
route(this, name, options);
- },
+ if (Ember.FEATURES.isEnabled("ember-routing-named-substates")) {
+ route(this, name + '_loading');
+ route(this, name + '_error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" });
+ }
+ },
generate: function() {
var dslMatches = this.matches;
if (!this.explicitIndex) {
@@ -32016,11 +32336,16 @@
return function(match) {
for (var i=0, l=dslMatches.length; i<l; i++) {
var dslMatch = dslMatches[i];
var matchObj = match(dslMatch[0]).to(dslMatch[1], dslMatch[2]);
- }
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ if(dslMatch[3]) {
+ matchObj.withQueryParams.apply(matchObj, dslMatch[3]);
+ }
+ }
+ }
};
}
};
function route(dsl, name, options) {
@@ -32058,11 +32383,11 @@
@module ember
@submodule ember-routing
*/
/**
-
+
Finds a controller instance.
@for Ember
@method controllerFor
@private
@@ -32070,21 +32395,26 @@
Ember.controllerFor = function(container, controllerName, lookupOptions) {
return container.lookup('controller:' + controllerName, lookupOptions);
};
/**
- Generates a controller automatically if none was provided.
- The type of generated controller depends on the context.
+ Generates a controller factory
+
+ The type of the generated controller factory is derived
+ from the context. If the context is an array an array controller
+ is generated, if an object, an object controller otherwise, a basic
+ controller is generated.
+
You can customize your generated controllers by defining
- `App.ObjectController` and `App.ArrayController`
-
+ `App.ObjectController` or `App.ArrayController`.
+
@for Ember
- @method generateController
+ @method generateControllerFactory
@private
*/
-Ember.generateController = function(container, controllerName, context) {
- var ControllerFactory, fullName, instance, name, factoryName, controllerType;
+Ember.generateControllerFactory = function(container, controllerName, context) {
+ var Factory, fullName, instance, name, factoryName, controllerType;
if (context && Ember.isArray(context)) {
controllerType = 'array';
} else if (context) {
controllerType = 'object';
@@ -32092,23 +32422,41 @@
controllerType = 'basic';
}
factoryName = 'controller:' + controllerType;
- ControllerFactory = container.lookupFactory(factoryName).extend({
+ Factory = container.lookupFactory(factoryName).extend({
isGenerated: true,
toString: function() {
return "(generated " + controllerName + " controller)";
}
});
fullName = 'controller:' + controllerName;
- container.register(fullName, ControllerFactory);
+ container.register(fullName, Factory);
- instance = container.lookup(fullName);
+ return Factory;
+};
+/**
+ Generates and instantiates a controller.
+
+ The type of the generated controller factory is derived
+ from the context. If the context is an array an array controller
+ is generated, if an object, an object controller otherwise, a basic
+ controller is generated.
+
+ @for Ember
+ @method generateController
+ @private
+*/
+Ember.generateController = function(container, controllerName, context) {
+ Ember.generateControllerFactory(container, controllerName, context);
+ var fullName = 'controller:' + controllerName;
+ var instance = container.lookup(fullName);
+
if (get(instance, 'namespace.LOG_ACTIVE_GENERATION')) {
Ember.Logger.info("generated -> " + fullName, { fullName: fullName });
}
return instance;
@@ -32242,17 +32590,10 @@
*/
reset: function() {
this.router.reset();
},
- willDestroy: function(){
- var location = get(this, 'location');
- location.destroy();
-
- this._super.apply(this, arguments);
- },
-
_lookupActiveView: function(templateName) {
var active = this._activeViews[templateName];
return active && active[0];
},
@@ -32271,20 +32612,27 @@
view.one('willDestroyElement', this, disconnect);
},
_setupLocation: function() {
var location = get(this, 'location'),
- rootURL = get(this, 'rootURL'),
- options = {};
+ rootURL = get(this, 'rootURL');
- if (typeof rootURL === 'string') {
- options.rootURL = rootURL;
+ if ('string' === typeof location && this.container) {
+ var resolvedLocation = this.container.lookup('location:' + location);
+
+ if ('undefined' !== typeof resolvedLocation) {
+ location = set(this, 'location', resolvedLocation);
+ } else {
+ // Allow for deprecated registration of custom location API's
+ var options = {implementation: location};
+
+ location = set(this, 'location', Ember.Location.create(options));
+ }
}
- if ('string' === typeof location) {
- options.implementation = location;
- location = set(this, 'location', Ember.Location.create(options));
+ if (typeof rootURL === 'string') {
+ location.rootURL = rootURL;
}
// ensure that initState is called AFTER the rootURL is set on
// the location instance
if (typeof location.initState === 'function') { location.initState(); }
@@ -32353,11 +32701,14 @@
args[0] = args[0] || '/';
var passedName = args[0], name, self = this,
isQueryParamsOnly = false;
-
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ isQueryParamsOnly = (args.length === 1 && args[0].hasOwnProperty('queryParams'));
+ }
+
if (!isQueryParamsOnly && passedName.charAt(0) === '/') {
name = passedName;
} else if (!isQueryParamsOnly) {
if (!this.router.hasRoute(passedName)) {
name = args[0] = passedName + '.index';
@@ -32502,11 +32853,18 @@
var router = parentRoute.router,
childName,
targetChildRouteName = originatingChildRoute.routeName.split('.').pop(),
namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.';
-
+ if (Ember.FEATURES.isEnabled("ember-routing-named-substates")) {
+ // First, try a named loading state, e.g. 'foo_loading'
+ childName = namespace + targetChildRouteName + '_' + name;
+ if (routeHasBeenDefined(router, childName)) {
+ return childName;
+ }
+ }
+
// Second, try general loading state, e.g. 'loading'
childName = namespace + name;
if (routeHasBeenDefined(router, childName)) {
return childName;
}
@@ -33115,11 +33473,14 @@
// referenced in action handlers
this.controller = controller;
var args = [controller, context];
-
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ args.push(queryParams);
+ }
+
if (this.setupControllers) {
this.setupControllers(controller, context);
} else {
this.setupController.apply(this, args);
@@ -34146,12 +34507,19 @@
// Map desired event name to invoke function
var eventName = get(this, 'eventName'), i;
this.on(eventName, this, this._invoke);
- },
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ var queryParams = get(this, '_potentialQueryParams') || [];
+ for(i=0; i < queryParams.length; i++) {
+ this.registerObserver(this, queryParams[i], this, this._queryParamsChanged);
+ }
+ }
+ },
+
/**
@private
This method is invoked by observers installed during `init` that fire
whenever the params change
@@ -34328,11 +34696,19 @@
var parameters = this.parameters,
options = parameters.options,
types = options.types,
data = options.data;
-
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ if (parameters.params.length === 0) {
+ var appController = this.container.lookup('controller:application');
+ return [get(appController, 'currentRouteName')];
+ } else {
+ return resolveParams(parameters.context, parameters.params, { types: types, data: data });
+ }
+ }
+
// Original implementation if query params not enabled
return resolveParams(parameters.context, parameters.params, { types: types, data: data });
}).property(),
/**
@@ -34360,11 +34736,16 @@
// If contexts aren't present, consider the linkView unloaded.
return;
}
}
-
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ var queryParams = get(this, 'queryParams');
+
+ if (queryParams || queryParams === false) { resolvedParams.push({queryParams: queryParams}); }
+ }
+
return resolvedParams;
}).property('resolvedParams', 'queryParams', 'router.url'),
_potentialQueryParams: Ember.computed(function () {
@@ -34924,67 +35305,82 @@
@param {Object?} contextString
@param {Hash} options
@return {String} HTML string
*/
Ember.Handlebars.registerHelper('render', function renderHelper(name, contextString, options) {
+ var length = arguments.length;
- var contextProvided = arguments.length === 3,
+ var contextProvided = length === 3,
container, router, controller, view, context, lookupOptions;
- if (arguments.length === 2) {
+ container = (options || contextString).data.keywords.controller.container;
+ router = container.lookup('router:main');
+
+ if (length === 2) {
+ // use the singleton controller
options = contextString;
contextString = undefined;
- }
- if (typeof contextString === 'string') {
+ } else if (length === 3) {
+ // create a new controller
context = Ember.Handlebars.get(options.contexts[1], contextString, options);
- lookupOptions = { singleton: false };
+ } else {
+ throw Ember.Error("You must pass a templateName to render");
}
+ // # legacy namespace
name = name.replace(/\//g, '.');
- container = options.data.keywords.controller.container;
- router = container.lookup('router:main');
+ // \ legacy slash as namespace support
view = container.lookup('view:' + name) || container.lookup('view:default');
- var controllerName = options.hash.controller;
+ // provide controller override
+ var controllerName = options.hash.controller || name;
+ var controllerFullName = 'controller:' + controllerName;
- // Look up the controller by name, if provided.
- if (controllerName) {
- controller = container.lookup('controller:' + controllerName, lookupOptions);
+ if (options.hash.controller) {
- } else {
- controller = container.lookup('controller:' + name, lookupOptions) ||
- Ember.generateController(container, name, context);
}
- if (controller && contextProvided) {
- controller.set('model', context);
+ var target = options.data.keywords.controller;
+
+ // choose name
+ if (length > 2) {
+ var factory = container.lookupFactory(controllerFullName) ||
+ Ember.generateControllerFactory(container, controllerName, context);
+
+ controller = factory.create({
+ model: context,
+ target: target
+ });
+
+ } else {
+ controller = container.lookup(controllerFullName) ||
+ Ember.generateController(container, controllerName);
+
+ controller.set('target', target);
}
var root = options.contexts[1];
if (root) {
view.registerObserver(root, contextString, function() {
controller.set('model', Ember.Handlebars.get(root, contextString, options));
});
}
- controller.set('target', options.data.keywords.controller);
-
options.hash.viewName = Ember.String.camelize(name);
options.hash.template = container.lookup('template:' + name);
options.hash.controller = controller;
if (router && !context) {
router._connectActiveView(name, view);
}
Ember.Handlebars.helpers.view.call(this, view, options);
});
-
});
})();
@@ -35675,10 +36071,12 @@
@method registerImplementation
@param {String} name
@param {Object} implementation of the `location` API
*/
registerImplementation: function(name, implementation) {
+
+
this.implementations[name] = implementation;
},
implementations: {}
};
@@ -35704,10 +36102,11 @@
@class NoneLocation
@namespace Ember
@extends Ember.Object
*/
Ember.NoneLocation = Ember.Object.extend({
+ implementation: 'none',
path: '',
/**
@private
@@ -35779,12 +36178,10 @@
// helpers.
return url;
}
});
-Ember.Location.registerImplementation('none', Ember.NoneLocation);
-
})();
(function() {
@@ -35803,10 +36200,11 @@
@class HashLocation
@namespace Ember
@extends Ember.Object
*/
Ember.HashLocation = Ember.Object.extend({
+ implementation: 'hash',
init: function() {
set(this, 'location', get(this, 'location') || window.location);
},
@@ -35816,11 +36214,23 @@
Returns the current `location.hash`, minus the '#' at the front.
@method getURL
*/
getURL: function() {
- // Default implementation without feature flag enabled
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ // location.hash is not used because it is inconsistently
+ // URL-decoded between browsers.
+ var href = get(this, 'location').href,
+ hashIndex = href.indexOf('#');
+
+ if ( hashIndex === -1 ) {
+ return "";
+ } else {
+ return href.substr(hashIndex + 1);
+ }
+ }
+ // Default implementation without feature flag enabled
return get(this, 'location').hash.substr(1);
},
/**
@private
@@ -35904,12 +36314,10 @@
Ember.$(window).off('hashchange.ember-location-'+guid);
}
});
-Ember.Location.registerImplementation('hash', Ember.HashLocation);
-
})();
(function() {
@@ -35929,10 +36337,11 @@
@class HistoryLocation
@namespace Ember
@extends Ember.Object
*/
Ember.HistoryLocation = Ember.Object.extend({
+ implementation: 'history',
init: function() {
set(this, 'location', get(this, 'location') || window.location);
},
@@ -35970,11 +36379,15 @@
path = location.pathname;
rootURL = rootURL.replace(/\/$/, '');
var url = path.replace(rootURL, '');
-
+ if (Ember.FEATURES.isEnabled("query-params")) {
+ var search = location.search || '';
+ url += search;
+ }
+
return url;
},
/**
@private
@@ -36123,12 +36536,10 @@
Ember.$(window).off('popstate.ember-location-'+guid);
}
});
-Ember.Location.registerImplementation('history', Ember.HistoryLocation);
-
})();
(function() {
@@ -36975,13 +37386,19 @@
Example:
```javascript
App.inject(<full_name or type>, <property name>, <full_name>)
- App.inject('model:user', 'email', 'model:email')
- App.inject('model', 'source', 'source:main')
+ App.inject('controller:application', 'email', 'model:email')
+ App.inject('controller', 'source', 'source:main')
```
+ Please note that injections on models are currently disabled.
+ This was done because ember-data was not ready for fully a container aware ecosystem.
+
+ You can enable injections on models by setting `Ember.MODEL_FACTORY_INJECTIONS` flag to `true`
+ If model factory injections are enabled, models should not be
+ accessed globally (only through `container.lookupFactory('model:modelName'))`);
@method inject
@param factoryNameOrType {String}
@param property {String}
@param injectionName {String}
@@ -37310,9 +37727,13 @@
container.register('route:basic', Ember.Route, { instantiate: false });
container.register('event_dispatcher:main', Ember.EventDispatcher);
container.register('router:main', Ember.Router);
container.injection('router:main', 'namespace', 'application:main');
+
+ container.register('location:hash', Ember.HashLocation);
+ container.register('location:history', Ember.HistoryLocation);
+ container.register('location:none', Ember.NoneLocation);
container.injection('controller', 'target', 'router:main');
container.injection('controller', 'namespace', 'application:main');
container.injection('route', 'router', 'router:main');