dist/ember.js in ember-source-1.0.0.rc3 vs dist/ember.js in ember-source-1.0.0.rc3.1

- old
+ new

@@ -1,7 +1,7 @@ -// Version: v1.0.0-rc.3 -// Last commit: 96e97b5 (2013-04-21 02:07:10 -0400) +// Version: v1.0.0-rc.1-536-gd47406c +// Last commit: d47406c (2013-04-25 17:21:02 -0700) (function() { /*global __fail__*/ @@ -149,12 +149,12 @@ }; }; })(); -// Version: v1.0.0-rc.3 -// Last commit: 96e97b5 (2013-04-21 02:07:10 -0400) +// Version: v1.0.0-rc.1-536-gd47406c +// Last commit: d47406c (2013-04-25 17:21:02 -0700) (function() { var define, requireModule; @@ -465,11 +465,11 @@ @for Ember @param {Object} obj Value to test @return {Boolean} */ Ember.isEmpty = function(obj) { - return obj === null || obj === undefined || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0); + return Ember.isNone(obj) || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0); }; Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.", Ember.isEmpty) ; })(); @@ -498,10 +498,17 @@ @method create @for Ember */ Ember.create = Object.create; +// IE8 has Object.create but it couldn't treat property descripters. +if (Ember.create) { + if (Ember.create({a: 1}, {a: {value: 2}}).a !== 2) { + Ember.create = null; + } +} + // STUB_OBJECT_CREATE allows us to override other libraries that stub // Object.create different than we would prefer if (!Ember.create || Ember.ENV.STUB_OBJECT_CREATE) { var K = function() {}; @@ -1990,17 +1997,16 @@ if (!keyName && 'string'===typeof obj) { keyName = obj; obj = null; } - if (!obj || keyName.indexOf('.') !== -1) { - Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined); + Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined); + + if (obj === null || keyName.indexOf('.') !== -1) { return getPath(obj, keyName); } - Ember.assert("You need to provide an object and key to `get`.", !!obj && keyName); - var meta = obj[META_KEY], desc = meta && meta.descs[keyName], ret; if (desc) { return desc.get(obj, keyName); } else { if (MANDATORY_SETTER && meta && meta.watching[keyName] > 0) { @@ -2068,11 +2074,11 @@ tuple.length = 0; } parts = path.split("."); len = parts.length; - for (idx=0; root && idx<len; idx++) { + for (idx=0; root !== undefined && root !== null && idx<len; idx++) { root = get(root, parts[idx], true); if (root && root.isDestroyed) { return undefined; } } return root; }; @@ -2114,11 +2120,13 @@ @module ember-metal */ var o_create = Ember.create, metaFor = Ember.meta, - META_KEY = Ember.META_KEY; + META_KEY = Ember.META_KEY, + /* listener flags */ + ONCE = 1, SUSPENDED = 2, IMMEDIATE = 4; /* The event system uses a series of nested hashes to store listeners on an object. When a listener is registered, or when an event arrives, these hashes are consulted to determine which target and action pair to invoke. @@ -2127,11 +2135,11 @@ // Object's meta hash { listeners: { // variable name: `listenerSet` "foo:changed": [ // variable name: `actions` - [target, method, onceFlag, suspendedFlag] + [target, method, flags] ] } } */ @@ -2173,16 +2181,15 @@ if (!actions) { return; } for (var i = actions.length - 1; i >= 0; i--) { var target = actions[i][0], method = actions[i][1], - once = actions[i][2], - suspended = actions[i][3], + flags = actions[i][2], actionIndex = indexOf(otherActions, target, method); if (actionIndex === -1) { - otherActions.push([target, method, once, suspended]); + otherActions.push([target, method, flags]); } } } function actionsDiff(obj, eventName, otherActions) { @@ -2192,18 +2199,17 @@ if (!actions) { return; } for (var i = actions.length - 1; i >= 0; i--) { var target = actions[i][0], method = actions[i][1], - once = actions[i][2], - suspended = actions[i][3], + flags = actions[i][2], actionIndex = indexOf(otherActions, target, method); if (actionIndex !== -1) { continue; } - otherActions.push([target, method, once, suspended]); - diffActions.push([target, method, once, suspended]); + otherActions.push([target, method, flags]); + diffActions.push([target, method, flags]); } return diffActions; } @@ -2225,15 +2231,18 @@ method = target; target = null; } var actions = actionsFor(obj, eventName), - actionIndex = indexOf(actions, target, method); + actionIndex = indexOf(actions, target, method), + flags = 0; + if (once) flags |= ONCE; + if (actionIndex !== -1) { return; } - actions.push([target, method, once, undefined]); + actions.push([target, method, flags]); if ('function' === typeof obj.didAddListener) { obj.didAddListener(eventName, target, method); } } @@ -2256,11 +2265,11 @@ if (!method && 'function' === typeof target) { method = target; target = null; } - function _removeListener(target, method, once) { + function _removeListener(target, method) { var actions = actionsFor(obj, eventName), actionIndex = indexOf(actions, target, method); // action doesn't exist, give up silently if (actionIndex === -1) { return; } @@ -2313,16 +2322,16 @@ actionIndex = indexOf(actions, target, method), action; if (actionIndex !== -1) { action = actions[actionIndex].slice(); // copy it, otherwise we're modifying a shared object - action[3] = true; // mark the action as suspended + action[2] |= SUSPENDED; // mark the action as suspended actions[actionIndex] = action; // replace the shared object with our copy } function tryable() { return callback.call(target); } - function finalizer() { if (action) { action[3] = undefined; } } + function finalizer() { if (action) { action[2] &= ~SUSPENDED; } } return Ember.tryFinally(tryable, finalizer); } /** @@ -2357,21 +2366,21 @@ actions = actionsFor(obj, eventName); var actionIndex = indexOf(actions, target, method); if (actionIndex !== -1) { action = actions[actionIndex].slice(); - action[3] = true; + action[2] |= SUSPENDED; actions[actionIndex] = action; suspendedActions.push(action); } } function tryable() { return callback.call(target); } function finalizer() { for (i = 0, l = suspendedActions.length; i < l; i++) { - suspendedActions[i][3] = undefined; + suspendedActions[i][2] &= ~SUSPENDED; } } return Ember.tryFinally(tryable, finalizer); } @@ -2417,17 +2426,15 @@ } if (!actions) { return; } for (var i = actions.length - 1; i >= 0; i--) { // looping in reverse for once listeners - if (!actions[i] || actions[i][3] === true) { continue; } - - var target = actions[i][0], - method = actions[i][1], - once = actions[i][2]; - - if (once) { removeListener(obj, eventName, target, method); } + var action = actions[i]; + if (!action) { continue; } + var target = action[0], method = action[1], flags = action[2]; + if (flags & SUSPENDED) { continue; } + if (flags & ONCE) { removeListener(obj, eventName, target, method); } if (!target) { target = obj; } if ('string' === typeof method) { method = target[method]; } if (params) { method.apply(target, params); } else { @@ -2503,11 +2510,11 @@ { sender: obj, keyName: keyName, eventName: eventName, listeners: [ - [target, method, onceFlag, suspendedFlag] + [target, method, flags] ] }, ... ] */ @@ -4862,31 +4869,48 @@ // TIMERS // var timers = {}; // active timers... +function sortByExpires(timerA, timerB) { + var a = timerA.expires, + b = timerB.expires; + + if (a > b) { return 1; } + if (a < b) { return -1; } + return 0; +} + var scheduledLater, scheduledLaterExpires; function invokeLaterTimers() { scheduledLater = null; run(function() { var now = (+ new Date()), earliest = -1; + var timersToBeInvoked = []; for (var key in timers) { if (!timers.hasOwnProperty(key)) { continue; } var timer = timers[key]; if (timer && timer.expires) { if (now >= timer.expires) { delete timers[key]; - invoke(timer.target, timer.method, timer.args, 2); + timersToBeInvoked.push(timer); } else { if (earliest < 0 || (timer.expires < earliest)) { earliest = timer.expires; } } } } + forEach.call(timersToBeInvoked.sort(sortByExpires), function(timer) { + invoke(timer.target, timer.method, timer.args, 2); + }); + // schedule next timeout to fire when the earliest timer expires if (earliest > 0) { - scheduledLater = setTimeout(invokeLaterTimers, earliest - now); + // To allow overwrite `setTimeout` as stub from test code. + // The assignment to `window.setTimeout` doesn't equal to `setTimeout` in older IE. + // So `window` is required. + scheduledLater = window.setTimeout(invokeLaterTimers, earliest - now); scheduledLaterExpires = earliest; } }); } @@ -6306,30 +6330,73 @@ */ })(); (function() { -define("rsvp", - [], - function() { +define("rsvp/all", + ["rsvp/defer","exports"], + function(__dependency1__, __exports__) { "use strict"; + var defer = __dependency1__.defer; + + function all(promises) { + var results = [], deferred = defer(), remaining = promises.length; + + if (remaining === 0) { + deferred.resolve([]); + } + + var resolver = function(index) { + return function(value) { + resolveAll(index, value); + }; + }; + + var resolveAll = function(index, value) { + results[index] = value; + if (--remaining === 0) { + deferred.resolve(results); + } + }; + + var rejectAll = function(error) { + deferred.reject(error); + }; + + for (var i = 0; i < promises.length; i++) { + if (promises[i] && typeof promises[i].then === 'function') { + promises[i].then(resolver(i), rejectAll); + } else { + resolveAll(i, promises[i]); + } + } + return deferred.promise; + } + + __exports__.all = all; + }); + +define("rsvp/async", + ["exports"], + function(__exports__) { + "use strict"; var browserGlobal = (typeof window !== 'undefined') ? window : {}; - var MutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; - var RSVP, async; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + var async; if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { async = function(callback, binding) { process.nextTick(function() { callback.call(binding); }); }; - } else if (MutationObserver) { + } else if (BrowserMutationObserver) { var queue = []; - var observer = new MutationObserver(function() { + var observer = new BrowserMutationObserver(function() { var toProcess = queue.slice(); queue = []; toProcess.forEach(function(tuple) { var callback = tuple[0], binding = tuple[1]; @@ -6356,10 +6423,51 @@ callback.call(binding); }, 1); }; } + + __exports__.async = async; + }); + +define("rsvp/config", + ["rsvp/async","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var async = __dependency1__.async; + + var config = {}; + config.async = async; + + __exports__.config = config; + }); + +define("rsvp/defer", + ["rsvp/promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; + + function defer() { + var deferred = {}; + + var promise = new Promise(function(resolve, reject) { + deferred.resolve = resolve; + deferred.reject = reject; + }); + + deferred.promise = promise; + return deferred; + } + + __exports__.defer = defer; + }); + +define("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; var Event = function(type, options) { this.type = type; for (var option in options) { if (!options.hasOwnProperty(option)) { continue; } @@ -6450,24 +6558,165 @@ } } } }; - var Promise = function() { + + __exports__.EventTarget = EventTarget; + }); + +define("rsvp/hash", + ["rsvp/defer","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var defer = __dependency1__.defer; + + function size(object) { + var size = 0; + + for (var prop in object) { + size++; + } + + return size; + } + + function hash(promises) { + var results = {}, deferred = defer(), remaining = size(promises); + + if (remaining === 0) { + deferred.resolve({}); + } + + var resolver = function(prop) { + return function(value) { + resolveAll(prop, value); + }; + }; + + var resolveAll = function(prop, value) { + results[prop] = value; + if (--remaining === 0) { + deferred.resolve(results); + } + }; + + var rejectAll = function(error) { + deferred.reject(error); + }; + + for (var prop in promises) { + if (promises[prop] && typeof promises[prop].then === 'function') { + promises[prop].then(resolver(prop), rejectAll); + } else { + resolveAll(prop, promises[prop]); + } + } + + return deferred.promise; + } + + __exports__.hash = hash; + }); + +define("rsvp/node", + ["rsvp/promise","rsvp/all","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; + var all = __dependency2__.all; + + function makeNodeCallbackFor(resolve, reject) { + return function (error, value) { + if (error) { + reject(error); + } else if (arguments.length > 2) { + resolve(Array.prototype.slice.call(arguments, 1)); + } else { + resolve(value); + } + }; + } + + function denodeify(nodeFunc) { + return function() { + var nodeArgs = Array.prototype.slice.call(arguments), resolve, reject; + + var promise = new Promise(function(nodeResolve, nodeReject) { + resolve = nodeResolve; + reject = nodeReject; + }); + + all(nodeArgs).then(function(nodeArgs) { + nodeArgs.push(makeNodeCallbackFor(resolve, reject)); + + try { + nodeFunc.apply(this, nodeArgs); + } catch(e) { + reject(e); + } + }); + + return promise; + }; + } + + __exports__.denodeify = denodeify; + }); + +define("rsvp/promise", + ["rsvp/config","rsvp/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var EventTarget = __dependency2__.EventTarget; + + function objectOrFunction(x) { + return isFunction(x) || (typeof x === "object" && x !== null); + } + + function isFunction(x){ + return typeof x === "function"; + } + + var Promise = function(resolver) { + var promise = this, + resolved = false; + + if (typeof resolver !== 'function') { + throw new TypeError('You must pass a resolver function as the sole argument to the promise constructor'); + } + + if (!(promise instanceof Promise)) { + return new Promise(resolver); + } + + var resolvePromise = function(value) { + if (resolved) { return; } + resolved = true; + resolve(promise, value); + }; + + var rejectPromise = function(value) { + if (resolved) { return; } + resolved = true; + reject(promise, value); + }; + this.on('promise:resolved', function(event) { this.trigger('success', { detail: event.detail }); }, this); this.on('promise:failed', function(event) { this.trigger('error', { detail: event.detail }); }, this); + + resolver(resolvePromise, rejectPromise); }; - var noop = function() {}; - var invokeCallback = function(type, promise, callback, event) { - var hasCallback = typeof callback === 'function', + var hasCallback = isFunction(callback), value, error, succeeded, failed; if (hasCallback) { try { value = callback(event.detail); @@ -6479,38 +6728,38 @@ } else { value = event.detail; succeeded = true; } - if (value && typeof value.then === 'function') { - value.then(function(value) { - promise.resolve(value); - }, function(error) { - promise.reject(error); - }); + if (handleThenable(promise, value)) { + return; } else if (hasCallback && succeeded) { - promise.resolve(value); + resolve(promise, value); } else if (failed) { - promise.reject(error); - } else { - promise[type](value); + reject(promise, error); + } else if (type === 'resolve') { + resolve(promise, value); + } else if (type === 'reject') { + reject(promise, value); } }; Promise.prototype = { + constructor: Promise, + then: function(done, fail) { - var thenPromise = new Promise(); + var thenPromise = new Promise(function() {}); - if (this.isResolved) { - RSVP.async(function() { - invokeCallback('resolve', thenPromise, done, { detail: this.resolvedValue }); + if (this.isFulfilled) { + config.async(function() { + invokeCallback('resolve', thenPromise, done, { detail: this.fulfillmentValue }); }, this); } if (this.isRejected) { - RSVP.async(function() { - invokeCallback('reject', thenPromise, fail, { detail: this.rejectedValue }); + config.async(function() { + invokeCallback('reject', thenPromise, fail, { detail: this.rejectedReason }); }, this); } this.on('promise:resolved', function(event) { invokeCallback('resolve', thenPromise, done, event); @@ -6519,79 +6768,142 @@ this.on('promise:failed', function(event) { invokeCallback('reject', thenPromise, fail, event); }); return thenPromise; - }, + } + }; - resolve: function(value) { - resolve(this, value); + EventTarget.mixin(Promise.prototype); - this.resolve = noop; - this.reject = noop; - }, + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (!handleThenable(promise, value)) { + fulfill(promise, value); + } + } - reject: function(value) { - reject(this, value); + function handleThenable(promise, value) { + var then = null; - this.resolve = noop; - this.reject = noop; + if (objectOrFunction(value)) { + try { + then = value.then; + } catch(e) { + reject(promise, e); + return true; + } + + if (isFunction(then)) { + try { + then.call(value, function(val) { + if (value !== val) { + resolve(promise, val); + } else { + fulfill(promise, val); + } + }, function(val) { + reject(promise, val); + }); + } catch (e) { + reject(promise, e); + } + return true; + } } - }; - function resolve(promise, value) { - RSVP.async(function() { + return false; + } + + function fulfill(promise, value) { + config.async(function() { promise.trigger('promise:resolved', { detail: value }); - promise.isResolved = true; - promise.resolvedValue = value; + promise.isFulfilled = true; + promise.fulfillmentValue = value; }); } function reject(promise, value) { - RSVP.async(function() { + config.async(function() { promise.trigger('promise:failed', { detail: value }); promise.isRejected = true; - promise.rejectedValue = value; + promise.rejectedReason = value; }); } - function all(promises) { - var i, results = []; - var allPromise = new Promise(); - var remaining = promises.length; - if (remaining === 0) { - allPromise.resolve([]); - } + __exports__.Promise = Promise; + }); - var resolver = function(index) { - return function(value) { - resolve(index, value); - }; - }; +define("rsvp/resolve", + ["rsvp/promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; - var resolve = function(index, value) { - results[index] = value; - if (--remaining === 0) { - allPromise.resolve(results); + + function objectOrFunction(x) { + return typeof x === "function" || (typeof x === "object" && x !== null); + } + + function resolve(thenable){ + var promise = new Promise(function(resolve, reject){ + var then; + + try { + if ( objectOrFunction(thenable) ) { + then = thenable.then; + + if (typeof then === "function") { + then.call(thenable, resolve, reject); + } else { + resolve(thenable); + } + + } else { + resolve(thenable); + } + + } catch(error) { + reject(error); } - }; + }); - var reject = function(error) { - allPromise.reject(error); - }; + return promise; + } - for (i = 0; i < remaining; i++) { - promises[i].then(resolver(i), reject); - } - return allPromise; + + __exports__.resolve = resolve; + }); + +define("rsvp", + ["rsvp/events","rsvp/promise","rsvp/node","rsvp/all","rsvp/hash","rsvp/defer","rsvp/config","rsvp/resolve","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var EventTarget = __dependency1__.EventTarget; + var Promise = __dependency2__.Promise; + var denodeify = __dependency3__.denodeify; + var all = __dependency4__.all; + var hash = __dependency5__.hash; + var defer = __dependency6__.defer; + var config = __dependency7__.config; + var resolve = __dependency8__.resolve; + + function configure(name, value) { + config[name] = value; } - EventTarget.mixin(Promise.prototype); - RSVP = { async: async, Promise: Promise, Event: Event, EventTarget: EventTarget, all: all, raiseOnUncaughtExceptions: true }; - return RSVP; + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.hash = hash; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.resolve = resolve; }); })(); (function() { @@ -8573,14 +8885,12 @@ // .......................................................... // HELPERS // -var get = Ember.get, set = Ember.set, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor; +var get = Ember.get, set = Ember.set, isNone = Ember.isNone, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor; -function none(obj) { return obj===null || obj===undefined; } - // .......................................................... // ARRAY // /** This module implements Observer-friendly Array-like behavior. This mixin is @@ -8725,12 +9035,12 @@ @return {Array} New array with specified slice */ slice: function(beginIndex, endIndex) { var ret = Ember.A([]); var length = get(this, 'length') ; - if (none(beginIndex)) beginIndex = 0 ; - if (none(endIndex) || (endIndex > length)) endIndex = length ; + if (isNone(beginIndex)) beginIndex = 0 ; + if (isNone(endIndex) || (endIndex > length)) endIndex = length ; if (beginIndex < 0) beginIndex = length + beginIndex; if (endIndex < 0) endIndex = length + endIndex; while(beginIndex < endIndex) { @@ -8886,11 +9196,11 @@ @method arrayContentWillChange @param {Number} startIdx The starting index in the array that will change. @param {Number} removeAmt The number of items that will be removed. If you pass `null` assumes 0 - @param {Number} addAmt The number of items that will be added If you + @param {Number} addAmt The number of items that will be added. If you pass `null` assumes 0. @return {Ember.Array} receiver */ arrayContentWillChange: function(startIdx, removeAmt, addAmt) { @@ -8920,10 +9230,24 @@ this.enumerableContentWillChange(removing, addAmt); return this; }, + /** + If you are implementing an object that supports `Ember.Array`, call this + method just after the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentDidChange + @param {Number} startIdx The starting index in the array that did change. + @param {Number} removeAmt The number of items that were removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that were added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ arrayContentDidChange: function(startIdx, removeAmt, addAmt) { // if no args are passed assume everything changes if (startIdx===undefined) { startIdx = 0; @@ -10078,11 +10402,11 @@ @param {String} keyName The name of the property to increment @param {Object} increment The amount to increment by. Defaults to 1 @return {Object} The new property value */ incrementProperty: function(keyName, increment) { - if (!increment) { increment = 1; } + if (Ember.isNone(increment)) { increment = 1; } set(this, keyName, (get(this, keyName) || 0)+increment); return get(this, keyName); }, /** @@ -10097,11 +10421,11 @@ @param {String} keyName The name of the property to decrement @param {Object} increment The amount to decrement by. Defaults to 1 @return {Object} The new property value */ decrementProperty: function(keyName, increment) { - if (!increment) { increment = 1; } + if (Ember.isNone(increment)) { increment = 1; } set(this, keyName, (get(this, keyName) || 0)-increment); return get(this, keyName); }, /** @@ -10434,13 +10758,13 @@ (function() { var RSVP = requireModule("rsvp"); -RSVP.async = function(callback, binding) { +RSVP.configure('async', function(callback, binding) { Ember.run.schedule('actions', binding, callback); -}; +}); /** @module ember @submodule ember-runtime */ @@ -10458,35 +10782,57 @@ @method then @param {Function} doneCallback a callback function to be called when done @param {Function} failCallback a callback function to be called when failed */ - then: function(doneCallback, failCallback) { - var promise = get(this, 'promise'); - return promise.then.apply(promise, arguments); + then: function(resolve, reject) { + var deferred, promise, entity; + + entity = this; + deferred = get(this, '_deferred'); + promise = deferred.promise; + + return promise.then(function(fulfillment) { + if (fulfillment === promise) { + return resolve(entity); + } else { + return resolve(fulfillment); + } + }, function(reason) { + return reject(reason); + }); }, /** Resolve a Deferred object and call any `doneCallbacks` with the given args. @method resolve */ resolve: function(value) { - get(this, 'promise').resolve(value); + var deferred, promise; + + deferred = get(this, '_deferred'); + promise = deferred.promise; + + if (value === this){ + deferred.resolve(promise); + } else { + deferred.resolve(value); + } }, /** Reject a Deferred object and call any `failCallbacks` with the given args. @method reject */ reject: function(value) { - get(this, 'promise').reject(value); + get(this, '_deferred').reject(value); }, - promise: Ember.computed(function() { - return new RSVP.Promise(); + _deferred: Ember.computed(function() { + return new RSVP.defer(); }) }); })(); @@ -12131,11 +12477,11 @@ /** @module ember @submodule ember-runtime */ -var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, none = Ember.isNone, fmt = Ember.String.fmt; +var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, isNone = Ember.isNone, fmt = Ember.String.fmt; /** An unordered collection of objects. A Set works a bit like an array except that its items are not ordered. You @@ -12489,11 +12835,11 @@ }), // implements Ember.MutableEnumerable addObject: function(obj) { if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR); - if (none(obj)) return this; // nothing to do + if (isNone(obj)) return this; // nothing to do var guid = guidFor(obj), idx = this[guid], len = get(this, 'length'), added ; @@ -12517,11 +12863,11 @@ }, // implements Ember.MutableEnumerable removeObject: function(obj) { if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR); - if (none(obj)) return this; // nothing to do + if (isNone(obj)) return this; // nothing to do var guid = guidFor(obj), idx = this[guid], len = get(this, 'length'), isFirst = idx === 0, @@ -12592,21 +12938,23 @@ Deferred.reopenClass({ promise: function(callback, binding) { var deferred = Deferred.create(); callback.call(binding, deferred); - return get(deferred, 'promise'); + return deferred; } }); Ember.Deferred = Deferred; })(); (function() { +var forEach = Ember.ArrayPolyfills.forEach; + /** @module ember @submodule ember-runtime */ @@ -12635,16 +12983,14 @@ @for Ember @param name {String} name of hook @param object {Object} object to pass to callbacks */ Ember.runLoadHooks = function(name, object) { - var hooks; - loaded[name] = object; - if (hooks = loadHooks[name]) { - loadHooks[name].forEach(function(callback) { + if (loadHooks[name]) { + forEach.call(loadHooks[name], function(callback) { callback(object); }); } }; @@ -13968,11 +14314,11 @@ dispatcher's `root` property. @method setup @param addedEvents {Hash} */ - setup: function(addedEvents) { + setup: function(addedEvents, rootElement) { var event, events = { touchstart : 'touchStart', touchmove : 'touchMove', touchend : 'touchEnd', touchcancel : 'touchCancel', @@ -14001,12 +14347,17 @@ dragend : 'dragEnd' }; Ember.$.extend(events, addedEvents || {}); - var rootElement = Ember.$(get(this, 'rootElement')); + if (!Ember.isNone(rootElement)) { + set(this, 'rootElement', rootElement); + } + + rootElement = Ember.$(get(this, 'rootElement')); + Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application')); Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length); Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length); rootElement.addClass('ember-application'); @@ -14319,11 +14670,11 @@ // create a new buffer relative to the original using the // provided buffer operation (for example, `insertAfter` will // insert a new buffer after the "parent buffer"). var tagName = this.tagName; - if (tagName === null || tagName === undefined) { + if (Ember.isNone(tagName)) { tagName = 'div'; } var buffer = this.buffer = parentBuffer && parentBuffer.begin(tagName) || Ember.RenderBuffer(tagName); this.transitionTo('inBuffer', false); @@ -17269,11 +17620,11 @@ this.forEachChildView(function(view) { view.renderToBuffer(buffer); }); }, - instrumentName: 'render.container', + instrumentName: 'container', /** @private When a child view is removed, destroy its element so that @@ -18374,14 +18725,29 @@ @class Handlebars @namespace Ember */ 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]; + } + } +} + Ember.Handlebars.helper = function(name, value) { if (Ember.View.detect(value)) { - Ember.Handlebars.registerHelper(name, function(name, options) { + Ember.Handlebars.registerHelper(name, function(options) { Ember.assert("You can only pass attributes as parameters to a application-defined helper", arguments.length < 3); + makeBindings(options); return Ember.Handlebars.helpers.view.call(this, value, options); }); } else { Ember.Handlebars.registerBoundHelper.apply(null, arguments); } @@ -19090,11 +19456,11 @@ */ Ember._Metamorph = Ember.Mixin.create({ isVirtual: true, tagName: '', - instrumentName: 'render.metamorph', + instrumentName: 'metamorph', init: function() { this._super(); this.morph = Metamorph(); Ember.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated. You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName); @@ -19279,11 +19645,11 @@ @namespace Ember @extends Ember._MetamorphView @private */ Ember._HandlebarsBoundView = Ember._MetamorphView.extend({ - instrumentName: 'render.boundHandlebars', + instrumentName: 'boundHandlebars', states: states, /** The function used to determine if the `displayTemplate` or `inverseTemplate` should be rendered. This should be a function that takes @@ -22363,10 +22729,19 @@ delete hash[prop]; } } } +/** + * `{{input}}` inserts a new instance of either Ember.TextField or + * Ember.Checkbox, depending on the `type` option passed in. If no `type` + * is supplied it defaults to Ember.TextField. + * + * @method input + * @for Ember.Handlebars.helpers + * @param {Hash} options + */ Ember.Handlebars.registerHelper('input', function(options) { Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); var hash = options.hash, types = options.hashTypes, @@ -22385,10 +22760,18 @@ hash.onEvent = onEvent || 'enter'; return Ember.Handlebars.helpers.view.call(this, Ember.TextField, options); } }); +/** + * `{{textarea}}` inserts a new instance of Ember.TextArea into the template + * passing its options to `Ember.TextArea`'s `create` method. + * + * @method textarea + * @for Ember.Handlebars.helpers + * @param {Hash} options + */ Ember.Handlebars.registerHelper('textarea', function(options) { Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); var hash = options.hash, types = options.hashTypes; @@ -23336,11 +23719,14 @@ `setup` method. */ function failure(router, error) { loaded(router); var handler = router.getHandler('failure'); - if (handler && handler.setup) { handler.setup(error); } + if (handler){ + if (handler.enter) { handler.enter(); } + if (handler.setup) { handler.setup(error); } + } } /** @private */ @@ -24700,10 +25086,70 @@ var ret = [ routeName ]; return ret.concat(resolvedPaths(linkView.parameters)); } /** + @class LinkView + @namespace Ember + @extends Ember.View + **/ + var LinkView = Ember.LinkView = Ember.View.extend({ + tagName: 'a', + namedRoute: null, + currentWhen: null, + title: null, + activeClass: 'active', + replace: false, + attributeBindings: ['href', 'title'], + classNameBindings: 'active', + + // Even though this isn't a virtual view, we want to treat it as if it is + // so that you can access the parent with {{view.prop}} + concreteView: Ember.computed(function() { + return get(this, 'parentView'); + }).property('parentView'), + + active: Ember.computed(function() { + var router = this.get('router'), + params = resolvedPaths(this.parameters), + currentWithIndex = this.currentWhen + '.index', + isActive = router.isActive.apply(router, [this.currentWhen].concat(params)) || + router.isActive.apply(router, [currentWithIndex].concat(params)); + + if (isActive) { return get(this, 'activeClass'); } + }).property('namedRoute', 'router.url'), + + router: Ember.computed(function() { + return this.get('controller').container.lookup('router:main'); + }), + + click: function(event) { + if (!isSimpleClick(event)) { return true; } + + event.preventDefault(); + if (this.bubbles === false) { event.stopPropagation(); } + + var router = this.get('router'); + + if (this.get('replace')) { + router.replaceWith.apply(router, args(this, router)); + } else { + router.transitionTo.apply(router, args(this, router)); + } + }, + + href: Ember.computed(function() { + if (this.get('tagName') !== 'a') { return false; } + + var router = this.get('router'); + return router.generate.apply(router, args(this, router)); + }) + }); + + LinkView.toString = function() { return "LinkView"; }; + + /** The `{{linkTo}}` helper renders a link to the supplied `routeName` passing an optionally supplied model to the route as its `model` context of the route. The block for `{{linkTo}}` becomes the innerHTML of the rendered element: @@ -24718,16 +25164,16 @@ <a href="/hamster-photos"> Great Hamster Photos </a> ``` - ## Supplying a tagName - By default `{{linkTo}} renders an `<a>` element. This can + ### Supplying a tagName + By default `{{linkTo}}` renders an `<a>` element. This can be overridden for a single use of `{{linkTo}}` by supplying a `tagName` option: - ``` + ```handlebars {{#linkTo photoGallery tagName="li"}} Great Hamster Photos {{/linkTo}} ``` @@ -24738,25 +25184,25 @@ ``` To override this option for your entire application, see "Overriding Application-wide Defaults". - ## Handling `href` + ### Handling `href` `{{linkTo}}` will use your application's Router to fill the element's `href` property with a url that matches the path to the supplied `routeName` for your routers's configured `Location` scheme, which defaults to Ember.HashLocation. - ## Handling current route + ### Handling current route `{{linkTo}}` will apply a CSS class name of 'active' when the application's current route matches the supplied routeName. For example, if the application's current route is 'photoGallery.recent' the following use of `{{linkTo}}`: - ``` + ```handlebars {{#linkTo photoGallery.recent}} Great Hamster Photos from the last week {{/linkTo}} ``` @@ -24770,11 +25216,11 @@ The CSS class name used for active classes can be customized for a single use of `{{linkTo}}` by passing an `activeClass` option: - ``` + ```handlebars {{#linkTo photoGallery.recent activeClass="current-url"}} Great Hamster Photos from the last week {{/linkTo}} ``` @@ -24785,11 +25231,11 @@ ``` To override this option for your entire application, see "Overriding Application-wide Defaults". - ## Supplying a model + ### Supplying a model An optional model argument can be used for routes whose paths contain dynamic segments. This argument will become the model context of the linked route: ```javascript @@ -24808,11 +25254,11 @@ <a href="/hamster-photos/42"> Tomster </a> ``` - ## Supplying multiple models + ### Supplying multiple models For deep-linking to route paths that contain multiple dynamic segments, multiple model arguments can be used. As the router transitions through the route path, each supplied model argument will become the context for the route with the dynamic segments: @@ -24836,11 +25282,11 @@ <a href="/hamster-photos/42/comment/718"> A+++ would snuggle again. </a> ``` - ## Overriding Application-wide Defaults + ### Overriding Application-wide Defaults ``{{linkTo}}`` creates an instance of Ember.LinkView for rendering. To override options for your entire application, reopen Ember.LinkView and supply the desired values: @@ -24848,71 +25294,11 @@ Ember.LinkView.reopen({ activeClass: "is-active", tagName: 'li' }) ``` - - @class LinkView - @namespace Ember - @extends Ember.View - **/ - var LinkView = Ember.LinkView = Ember.View.extend({ - tagName: 'a', - namedRoute: null, - currentWhen: null, - title: null, - activeClass: 'active', - replace: false, - attributeBindings: ['href', 'title'], - classNameBindings: 'active', - // Even though this isn't a virtual view, we want to treat it as if it is - // so that you can access the parent with {{view.prop}} - concreteView: Ember.computed(function() { - return get(this, 'parentView'); - }).property('parentView'), - - active: Ember.computed(function() { - var router = this.get('router'), - params = resolvedPaths(this.parameters), - currentWithIndex = this.currentWhen + '.index', - isActive = router.isActive.apply(router, [this.currentWhen].concat(params)) || - router.isActive.apply(router, [currentWithIndex].concat(params)); - - if (isActive) { return get(this, 'activeClass'); } - }).property('namedRoute', 'router.url'), - - router: Ember.computed(function() { - return this.get('controller').container.lookup('router:main'); - }), - - click: function(event) { - if (!isSimpleClick(event)) { return true; } - - event.preventDefault(); - if (this.bubbles === false) { event.stopPropagation(); } - - var router = this.get('router'); - - if (this.get('replace')) { - router.replaceWith.apply(router, args(this, router)); - } else { - router.transitionTo.apply(router, args(this, router)); - } - }, - - href: Ember.computed(function() { - if (this.get('tagName') !== 'a') { return false; } - - var router = this.get('router'); - return router.generate.apply(router, args(this, router)); - }) - }); - - LinkView.toString = function() { return "LinkView"; }; - - /** @method linkTo @for Ember.Handlebars.helpers @param {String} routeName @param {Object} [context]* @return {String} HTML string @@ -25125,10 +25511,11 @@ isSimpleClick = Ember.ViewUtils.isSimpleClick; var EmberHandlebars = Ember.Handlebars, handlebarsGet = EmberHandlebars.get, SafeString = EmberHandlebars.SafeString, + forEach = Ember.ArrayPolyfills.forEach, get = Ember.get, a_slice = Array.prototype.slice; function args(options, actionName) { var ret = []; @@ -25151,11 +25538,11 @@ return isSimpleClick(event); } var allowed = true; - keys.forEach(function(key) { + forEach.call(keys, function(key) { if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { allowed = false; } }); @@ -26814,18 +27201,17 @@ return this; }, reset: function() { - Ember.assert('App#reset no longer rneeds to be wrapped in a run-loop', !Ember.run.currentRunLoop); + Ember.assert('App#reset no longer needs to be wrapped in a run-loop', !Ember.run.currentRunLoop); Ember.run(this, function(){ - Ember.run(get(this,'__container__'), 'destroy'); + Ember.run(this.__container__, 'destroy'); this.buildContainer(); this._readinessDeferrals = 1; - this.$(this.rootElement).removeClass('ember-application'); Ember.run.schedule('actions', this, function(){ this._initialize(); this.startRouting(); }); @@ -26881,36 +27267,21 @@ `customEvents`. @method setupEventDispatcher */ setupEventDispatcher: function() { - var eventDispatcher = this.createEventDispatcher(), - customEvents = get(this, 'customEvents'); + var customEvents = get(this, 'customEvents'), + rootElement = get(this, 'rootElement'), + dispatcher = this.__container__.lookup('event_dispatcher:main'); - eventDispatcher.setup(customEvents); + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); }, /** @private - Create an event dispatcher for the application's `rootElement`. - - @method createEventDispatcher - */ - createEventDispatcher: function() { - var rootElement = get(this, 'rootElement'), - eventDispatcher = Ember.EventDispatcher.create({ - rootElement: rootElement - }); - - set(this, 'eventDispatcher', eventDispatcher); - return eventDispatcher; - }, - - /** - @private - If the application has a router, use it to route to the current URL, and trigger a new call to `route` whenever the URL changes. @method startRouting @property router {Ember.Router} @@ -26944,14 +27315,11 @@ resolver: null, willDestroy: function() { Ember.BOOTED = false; - var eventDispatcher = get(this, 'eventDispatcher'); - if (eventDispatcher) { eventDispatcher.destroy(); } - - get(this, '__container__').destroy(); + this.__container__.destroy(); }, initializer: function(options) { this.constructor.initializer(options); } @@ -27009,17 +27377,18 @@ container.register('controller:basic', Ember.Controller, { instantiate: false }); container.register('controller:object', Ember.ObjectController, { instantiate: false }); container.register('controller:array', Ember.ArrayController, { instantiate: false }); container.register('route:basic', Ember.Route, { instantiate: false }); + container.register('event_dispatcher:main', Ember.EventDispatcher); container.injection('router:main', 'namespace', 'application:main'); - container.typeInjection('controller', 'target', 'router:main'); - container.typeInjection('controller', 'namespace', 'application:main'); + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); - container.typeInjection('route', 'router', 'router:main'); + container.injection('route', 'router', 'router:main'); return container; } }); @@ -27130,10 +27499,35 @@ return satisfied; } Ember.ControllerMixin.reopen({ concatenatedProperties: ['needs'], + + /** + An array of other controller objects available inside + instances of this controller via the `controllers` + property: + + For example, when you define a controller: + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'] + }); + ``` + + The application's single instance of these other + controllers are accessible by name through the + `controllers` property: + + ```javascript + this.get('controllers.post'); // instance of App.PostController + ``` + + @property {Array} needs + @default [] + */ needs: [], init: function() { this._super.apply(this, arguments); @@ -28535,11 +28929,11 @@ })(); })(); -// Version: v1.0.0-rc.3 -// Last commit: 96e97b5 (2013-04-21 02:07:10 -0400) +// Version: v1.0.0-rc.1-536-gd47406c +// Last commit: d47406c (2013-04-25 17:21:02 -0700) (function() { /** Ember