dist/ember.js in ember-source-1.9.0.beta.1.1 vs dist/ember.js in ember-source-1.9.0.beta.3

- old
+ new

@@ -3,11 +3,11 @@ * @copyright Copyright 2011-2014 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.9.0-beta.1 + * @version 1.9.0-beta.3 */ (function() { var enifed, requireModule, eriuqer, requirejs, Ember; @@ -191,10 +191,27 @@ } } } }, + join: function(target, method /*, args */) { + if (this.currentInstance) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + return method.apply(target, slice.call(arguments, 2)); + } else { + return this.run.apply(this, arguments); + } + }, + defer: function(queueName, target, method /* , args */) { if (!method) { method = target; target = null; } @@ -1177,24 +1194,10 @@ this.children.push(container); return container; }, /** - Sets a key-value pair on the current container. If a parent container, - has the same key, once set on a child, the parent and child will diverge - as expected. - - @method set - @param {Object} object - @param {String} key - @param {any} value - */ - set: function(object, key, value) { - object[key] = value; - }, - - /** Registers a factory for later injection. Example: ```javascript @@ -1445,15 +1448,17 @@ this._typeOptions[type] = options; }, /** @method options - @param {String} type + @param {String} fullName @param {Object} options */ - options: function(type, options) { - this.optionsForType(type, options); + options: function(fullName, options) { + options = options || {}; + var normalizedName = this.normalize(fullName); + this._options[normalizedName] = options; }, /** Used only via `injection`. @@ -2489,14 +2494,14 @@ If there is a bubbling browser event that Ember does not listen for by default, you can specify custom events and their corresponding view method names by setting the application's `customEvents` property: ```javascript - App = Ember.Application.create({ + var App = Ember.Application.create({ customEvents: { // add support for the paste event - paste: "paste" + paste: 'paste' } }); ``` By default, the application sets up these event listeners on the document @@ -2506,11 +2511,11 @@ For example, if only events inside a DOM element with the ID of `ember-app` should be delegated, set your application's `rootElement` property: ```javascript - window.App = Ember.Application.create({ + var App = Ember.Application.create({ rootElement: '#ember-app' }); ``` The `rootElement` can be either a DOM element or a jQuery-compatible selector @@ -2549,11 +2554,11 @@ between routes can be logged with the `LOG_TRANSITIONS` flag, and more detailed intra-transition logging can be logged with the `LOG_TRANSITIONS_INTERNAL` flag: ```javascript - window.App = Ember.Application.create({ + var App = Ember.Application.create({ LOG_TRANSITIONS: true, // basic logging of successful transitions LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps }); ``` @@ -2618,14 +2623,14 @@ views, set your `Ember.Application`'s `customEvents` property to a hash containing the DOM event name as the key and the corresponding view method name as the value. For example: ```javascript - App = Ember.Application.create({ + var App = Ember.Application.create({ customEvents: { // add support for the paste event - paste: "paste" + paste: 'paste' } }); ``` @property customEvents @@ -2751,14 +2756,15 @@ Use this to defer readiness until some condition is true. Example: ```javascript - App = Ember.Application.create(); + var App = Ember.Application.create(); + App.deferReadiness(); - - jQuery.getJSON("/auth-token", function(token) { + // Ember.$ is a reference to the jQuery object/function + Ember.$.getJSON('/auth-token', function(token) { App.token = token; App.advanceReadiness(); }); ``` @@ -2800,23 +2806,24 @@ A simple example: ```javascript var App = Ember.Application.create(); - App.Orange = Ember.Object.extend(); + + App.Orange = Ember.Object.extend(); App.register('fruit:favorite', App.Orange); ``` Ember will resolve factories from the `App` namespace automatically. For example `App.CarsController` will be discovered and returned if an application requests `controller:cars`. An example of registering a controller with a non-standard name: ```javascript - var App = Ember.Application.create(), - Session = Ember.Controller.extend(); + var App = Ember.Application.create(); + var Session = Ember.Controller.extend(); App.register('controller:session', Session); // The Session controller can now be treated like a normal controller, // despite its non-standard name. @@ -2837,14 +2844,14 @@ App.Person = Ember.Object.extend(); App.Orange = Ember.Object.extend(); App.Email = Ember.Object.extend(); App.session = Ember.Object.create(); - App.register('model:user', App.Person, {singleton: false }); + App.register('model:user', App.Person, { singleton: false }); App.register('fruit:favorite', App.Orange); - App.register('communication:main', App.Email, {singleton: false}); - App.register('session', App.session, {instantiate: false}); + App.register('communication:main', App.Email, { singleton: false }); + App.register('session', App.session, { instantiate: false }); ``` @method register @param fullName {String} type:name (e.g., 'model:user') @param factory {Function} (e.g., App.Person) @@ -2864,12 +2871,12 @@ provide services to a set of framework components. An example of providing a session object to all controllers: ```javascript - var App = Ember.Application.create(), - Session = Ember.Object.extend({ isAuthenticated: false }); + var App = Ember.Application.create(); + var Session = Ember.Object.extend({ isAuthenticated: false }); // A factory must be registered before it can be injected App.register('session:main', Session); // Inject 'session:main' onto all factories of the type 'controller' @@ -2892,11 +2899,11 @@ It is important to note that injections can only be performed on classes that are instantiated by Ember itself. Instantiating a class directly (via `create` or `new`) bypasses the dependency injection system. - Ember-Data instantiates its models in a unique manner, and consequently + **Note:** Ember-Data instantiates its models in a unique manner, and consequently injections onto models (or all models) will not work as expected. Injections on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` to `true`. @method inject @@ -2964,28 +2971,27 @@ 4. Re-route to the existing url Typical Example: ```javascript - var App; run(function() { App = Ember.Application.create(); }); - module("acceptance test", { + module('acceptance test', { setup: function() { App.reset(); } }); - test("first test", function() { + test('first test', function() { // App is freshly reset }); - test("first test", function() { + test('second test', function() { // App is again freshly reset }); ``` Advanced Example: @@ -2993,32 +2999,32 @@ Occasionally you may want to prevent the app from initializing during setup. This could enable extra configuration, or enable asserting prior to the app becoming ready. ```javascript - var App; run(function() { App = Ember.Application.create(); }); - module("acceptance test", { + module('acceptance test', { setup: function() { run(function() { App.reset(); App.deferReadiness(); }); } }); - test("first test", function() { + test('first test', function() { ok(true, 'something before app is initialized'); run(function() { App.advanceReadiness(); }); + ok(true, 'something after app is initialized'); }); ``` @method reset @@ -3183,12 +3189,13 @@ same name will result in an error. ```javascript Ember.Application.initializer({ name: 'namedInitializer', + initialize: function(container, application) { - Ember.debug("Running namedInitializer!"); + Ember.debug('Running namedInitializer!'); } }); ``` * `before` and `after` are used to ensure that this initializer is ran prior @@ -3198,12 +3205,13 @@ An example of ordering initializers, we create an initializer named `first`: ```javascript Ember.Application.initializer({ name: 'first', + initialize: function(container, application) { - Ember.debug("First initializer!"); + Ember.debug('First initializer!'); } }); // DEBUG: First initializer! ``` @@ -3215,11 +3223,11 @@ Ember.Application.initializer({ name: 'second', after: 'first', initialize: function(container, application) { - Ember.debug("Second initializer!"); + Ember.debug('Second initializer!'); } }); // DEBUG: First initializer! // DEBUG: Second initializer! @@ -3232,11 +3240,11 @@ Ember.Application.initializer({ name: 'pre', before: 'first', initialize: function(container, application) { - Ember.debug("Pre initializer!"); + Ember.debug('Pre initializer!'); } }); // DEBUG: Pre initializer! // DEBUG: First initializer! @@ -3250,11 +3258,11 @@ Ember.Application.initializer({ name: 'post', after: ['first', 'second'], initialize: function(container, application) { - Ember.debug("Post initializer!"); + Ember.debug('Post initializer!'); } }); // DEBUG: Pre initializer! // DEBUG: First initializer! @@ -3267,14 +3275,15 @@ Example of using `container` to preload data into the store: ```javascript Ember.Application.initializer({ - name: "preload-data", + name: 'preload-data', initialize: function(container, application) { var store = container.lookup('store:main'); + store.pushPayload(preloadedData); } }); ``` @@ -3304,10 +3313,11 @@ }); } Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]); Ember.assert("An initializer cannot be registered without an initialize function", canInvoke(initializer, 'initialize')); + Ember.assert("An initializer cannot be registered without a name property", initializer.name !== undefined); this.initializers[initializer.name] = initializer; }, /** @@ -5999,28 +6009,28 @@ if (stack1 != null) { data.buffer.push(stack1); } data.buffer.push("</option>"); return buffer; },"3":function(depth0,helpers,partials,data) { var stack1; - stack1 = helpers.each.call(depth0, "view.groupedContent", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(4, data),"inverse":this.noop,"types":["ID"],"contexts":[depth0],"data":data}); + stack1 = helpers.each.call(depth0, "group", "in", "view.groupedContent", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(4, data),"inverse":this.noop,"types":["ID","ID","ID"],"contexts":[depth0,depth0,depth0],"data":data}); if (stack1 != null) { data.buffer.push(stack1); } else { data.buffer.push(''); } },"4":function(depth0,helpers,partials,data) { var escapeExpression=this.escapeExpression; data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {"name":"view","hash":{ - 'label': ("label"), - 'content': ("content") + 'label': ("group.label"), + 'content': ("group.content") },"hashTypes":{'label': "ID",'content': "ID"},"hashContexts":{'label': depth0,'content': depth0},"types":["ID"],"contexts":[depth0],"data":data}))); },"6":function(depth0,helpers,partials,data) { var stack1; - stack1 = helpers.each.call(depth0, "view.content", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(7, data),"inverse":this.noop,"types":["ID"],"contexts":[depth0],"data":data}); + stack1 = helpers.each.call(depth0, "item", "in", "view.content", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(7, data),"inverse":this.noop,"types":["ID","ID","ID"],"contexts":[depth0,depth0,depth0],"data":data}); if (stack1 != null) { data.buffer.push(stack1); } else { data.buffer.push(''); } },"7":function(depth0,helpers,partials,data) { var escapeExpression=this.escapeExpression; data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {"name":"view","hash":{ - 'content': ("") + 'content': ("item") },"hashTypes":{'content': "ID"},"hashContexts":{'content': depth0},"types":["ID"],"contexts":[depth0],"data":data}))); },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { var stack1, buffer = ''; stack1 = helpers['if'].call(depth0, "view.prompt", {"name":"if","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(1, data),"inverse":this.noop,"types":["ID"],"contexts":[depth0],"data":data}); if (stack1 != null) { data.buffer.push(stack1); } @@ -6885,25 +6895,33 @@ function helperMissingHelper(path) { if (!resolveHelper) { resolveHelper = requireModule('ember-handlebars/helpers/binding')['resolveHelper']; } // ES6TODO: stupid circular dep - var error, view = ""; + var error, fmtError, view = ""; var options = arguments[arguments.length - 1]; var helper = resolveHelper(options.data.view.container, options.name); if (helper) { return helper.apply(this, arguments); } - error = "%@ Handlebars error: Could not find property '%@' on object %@."; if (options.data) { view = options.data.view; } - throw new EmberError(fmt(error, [view, options.name, this])); + + if (options.name.match(/-/)) { + error = "%@ Handlebars error: Could not find component or helper named '%@'"; + fmtError = fmt(error, [view, options.name]); + } else { + error = "%@ Handlebars error: Could not find property '%@' on object %@."; + fmtError = fmt(error, [view, options.name, this]); + } + + throw new EmberError(fmtError); } __exports__.helperMissingHelper = helperMissingHelper;/** @private @method blockHelperMissingHelper @@ -8219,27 +8237,17 @@ /** The `{{#each}}` helper loops over elements in a collection. It is an extension of the base Handlebars `{{#each}}` helper. The default behavior of `{{#each}}` is to yield its inner block once for every - item in an array. Each yield will provide the item as the context of the block. + item in an array. ```javascript var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; ``` ```handlebars - {{#each developers}} - {{name}} - {{! `this` is each developer }} - {{/each}} - ``` - - `{{#each}}` supports an alternative syntax with element naming. This preserves - context of the yielded block: - - ```handlebars {{#each person in developers}} {{person.name}} {{! `this` is whatever it was outside the #each }} {{/each}} ``` @@ -8250,12 +8258,12 @@ ```javascript var developerNames = ['Yehuda', 'Tom', 'Paul'] ``` ```handlebars - {{#each developerNames}} - {{this}} + {{#each name in developerNames}} + {{name}} {{/each}} ``` ### {{else}} condition @@ -8277,12 +8285,12 @@ The following template: ```handlebars <ul> - {{#each developers itemViewClass="person"}} - {{name}} + {{#each developer in developers itemViewClass="person"}} + {{developer.name}} {{/each}} </ul> ``` Will use the following view for each item @@ -8309,17 +8317,17 @@ as the previous one: ```javascript App.PersonView = Ember.View.extend({ tagName: 'li', - template: '{{name}}' + template: '{{developer.name}}' }); ``` ```handlebars <ul> - {{each developers itemViewClass="person"}} + {{each developer in developers itemViewClass="person"}} </ul> ``` ### Specifying an alternative view for no items (else) @@ -8333,12 +8341,12 @@ }); ``` ```handlebars <ul> - {{#each developers emptyViewClass="no-people"}} - <li>{{name}}</li> + {{#each developer in developers emptyViewClass="no-people"}} + <li>{{developer.name}}</li> {{/each}} </ul> ``` ### Wrapping each item in a controller @@ -8377,16 +8385,17 @@ @param [options.itemController] {String} name of a controller to be created for each item */ function eachHelper(path) { var options = arguments[arguments.length - 1]; var helperName = 'each'; + var keywordName; if (arguments.length === 4) { Ember.assert("If you pass more than one argument to the each helper," + " it must be in the form #each foo in bar", arguments[1] === "in"); - var keywordName = arguments[0]; + keywordName = arguments[0]; path = arguments[2]; helperName += ' ' + keywordName + ' in ' + path; options.hash.keyword = keywordName; @@ -8394,10 +8403,12 @@ path = ''; } else { helperName += ' ' + path; } + Ember.deprecate('Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.', keywordName); + options.hash.emptyViewClass = Ember._MetamorphView; options.hash.dataSourceBinding = path; options.hashTypes.dataSourceBinding = 'STRING'; options.helperName = options.helperName || helperName; @@ -8652,21 +8663,11 @@ value as the name of the template to render. If the resolved value is falsy, nothing will be rendered. If `someTemplateName` changes, the partial will be re-rendered using the new template name. - ## Setting the partial's context with `with` - The `partial` helper can be used in conjunction with the `with` - helper to set a context that will be used by the partial: - - ```handlebars - {{#with currentUser}} - {{partial "user_info"}} - {{/with}} - ``` - @method partial @for Ember.Handlebars.helpers @param {String} partialName the name of the template to render minus the leading underscore */ @@ -9280,46 +9281,15 @@ } } }); /** - Use the `{{with}}` helper when you want to scope context. Take the following code as an example: + Use the `{{with}}` helper when you want to aliases the to a new name. It's helpful + for semantic clarity and to retain default scope or to reference from another + `{{with}}` block. ```handlebars - <h5>{{user.name}}</h5> - - <div class="role"> - <h6>{{user.role.label}}</h6> - <span class="role-id">{{user.role.id}}</span> - - <p class="role-desc">{{user.role.description}}</p> - </div> - ``` - - `{{with}}` can be our best friend in these cases, - instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. - Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: - - ```handlebars - <h5>{{user.name}}</h5> - - <div class="role"> - {{#with user.role}} - <h6>{{label}}</h6> - <span class="role-id">{{id}}</span> - - <p class="role-desc">{{description}}</p> - {{/with}} - </div> - ``` - - ### `as` operator - - This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain - default scope or to reference from another `{{with}}` block. - - ```handlebars // posts might not be {{#with user.posts as blogPosts}} <div class="notice"> There are {{blogPosts.length}} blog posts written by {{user.name}}. </div> @@ -9337,22 +9307,22 @@ the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. ### `controller` option Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of - the specified controller with the new context as its content. + the specified controller wrapping the aliased keyword. This is very similar to using an `itemController` option with the `{{each}}` helper. ```handlebars - {{#with users.posts controller='userBlogPosts'}} - {{!- The current context is wrapped in our controller instance }} + {{#with users.posts as posts controller='userBlogPosts'}} + {{!- `posts` is wrapped in our controller instance }} {{/with}} ``` - In the above example, the template provided to the `{{with}}` block is now wrapped in the - `userBlogPost` controller, which provides a very elegant way to decorate the context with custom + In the above example, the `posts` keyword is now wrapped in the `userBlogPost` controller, + which provides an elegant way to decorate the context with custom functions/properties. @method with @for Ember.Handlebars.helpers @param {Function} context @@ -9387,10 +9357,12 @@ bindContext = this; options = localizedOptions; preserveContext = true; } else { + Ember.deprecate('Using the context switching form of `{{with}}` is deprecated. Please use the keyword form (`{{with foo as bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.'); + Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); helperName += ' ' + contextPath; bindContext = options.contexts[0]; @@ -11014,11 +10986,13 @@ // add an observer on the object to be notified when the binding should be updated addObserver(obj, fromPath, this, this.fromDidChange); // if the binding is a two-way binding, also set up an observer on the target - if (!this._oneWay) { addObserver(obj, toPath, this, this.toDidChange); } + if (!this._oneWay) { + addObserver(obj, toPath, this, this.toDidChange); + } this._readyToSync = true; return this; }, @@ -11039,11 +11013,13 @@ // remove an observer on the object so we're no longer notified of // changes that should update bindings. removeObserver(obj, this._from, this, this.fromDidChange); // if the binding is two-way, remove the observer from the target as well - if (twoWay) { removeObserver(obj, this._to, this, this.toDidChange); } + if (twoWay) { + removeObserver(obj, this._to, this, this.toDidChange); + } this._readyToSync = false; // disable scheduled syncs... return this; }, @@ -11425,11 +11401,13 @@ if (pendingQueue.length === 0) { return; } // nothing to do var queue = pendingQueue; pendingQueue = []; - forEach.call(queue, function(q) { q[0].add(q[1]); }); + forEach.call(queue, function(q) { + q[0].add(q[1]); + }); warn('Watching an undefined global, Ember expects watched globals to be' + ' setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); } @@ -11441,11 +11419,13 @@ if (!m.hasOwnProperty('chainWatchers')) { nodes = m.chainWatchers = {}; } - if (!nodes[keyName]) { nodes[keyName] = []; } + if (!nodes[keyName]) { + nodes[keyName] = []; + } nodes[keyName].push(node); watchKey(obj, keyName, m); } function removeChainWatcher(obj, keyName, node) { @@ -11485,11 +11465,13 @@ this._value = value; this._paths = {}; if (this._watching) { this._object = parent.value(); - if (this._object) { addChainWatcher(this._object, this._key, this); } + if (this._object) { + addChainWatcher(this._object, this._key, this); + } } // Special-case: the EachProxy relies on immediate evaluation to // establish its observers. // @@ -11505,13 +11487,17 @@ function lazyGet(obj, key) { if (!obj) return undefined; var meta = obj['__ember_meta__']; // check if object meant only to be a prototype - if (meta && meta.proto === obj) return undefined; + if (meta && meta.proto === obj) { + return undefined; + } - if (key === "@each") return get(obj, key); + if (key === "@each") { + return get(obj, key); + } // if a CP only return cached value var desc = meta && meta.descs[key]; if (desc && desc._cacheable) { if (key in meta.cache) { @@ -11533,11 +11519,13 @@ }; ChainNodePrototype.destroy = function() { if (this._watching) { var obj = this._object; - if (obj) { removeChainWatcher(obj, this._key, this); } + if (obj) { + removeChainWatcher(obj, this._key, this); + } this._watching = false; // so future calls do nothing } }; // copies a top level object only @@ -11545,11 +11533,14 @@ var ret = new ChainNode(null, null, obj); var paths = this._paths; var path; for (path in paths) { - if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + // this check will also catch non-number vals. + if (paths[path] <= 0) { + continue; + } ret.add(path); } return ret; }; @@ -11592,11 +11583,13 @@ // path ChainNodePrototype.remove = function(path) { var obj, tuple, key, src, paths; paths = this._paths; - if (paths[path] > 0) { paths[path]--; } + if (paths[path] > 0) { + paths[path]--; + } obj = this.value(); tuple = normalizeTuple(obj, path); if (tuple[0] === obj) { path = tuple[1]; @@ -11615,14 +11608,18 @@ ChainNodePrototype.count = 0; ChainNodePrototype.chain = function(key, path, src) { var chains = this._chains; var node; - if (!chains) { chains = this._chains = {}; } + if (!chains) { + chains = this._chains = {}; + } node = chains[key]; - if (!node) { node = chains[key] = new ChainNode(this, key, src); } + if (!node) { + node = chains[key] = new ChainNode(this, key, src); + } node.count++; // count chains... // chain rest of path if there is one if (path) { key = firstKey(path); @@ -11634,14 +11631,14 @@ ChainNodePrototype.unchain = function(key, path) { var chains = this._chains; var node = chains[key]; // unchain rest of path first... - if (path && path.length>1) { - key = firstKey(path); - path = path.slice(key.length+1); - node.unchain(key, path); + if (path && path.length > 1) { + var nextKey = firstKey(path); + var nextPath = path.slice(nextKey.length + 1); + node.unchain(nextKey, nextPath); } // delete node if needed. node.count--; if (node.count<=0) { @@ -11653,20 +11650,26 @@ ChainNodePrototype.willChange = function(events) { var chains = this._chains; if (chains) { for(var key in chains) { - if (!chains.hasOwnProperty(key)) { continue; } + if (!chains.hasOwnProperty(key)) { + continue; + } chains[key].willChange(events); } } - if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } + if (this._parent) { + this._parent.chainWillChange(this, this._key, 1, events); + } }; ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { - if (this._key) { path = this._key + '.' + path; } + if (this._key) { + path = this._key + '.' + path; + } if (this._parent) { this._parent.chainWillChange(this, path, depth+1, events); } else { if (depth > 1) { @@ -11678,11 +11681,14 @@ } } }; ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { - if (this._key) { path = this._key + '.' + path; } + if (this._key) { + path = this._key + '.' + path; + } + if (this._parent) { this._parent.chainDidChange(this, path, depth+1, events); } else { if (depth > 1) { events.push(this.value(), path); @@ -11705,12 +11711,13 @@ } this._value = undefined; // Special-case: the EachProxy relies on immediate evaluation to // establish its observers. - if (this._parent && this._parent._key === '@each') + if (this._parent && this._parent._key === '@each') { this.value(); + } } // then notify chains... var chains = this._chains; if (chains) { @@ -11719,26 +11726,34 @@ chains[key].didChange(events); } } // if no events are passed in then we only care about the above wiring update - if (events === null) { return; } + if (events === null) { + return; + } // and finally tell parent about my path changing... - if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } + if (this._parent) { + this._parent.chainDidChange(this, this._key, 1, events); + } }; function finishChains(obj) { // We only create meta if we really have to - var m = obj['__ember_meta__'], - chains, chainWatchers, chainNodes; + var m = obj['__ember_meta__']; + var chains, chainWatchers, chainNodes; + if (m) { // finish any current chains node watchers that reference obj chainWatchers = m.chainWatchers; if (chainWatchers) { for(var key in chainWatchers) { - if (!chainWatchers.hasOwnProperty(key)) { continue; } + if (!chainWatchers.hasOwnProperty(key)) { + continue; + } + chainNodes = chainWatchers[key]; if (chainNodes) { for (var i=0,l=chainNodes.length;i<l;i++) { chainNodes[i].didChange(null); } @@ -11787,22 +11802,22 @@ // .......................................................... // COMPUTED PROPERTY // /** - A computed property transforms an objects function into a property. + A computed property transforms an object's function into a property. By default the function backing the computed property will only be called once and the result will be cached. You can specify various properties - that your computed property is dependent on. This will force the cached + that your computed property depends on. This will force the cached result to be recomputed if the dependencies are modified. In the following example we declare a computed property (by calling - `.property()` on the fullName function) and setup the properties + `.property()` on the fullName function) and setup the property dependencies (depending on firstName and lastName). The fullName function will be called once (regardless of how many times it is accessed) as long - as it's dependencies have not been changed. Once firstName or lastName are updated + as its dependencies have not changed. Once firstName or lastName are updated any future calls (or anything bound) to fullName will incorporate the new values. ```javascript var Person = Ember.Object.extend({ @@ -12094,11 +12109,13 @@ } else { cache[keyName] = ret; } chainNodes = meta.chainWatchers && meta.chainWatchers[keyName]; - if (chainNodes) { finishChains(chainNodes); } + if (chainNodes) { + finishChains(chainNodes); + } addDependentKeys(this, obj, keyName, meta); } else { ret = this.func.call(obj, keyName); } return ret; @@ -12336,11 +12353,13 @@ function cacheFor(obj, key) { var meta = obj['__ember_meta__']; var cache = meta && meta.cache; var ret = cache && cache[key]; - if (ret === UNDEFINED) { return undefined; } + if (ret === UNDEFINED) { + return undefined; + } return ret; } cacheFor.set = function(cache, key, value) { if (value === undefined) { @@ -12350,11 +12369,13 @@ } }; cacheFor.get = function(cache, key) { var ret = cache[key]; - if (ret === UNDEFINED) { return undefined; } + if (ret === UNDEFINED) { + return undefined; + } return ret; }; cacheFor.remove = function(cache, key) { cache[key] = undefined; @@ -13095,11 +13116,11 @@ The core Runtime framework is based on the jQuery API with a number of performance optimizations. @class Ember @static - @version 1.9.0-beta.1 + @version 1.9.0-beta.3 */ 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. @@ -13122,14 +13143,14 @@ /** @property VERSION @type String - @default '1.9.0-beta.1' + @default '1.9.0-beta.3' @static */ - Ember.VERSION = '1.9.0-beta.1'; + Ember.VERSION = '1.9.0-beta.3'; /** Standard environmental variables. You can define these in a global `EmberENV` variable before loading Ember to control various configuration settings. @@ -13240,11 +13261,11 @@ @default true */ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); /** - Determines whether Ember should add ECMAScript 5 shims to older browsers. + Determines whether Ember should add ECMAScript 5 Array shims to older browsers. @property SHIM_ES5 @type Boolean @default Ember.EXTEND_PROTOTYPES */ @@ -14773,11 +14794,12 @@ return function keys(obj) { if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } - var result = [], prop, i; + var result = []; + var prop, i; for (prop in obj) { if (prop !== '_super' && prop.lastIndexOf('__',0) !== 0 && hasOwnProperty.call(obj, prop)) { @@ -14863,12 +14885,16 @@ } var method = typeof consoleObj === 'object' ? consoleObj[name] : null; if (method) { - // Older IE doesn't support apply, but Chrome needs it - if (typeof method.apply === 'function') { + // Older IE doesn't support bind, but Chrome needs it + if (typeof method.bind === 'function') { + logToConsole = method.bind(consoleObj); + logToConsole.displayName = 'console.' + name; + return logToConsole; + } else if (typeof method.apply === 'function') { logToConsole = function() { method.apply(consoleObj, arguments); }; logToConsole.displayName = 'console.' + name; return logToConsole; @@ -15557,11 +15583,10 @@ */ var Ember = __dependency1__["default"]; // warn, assert, wrap, et; var merge = __dependency2__["default"]; - var a_map = __dependency3__.map; var a_indexOf = __dependency3__.indexOf; var a_forEach = __dependency3__.forEach; var o_create = __dependency4__.create; var get = __dependency5__.get; var set = __dependency6__.set; @@ -15612,26 +15637,10 @@ ret = m.mixins = o_create(ret); } return ret; } - function initMixin(mixin, args) { - if (args && args.length > 0) { - mixin.mixins = a_map.call(args, function(x) { - if (x instanceof Mixin) { return x; } - - // Note: Manually setup a primitive mixin here. This is the only - // way to actually get a primitive mixin. This way normal creation - // of mixins will give you combined mixins... - var mixin = new Mixin(); - mixin.properties = x; - return mixin; - }); - } - return mixin; - } - function isMethod(obj) { return 'function' === typeof obj && obj.isMethod !== false && obj !== Boolean && obj !== Object && @@ -16074,17 +16083,34 @@ @class Mixin @namespace Ember */ __exports__["default"] = Mixin; - function Mixin() { return initMixin(this, arguments); } - Mixin.prototype = { - properties: null, - mixins: null, - ownerConstructor: null - }; + function Mixin(args, properties) { + this.properties = properties; + var length = args && args.length; + + if (length > 0) { + var m = new Array(length); + + for (var i = 0; i < length; i++) { + var x = args[i]; + if (x instanceof Mixin) { + m[i] = x; + } else { + m[i] = new Mixin(undefined, x); + } + } + + this.mixins = m; + } else { + this.mixins = undefined; + } + this.ownerConstructor = undefined; + } + Mixin._apply = applyMixin; Mixin.applyPartial = function(obj) { var args = a_slice.call(arguments, 1); return applyMixin(obj, args, true); @@ -16102,26 +16128,30 @@ */ Mixin.create = function() { // ES6TODO: this relies on a global state? Ember.anyUnprocessedMixins = true; var M = this; - return initMixin(new M(), arguments); + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + return new M(args, undefined); }; var MixinPrototype = Mixin.prototype; /** @method reopen @param arguments* */ MixinPrototype.reopen = function() { - var mixin, tmp; + var mixin; if (this.properties) { - mixin = Mixin.create(); - mixin.properties = this.properties; - delete this.properties; + mixin = new Mixin(undefined, this.properties); + this.properties = undefined; this.mixins = [mixin]; } else if (!this.mixins) { this.mixins = []; } @@ -16136,13 +16166,11 @@ Object.prototype.toString.call(mixin) !== '[object Array]'); if (mixin instanceof Mixin) { mixins.push(mixin); } else { - tmp = Mixin.create(); - tmp.properties = mixin; - mixins.push(tmp); + mixins.push(new Mixin(undefined, mixin)); } } return this; }; @@ -16190,11 +16218,11 @@ } return false; }; MixinPrototype.without = function() { - var ret = new Mixin(this); + var ret = new Mixin([this]); ret._without = a_slice.call(arguments); return ret; }; function _keys(ret, mixin, seen) { @@ -16215,11 +16243,13 @@ var keys = {}; var seen = {}; var ret = []; _keys(keys, this, seen); for(var key in keys) { - if (keys.hasOwnProperty(key)) { ret.push(key); } + if (keys.hasOwnProperty(key)) { + ret.push(key); + } } return ret; }; // returns the mixins currently applied to the specified object @@ -17173,13 +17203,22 @@ var m = obj['__ember_meta__']; var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; var proto = m && m.proto; var desc = m && m.descs[keyName]; - if (!watching) { return; } - if (proto === obj) { return; } - if (desc && desc.willChange) { desc.willChange(obj, keyName); } + if (!watching) { + return; + } + + if (proto === obj) { + return; + } + + if (desc && desc.willChange) { + desc.willChange(obj, keyName); + } + dependentKeysWillChange(obj, keyName, m); chainsWillChange(obj, keyName, m); notifyBeforeObservers(obj, keyName); } @@ -17202,16 +17241,23 @@ var m = obj['__ember_meta__']; var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; var proto = m && m.proto; var desc = m && m.descs[keyName]; - if (proto === obj) { return; } + if (proto === obj) { + return; + } // shouldn't this mean that we're watching this key? - if (desc && desc.didChange) { desc.didChange(obj, keyName); } - if (!watching && keyName !== 'length') { return; } + if (desc && desc.didChange) { + desc.didChange(obj, keyName); + } + if (!watching && keyName !== 'length') { + return; + } + if (m && m.deps && m.deps[keyName]) { dependentKeysDidChange(obj, keyName, m); } chainsDidChange(obj, keyName, m, false); @@ -17225,13 +17271,20 @@ var deps; if (meta && meta.deps && (deps = meta.deps[depKey])) { var seen = WILL_SEEN; var top = !seen; - if (top) { seen = WILL_SEEN = {}; } + + if (top) { + seen = WILL_SEEN = {}; + } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); - if (top) { WILL_SEEN = null; } + + if (top) { + WILL_SEEN = null; + } } } // called whenever a property has just changed to update dependent keys function dependentKeysDidChange(obj, depKey, meta) { @@ -17239,37 +17292,59 @@ var deps; if (meta && meta.deps && (deps = meta.deps[depKey])) { var seen = DID_SEEN; var top = !seen; - if (top) { seen = DID_SEEN = {}; } + + if (top) { + seen = DID_SEEN = {}; + } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); - if (top) { DID_SEEN = null; } + + if (top) { + DID_SEEN = null; + } } } function keysOf(obj) { var keys = []; - for (var key in obj) keys.push(key); + + for (var key in obj) { + keys.push(key); + } + return keys; } function iterDeps(method, obj, deps, depKey, seen, meta) { var keys, key, i, desc; var guid = guidFor(obj); var current = seen[guid]; - if (!current) current = seen[guid] = {}; - if (current[depKey]) return; + + if (!current) { + current = seen[guid] = {}; + } + + if (current[depKey]) { + return; + } + current[depKey] = true; if (deps) { keys = keysOf(deps); var descs = meta.descs; for (i=0; i<keys.length; i++) { key = keys[i]; desc = descs[key]; - if (desc && desc._suspended === obj) continue; + + if (desc && desc._suspended === obj) { + continue; + } + method(obj, key); } } } @@ -17838,18 +17913,12 @@ then it will be looked up on the passed target. @param {Object} [args*] Any additional arguments you wish to pass to the method. @return {Object} Return value from invoking the passed function. Please note, when called within an existing loop, no return value is possible. */ - run.join = function(target, method /* args */) { - if (!run.currentRunLoop) { - return Ember.run.apply(Ember, arguments); - } - - var args = slice.call(arguments); - args.unshift('actions'); - run.schedule.apply(run, args); + run.join = function() { + return backburner.join.apply(backburner, arguments); }; /** Provides a useful utility for when integrating with non-Ember libraries that provide asynchronous callbacks. @@ -19652,11 +19721,12 @@ } }; function unwatchKey(obj, keyName, meta) { - var m = meta || metaFor(obj), watching = m.watching; + var m = meta || metaFor(obj); + var watching = m.watching; if (watching[keyName] === 1) { watching[keyName] = 0; var desc = m.descs[keyName]; @@ -25427,15 +25497,19 @@ view.appendTo(rootElement); } } function generateTopLevelTeardown(view) { - return function() { view.destroy(); }; + return function() { + view.destroy(); + }; } function generateOutletTeardown(parentView, outlet) { - return function() { parentView.disconnectOutlet(outlet); }; + return function() { + parentView.disconnectOutlet(outlet); + }; } function getFullQueryParams(router, state) { if (state.fullQueryParams) { return state.fullQueryParams; } @@ -28631,12 +28705,12 @@ ``` Then, create a view that binds to your new controller: ```handlebars - {{#each MyApp.listController}} - {{firstName}} {{lastName}} + {{#each person in MyApp.listController}} + {{person.firstName}} {{person.lastName}} {{/each}} ``` Although you are binding to the controller, the behavior of this controller is to pass through any methods or properties to the underlying array. This @@ -39118,11 +39192,11 @@ return result; }, _bubbleEvent: function(view, evt, eventName) { - return run(view, view.handleEvent, eventName, evt); + return run.join(view, view.handleEvent, eventName, evt); }, destroy: function() { var rootElement = get(this, 'rootElement'); jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); @@ -40741,9 +40815,33 @@ this.triggerAction({ action: actionName, actionContext: contexts }); + }, + + send: function(actionName) { + var args = [].slice.call(arguments, 1); + var target; + var hasAction = this._actions && this._actions[actionName]; + + if (hasAction) { + if (this._actions[actionName].apply(this, args) === true) { + // handler returned true, so this action will bubble + } else { + return; + } + } + + if (target = get(this, 'target')) { + Ember.assert("The `target` for " + this + " (" + target + + ") does not have a `send` method", typeof target.send === 'function'); + target.send.apply(target, arguments); + } else { + if (!hasAction) { + throw new Error(Ember.inspect(this) + ' had no action handler for: ' + actionName); + } + } } }); __exports__["default"] = Component; }); \ No newline at end of file