ember-rails 0.9.2 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -84,6 +84,8 @@ Default behavior for ember-rails is to precompile handlebars templates only in p
84
84
  If you don't want this behavior you can turn it off in your application configuration block :
85
85
 
86
86
  config.handlebars.precompile = false
87
+
88
+ (Remember to clear the local sprockets cache if you change the value of precompile, by default at `tmp/cache/assets`)
87
89
 
88
90
  Bundle all templates together thanks to Sprockets,
89
91
  e.g create `app/assets/javascripts/templates/all.js` with:
@@ -77,11 +77,11 @@ module Ember
77
77
 
78
78
  if root.kind_of? Array
79
79
  root.each do |root|
80
- path.gsub!(/^#{Regexp.quote(root)}\//, '')
80
+ path.sub!(/#{Regexp.quote(root)}\//, '')
81
81
  end
82
82
  else
83
83
  unless root.empty?
84
- path.gsub!(/^#{Regexp.quote(root)}\/?/, '')
84
+ path.sub!(/#{Regexp.quote(root)}\/?/, '')
85
85
  end
86
86
  end
87
87
 
@@ -1,5 +1,5 @@
1
1
  module Ember
2
2
  module Handlebars
3
- VERSION = "1.0.rc.2"
3
+ VERSION = "1.0.rc.3"
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Ember
2
2
  module Rails
3
- VERSION = '0.9.2'
3
+ VERSION = '0.10.0'
4
4
  end
5
5
  end
@@ -1,3 +1,3 @@
1
1
  module Ember
2
- VERSION = "1.0-pre.4"
2
+ VERSION = "1.0.0-rc.1"
3
3
  end
@@ -1,5 +1,5 @@
1
- // Version: v1.0.0-pre.3-19-g015138e
2
- // Last commit: 015138e (2013-01-17 23:02:17 -0800)
1
+ // Version: v1.0.0-pre.4-206-g4f2036f
2
+ // Last commit: 4f2036f (2013-02-12 17:02:00 +0100)
3
3
 
4
4
 
5
5
  (function() {
@@ -69,6 +69,21 @@ Ember.warn = function(message, test) {
69
69
  }
70
70
  };
71
71
 
72
+ /**
73
+ Display a debug notice. Ember build tools will remove any calls to
74
+ `Ember.debug()` when doing a production build.
75
+
76
+ ```javascript
77
+ Ember.debug("I'm a debug notice!");
78
+ ```
79
+
80
+ @method debug
81
+ @param {String} message A debug message to display.
82
+ */
83
+ Ember.debug = function(message) {
84
+ Ember.Logger.debug("DEBUG: "+message);
85
+ };
86
+
72
87
  /**
73
88
  Display a deprecation warning with the provided message and a stack trace
74
89
  (Chrome and Firefox only). Ember build tools will remove any calls to
@@ -133,17 +148,10 @@ Ember.deprecateFunc = function(message, func) {
133
148
  };
134
149
  };
135
150
 
136
- if ('undefined' !== typeof window) {
137
- window.ember_assert = Ember.deprecateFunc("ember_assert is deprecated. Please use Ember.assert instead.", Ember.assert);
138
- window.ember_warn = Ember.deprecateFunc("ember_warn is deprecated. Please use Ember.warn instead.", Ember.warn);
139
- window.ember_deprecate = Ember.deprecateFunc("ember_deprecate is deprecated. Please use Ember.deprecate instead.", Ember.deprecate);
140
- window.ember_deprecateFunc = Ember.deprecateFunc("ember_deprecateFunc is deprecated. Please use Ember.deprecateFunc instead.", Ember.deprecateFunc);
141
- }
142
-
143
151
  })();
144
152
 
145
- // Version: v1.0.0-pre.3-19-g015138e
146
- // Last commit: 015138e (2013-01-17 23:02:17 -0800)
153
+ // Version: v1.0.0-rc.1
154
+ // Last commit: 8b061b4 (2013-02-15 12:10:22 -0800)
147
155
 
148
156
 
149
157
  (function() {
@@ -203,7 +211,7 @@ var define, requireModule;
203
211
 
204
212
  @class Ember
205
213
  @static
206
- @version 1.0.0-pre.4
214
+ @version 1.0.0-rc.1
207
215
  */
208
216
 
209
217
  if ('undefined' === typeof Ember) {
@@ -230,10 +238,10 @@ Ember.toString = function() { return "Ember"; };
230
238
  /**
231
239
  @property VERSION
232
240
  @type String
233
- @default '1.0.0-pre.4'
241
+ @default '1.0.0-rc.1'
234
242
  @final
235
243
  */
236
- Ember.VERSION = '1.0.0-pre.4';
244
+ Ember.VERSION = '1.0.0-rc.1';
237
245
 
238
246
  /**
239
247
  Standard environmental variables. You can define these in a global `ENV`
@@ -303,20 +311,12 @@ Ember.K = function() { return this; };
303
311
 
304
312
  if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; }
305
313
  if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; }
314
+ if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; }
306
315
  if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; }
307
316
  if ('undefined' === typeof Ember.deprecateFunc) {
308
317
  Ember.deprecateFunc = function(_, func) { return func; };
309
318
  }
310
319
 
311
- // These are deprecated but still supported
312
-
313
- if ('undefined' === typeof ember_assert) { exports.ember_assert = Ember.K; }
314
- if ('undefined' === typeof ember_warn) { exports.ember_warn = Ember.K; }
315
- if ('undefined' === typeof ember_deprecate) { exports.ember_deprecate = Ember.K; }
316
- if ('undefined' === typeof ember_deprecateFunc) {
317
- exports.ember_deprecateFunc = function(_, func) { return func; };
318
- }
319
-
320
320
  /**
321
321
  Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from
322
322
  jQuery master. We'll just bootstrap our own uuid now.
@@ -331,14 +331,36 @@ Ember.uuid = 0;
331
331
  // LOGGER
332
332
  //
333
333
 
334
+ function consoleMethod(name) {
335
+ if (imports.console && imports.console[name]) {
336
+ // Older IE doesn't support apply, but Chrome needs it
337
+ if (imports.console[name].apply) {
338
+ return function() {
339
+ imports.console[name].apply(imports.console, arguments);
340
+ };
341
+ } else {
342
+ return function() {
343
+ var message = Array.prototype.join.call(arguments, ', ');
344
+ imports.console[name](message);
345
+ };
346
+ }
347
+ }
348
+ }
349
+
334
350
  /**
335
- Inside Ember-Metal, simply uses the `imports.console` object.
351
+ Inside Ember-Metal, simply uses the methods from `imports.console`.
336
352
  Override this to provide more robust logging functionality.
337
353
 
338
354
  @class Logger
339
355
  @namespace Ember
340
356
  */
341
- Ember.Logger = imports.console || { log: Ember.K, warn: Ember.K, error: Ember.K, info: Ember.K, debug: Ember.K };
357
+ Ember.Logger = {
358
+ log: consoleMethod('log') || Ember.K,
359
+ warn: consoleMethod('warn') || Ember.K,
360
+ error: consoleMethod('error') || Ember.K,
361
+ info: consoleMethod('info') || Ember.K,
362
+ debug: consoleMethod('debug') || consoleMethod('info') || Ember.K
363
+ };
342
364
 
343
365
 
344
366
  // ..........................................................
@@ -1257,8 +1279,63 @@ Ember.subscribe = Ember.Instrumentation.subscribe;
1257
1279
 
1258
1280
 
1259
1281
  (function() {
1260
- /*jshint newcap:false*/
1282
+ var utils = Ember.EnumerableUtils = {
1283
+ map: function(obj, callback, thisArg) {
1284
+ return obj.map ? obj.map.call(obj, callback, thisArg) : Array.prototype.map.call(obj, callback, thisArg);
1285
+ },
1286
+
1287
+ forEach: function(obj, callback, thisArg) {
1288
+ return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : Array.prototype.forEach.call(obj, callback, thisArg);
1289
+ },
1290
+
1291
+ indexOf: function(obj, element, index) {
1292
+ return obj.indexOf ? obj.indexOf.call(obj, element, index) : Array.prototype.indexOf.call(obj, element, index);
1293
+ },
1294
+
1295
+ indexesOf: function(obj, elements) {
1296
+ return elements === undefined ? [] : utils.map(elements, function(item) {
1297
+ return utils.indexOf(obj, item);
1298
+ });
1299
+ },
1300
+
1301
+ addObject: function(array, item) {
1302
+ var index = utils.indexOf(array, item);
1303
+ if (index === -1) { array.push(item); }
1304
+ },
1305
+
1306
+ removeObject: function(array, item) {
1307
+ var index = utils.indexOf(array, item);
1308
+ if (index !== -1) { array.splice(index, 1); }
1309
+ },
1310
+
1311
+ replace: function(array, idx, amt, objects) {
1312
+ if (array.replace) {
1313
+ return array.replace(idx, amt, objects);
1314
+ } else {
1315
+ var args = Array.prototype.concat.apply([idx, amt], objects);
1316
+ return array.splice.apply(array, args);
1317
+ }
1318
+ },
1319
+
1320
+ intersection: function(array1, array2) {
1321
+ var intersection = [];
1322
+
1323
+ array1.forEach(function(element) {
1324
+ if (array2.indexOf(element) >= 0) {
1325
+ intersection.push(element);
1326
+ }
1327
+ });
1328
+
1329
+ return intersection;
1330
+ }
1331
+ };
1332
+
1333
+ })();
1334
+
1261
1335
 
1336
+
1337
+ (function() {
1338
+ /*jshint newcap:false*/
1262
1339
  /**
1263
1340
  @module ember-metal
1264
1341
  */
@@ -1336,46 +1413,6 @@ Ember.ArrayPolyfills = {
1336
1413
  indexOf: arrayIndexOf
1337
1414
  };
1338
1415
 
1339
- var utils = Ember.EnumerableUtils = {
1340
- map: function(obj, callback, thisArg) {
1341
- return obj.map ? obj.map.call(obj, callback, thisArg) : arrayMap.call(obj, callback, thisArg);
1342
- },
1343
-
1344
- forEach: function(obj, callback, thisArg) {
1345
- return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : arrayForEach.call(obj, callback, thisArg);
1346
- },
1347
-
1348
- indexOf: function(obj, element, index) {
1349
- return obj.indexOf ? obj.indexOf.call(obj, element, index) : arrayIndexOf.call(obj, element, index);
1350
- },
1351
-
1352
- indexesOf: function(obj, elements) {
1353
- return elements === undefined ? [] : utils.map(elements, function(item) {
1354
- return utils.indexOf(obj, item);
1355
- });
1356
- },
1357
-
1358
- addObject: function(array, item) {
1359
- var index = utils.indexOf(array, item);
1360
- if (index === -1) { array.push(item); }
1361
- },
1362
-
1363
- removeObject: function(array, item) {
1364
- var index = utils.indexOf(array, item);
1365
- if (index !== -1) { array.splice(index, 1); }
1366
- },
1367
-
1368
- replace: function(array, idx, amt, objects) {
1369
- if (array.replace) {
1370
- return array.replace(idx, amt, objects);
1371
- } else {
1372
- var args = Array.prototype.concat.apply([idx, amt], objects);
1373
- return array.splice.apply(array, args);
1374
- }
1375
- }
1376
- };
1377
-
1378
-
1379
1416
  if (Ember.SHIM_ES5) {
1380
1417
  if (!Array.prototype.map) {
1381
1418
  Array.prototype.map = arrayMap;
@@ -2112,6 +2149,17 @@ var Descriptor = Ember.Descriptor = function() {};
2112
2149
  // DEFINING PROPERTIES API
2113
2150
  //
2114
2151
 
2152
+ var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) {
2153
+ Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false);
2154
+ };
2155
+
2156
+ var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) {
2157
+ return function() {
2158
+ var meta = this[META_KEY];
2159
+ return meta && meta.values[name];
2160
+ };
2161
+ };
2162
+
2115
2163
  /**
2116
2164
  @private
2117
2165
 
@@ -2195,13 +2243,8 @@ Ember.defineProperty = function(obj, keyName, desc, data, meta) {
2195
2243
  objectDefineProperty(obj, keyName, {
2196
2244
  configurable: true,
2197
2245
  enumerable: true,
2198
- set: function() {
2199
- Ember.assert('Must use Ember.set() to access this property', false);
2200
- },
2201
- get: function() {
2202
- var meta = this[META_KEY];
2203
- return meta && meta.values[keyName];
2204
- }
2246
+ set: MANDATORY_SETTER_FUNCTION,
2247
+ get: DEFAULT_GETTER_FUNCTION(keyName)
2205
2248
  });
2206
2249
  } else {
2207
2250
  obj[keyName] = data;
@@ -2926,13 +2969,8 @@ Ember.watch = function(obj, keyName) {
2926
2969
  o_defineProperty(obj, keyName, {
2927
2970
  configurable: true,
2928
2971
  enumerable: true,
2929
- set: function() {
2930
- Ember.assert('Must use Ember.set() to access this property', false);
2931
- },
2932
- get: function() {
2933
- var meta = this[META_KEY];
2934
- return meta && meta.values[keyName];
2935
- }
2972
+ set: Ember.MANDATORY_SETTER_FUNCTION,
2973
+ get: Ember.DEFAULT_GETTER_FUNCTION(keyName)
2936
2974
  });
2937
2975
  }
2938
2976
  } else {
@@ -5845,7 +5883,8 @@ define("rsvp",
5845
5883
  callbacks, callbackTuple, callback, binding, event;
5846
5884
 
5847
5885
  if (callbacks = allCallbacks[eventName]) {
5848
- for (var i=0, l=callbacks.length; i<l; i++) {
5886
+ // Don't cache the callbacks.length since it may grow
5887
+ for (var i=0; i<callbacks.length; i++) {
5849
5888
  callbackTuple = callbacks[i];
5850
5889
  callback = callbackTuple[0];
5851
5890
  binding = callbackTuple[1];
@@ -5963,9 +6002,41 @@ define("rsvp",
5963
6002
  });
5964
6003
  }
5965
6004
 
6005
+ function all(promises) {
6006
+ var i, results = [];
6007
+ var allPromise = new Promise();
6008
+ var remaining = promises.length;
6009
+
6010
+ if (remaining === 0) {
6011
+ allPromise.resolve([]);
6012
+ }
6013
+
6014
+ var resolver = function(index) {
6015
+ return function(value) {
6016
+ resolve(index, value);
6017
+ };
6018
+ };
6019
+
6020
+ var resolve = function(index, value) {
6021
+ results[index] = value;
6022
+ if (--remaining === 0) {
6023
+ allPromise.resolve(results);
6024
+ }
6025
+ };
6026
+
6027
+ var reject = function(error) {
6028
+ allPromise.reject(error);
6029
+ };
6030
+
6031
+ for (i = 0; i < remaining; i++) {
6032
+ promises[i].then(resolver(i), reject);
6033
+ }
6034
+ return allPromise;
6035
+ }
6036
+
5966
6037
  EventTarget.mixin(Promise.prototype);
5967
6038
 
5968
- RSVP = { async: async, Promise: Promise, Event: Event, EventTarget: EventTarget };
6039
+ RSVP = { async: async, Promise: Promise, Event: Event, EventTarget: EventTarget, all: all, raiseOnUncaughtExceptions: true };
5969
6040
  return RSVP;
5970
6041
  });
5971
6042
 
@@ -6036,10 +6107,10 @@ define("container",
6036
6107
  this.resolver = parent && parent.resolver || function() {};
6037
6108
  this.registry = new InheritingDict(parent && parent.registry);
6038
6109
  this.cache = new InheritingDict(parent && parent.cache);
6039
- this.typeInjections = {};
6110
+ this.typeInjections = new InheritingDict(parent && parent.typeInjections);
6040
6111
  this.injections = {};
6041
- this.options = {};
6042
- this.typeOptions = {};
6112
+ this._options = new InheritingDict(parent && parent._options);
6113
+ this._typeOptions = new InheritingDict(parent && parent._typeOptions);
6043
6114
  }
6044
6115
 
6045
6116
  Container.prototype = {
@@ -6054,8 +6125,20 @@ define("container",
6054
6125
  },
6055
6126
 
6056
6127
  register: function(type, name, factory, options) {
6057
- this.registry.set(type + ":" + name, factory);
6058
- this.options[type + ":" + name] = options || {};
6128
+ var fullName;
6129
+
6130
+
6131
+ if (type.indexOf(':') !== -1){
6132
+ options = factory;
6133
+ factory = name;
6134
+ fullName = type;
6135
+ } else {
6136
+ Ember.deprecate('register("'+type +'", "'+ name+'") is now deprecated in-favour of register("'+type+':'+name+'");', true);
6137
+ fullName = type + ":" + name;
6138
+ }
6139
+
6140
+ this.registry.set(fullName, factory);
6141
+ this._options.set(fullName, options || {});
6059
6142
  },
6060
6143
 
6061
6144
  resolve: function(fullName) {
@@ -6089,19 +6172,31 @@ define("container",
6089
6172
  optionsForType: function(type, options) {
6090
6173
  if (this.parent) { illegalChildOperation('optionsForType'); }
6091
6174
 
6092
- this.typeOptions[type] = options;
6175
+ this._typeOptions.set(type, options);
6176
+ },
6177
+
6178
+ options: function(type, options) {
6179
+ this.optionsForType(type, options);
6093
6180
  },
6094
6181
 
6095
6182
  typeInjection: function(type, property, fullName) {
6096
6183
  if (this.parent) { illegalChildOperation('typeInjection'); }
6097
6184
 
6098
- var injections = this.typeInjections[type] = this.typeInjections[type] || [];
6185
+ var injections = this.typeInjections.get(type);
6186
+ if (!injections) {
6187
+ injections = [];
6188
+ this.typeInjections.set(type, injections);
6189
+ }
6099
6190
  injections.push({ property: property, fullName: fullName });
6100
6191
  },
6101
6192
 
6102
6193
  injection: function(factoryName, property, injectionName) {
6103
6194
  if (this.parent) { illegalChildOperation('injection'); }
6104
6195
 
6196
+ if (factoryName.indexOf(':') === -1) {
6197
+ return this.typeInjection(factoryName, property, injectionName);
6198
+ }
6199
+
6105
6200
  var injections = this.injections[factoryName] = this.injections[factoryName] || [];
6106
6201
  injections.push({ property: property, fullName: injectionName });
6107
6202
  },
@@ -6162,14 +6257,14 @@ define("container",
6162
6257
  }
6163
6258
 
6164
6259
  function option(container, fullName, optionName) {
6165
- var options = container.options[fullName];
6260
+ var options = container._options.get(fullName);
6166
6261
 
6167
6262
  if (options && options[optionName] !== undefined) {
6168
6263
  return options[optionName];
6169
6264
  }
6170
6265
 
6171
6266
  var type = fullName.split(":")[0];
6172
- options = container.typeOptions[type];
6267
+ options = container._typeOptions.get(type);
6173
6268
 
6174
6269
  if (options) {
6175
6270
  return options[optionName];
@@ -6193,11 +6288,12 @@ define("container",
6193
6288
 
6194
6289
  if (factory) {
6195
6290
  var injections = [];
6196
- injections = injections.concat(container.typeInjections[type] || []);
6291
+ injections = injections.concat(container.typeInjections.get(type) || []);
6197
6292
  injections = injections.concat(container.injections[fullName] || []);
6198
6293
 
6199
6294
  var hash = buildInjections(container, injections);
6200
6295
  hash.container = container;
6296
+ hash._debugContainerKey = fullName;
6201
6297
 
6202
6298
  value = factory.create(hash);
6203
6299
 
@@ -6373,7 +6469,7 @@ Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.i
6373
6469
  Ember.compare('hello', 'hello'); // 0
6374
6470
  Ember.compare('abc', 'dfg'); // -1
6375
6471
  Ember.compare(2, 1); // 1
6376
- ```javascript
6472
+ ```
6377
6473
 
6378
6474
  @method compare
6379
6475
  @for Ember
@@ -7587,7 +7683,7 @@ Ember.Enumerable = Ember.Mixin.create(
7587
7683
  @method find
7588
7684
  @param {Function} callback The callback to execute
7589
7685
  @param {Object} [target] The target object to use
7590
- @return {Object} Found item or `null`.
7686
+ @return {Object} Found item or `undefined`.
7591
7687
  */
7592
7688
  find: function(callback, target) {
7593
7689
  var len = get(this, 'length') ;
@@ -7615,7 +7711,7 @@ Ember.Enumerable = Ember.Mixin.create(
7615
7711
  @method findProperty
7616
7712
  @param {String} key the property to test
7617
7713
  @param {String} [value] optional value to test against.
7618
- @return {Object} found item or `null`
7714
+ @return {Object} found item or `undefined`
7619
7715
  */
7620
7716
  findProperty: function(key, value) {
7621
7717
  return this.find(iter.apply(this, arguments));
@@ -7675,7 +7771,7 @@ Ember.Enumerable = Ember.Mixin.create(
7675
7771
 
7676
7772
  /**
7677
7773
  Returns `true` if the passed function returns true for any item in the
7678
- enumeration. This corresponds with the `every()` method in JavaScript 1.6.
7774
+ enumeration. This corresponds with the `some()` method in JavaScript 1.6.
7679
7775
 
7680
7776
  The callback method you provide should have the following signature (all
7681
7777
  parameters are optional):
@@ -8195,7 +8291,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8195
8291
  arr.indexOf("a", -1); // 4
8196
8292
  arr.indexOf("b", 3); // -1
8197
8293
  arr.indexOf("a", 100); // -1
8198
- ```javascript
8294
+ ```
8199
8295
 
8200
8296
  @method indexOf
8201
8297
  @param {Object} object the item to search for
@@ -8840,7 +8936,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
8840
8936
  var colors = ["red", "green", "blue"];
8841
8937
  colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"]
8842
8938
  colors.insertAt(5, "orange"); // Error: Index out of range
8843
- ```javascript
8939
+ ```
8844
8940
 
8845
8941
  @method insertAt
8846
8942
  @param {Number} idx index of insert the object at.
@@ -9141,9 +9237,6 @@ var get = Ember.get, set = Ember.set, defineProperty = Ember.defineProperty;
9141
9237
  */
9142
9238
  Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
9143
9239
 
9144
- // compatibility
9145
- isObserverable: true,
9146
-
9147
9240
  /**
9148
9241
  Retrieves the value of a property from the object.
9149
9242
 
@@ -9730,7 +9823,7 @@ Ember.Evented = Ember.Mixin.create({
9730
9823
  event.
9731
9824
 
9732
9825
  ```javascript
9733
- person.on('didEat', food) {
9826
+ person.on('didEat', function(food) {
9734
9827
  console.log('person ate some ' + food);
9735
9828
  });
9736
9829
 
@@ -10010,9 +10103,9 @@ function makeCtor() {
10010
10103
  }
10011
10104
 
10012
10105
  var CoreObject = makeCtor();
10106
+ CoreObject.toString = function() { return "Ember.CoreObject"; };
10013
10107
 
10014
10108
  CoreObject.PrototypeMixin = Mixin.create({
10015
-
10016
10109
  reopen: function() {
10017
10110
  applyMixin(this, arguments, true);
10018
10111
  return this;
@@ -10113,9 +10206,10 @@ CoreObject.PrototypeMixin = Mixin.create({
10113
10206
  @return {Ember.Object} receiver
10114
10207
  */
10115
10208
  destroy: function() {
10116
- if (this.isDestroying) { return; }
10209
+ if (this._didCallDestroy) { return; }
10117
10210
 
10118
10211
  this.isDestroying = true;
10212
+ this._didCallDestroy = true;
10119
10213
 
10120
10214
  if (this.willDestroy) { this.willDestroy(); }
10121
10215
 
@@ -10183,6 +10277,8 @@ CoreObject.PrototypeMixin = Mixin.create({
10183
10277
  }
10184
10278
  });
10185
10279
 
10280
+ CoreObject.PrototypeMixin.ownerConstructor = CoreObject;
10281
+
10186
10282
  function makeToString(ret) {
10187
10283
  return function() { return ret; };
10188
10284
  }
@@ -10321,6 +10417,8 @@ var ClassMixin = Mixin.create({
10321
10417
 
10322
10418
  });
10323
10419
 
10420
+ ClassMixin.ownerConstructor = CoreObject;
10421
+
10324
10422
  if (Ember.config.overrideClassMixin) {
10325
10423
  Ember.config.overrideClassMixin(ClassMixin);
10326
10424
  }
@@ -10812,6 +10910,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
10812
10910
  @uses Ember.Observable
10813
10911
  */
10814
10912
  Ember.Object = Ember.CoreObject.extend(Ember.Observable);
10913
+ Ember.Object.toString = function() { return "Ember.Object"; };
10815
10914
 
10816
10915
  })();
10817
10916
 
@@ -10872,16 +10971,28 @@ var Namespace = Ember.Namespace = Ember.Object.extend({
10872
10971
 
10873
10972
  Namespace.reopenClass({
10874
10973
  NAMESPACES: [Ember],
10974
+ NAMESPACES_BY_ID: {},
10875
10975
  PROCESSED: false,
10876
- processAll: processAllNamespaces
10976
+ processAll: processAllNamespaces,
10977
+ byName: function(name) {
10978
+ if (!Ember.BOOTED) {
10979
+ processAllNamespaces();
10980
+ }
10981
+
10982
+ return NAMESPACES_BY_ID[name];
10983
+ }
10877
10984
  });
10878
10985
 
10986
+ var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
10987
+
10879
10988
  var hasOwnProp = ({}).hasOwnProperty,
10880
10989
  guidFor = Ember.guidFor;
10881
10990
 
10882
10991
  function processNamespace(paths, root, seen) {
10883
10992
  var idx = paths.length;
10884
10993
 
10994
+ NAMESPACES_BY_ID[paths.join('.')] = root;
10995
+
10885
10996
  // Loop over all of the keys in the namespace, looking for classes
10886
10997
  for(var key in root) {
10887
10998
  if (!hasOwnProp.call(root, key)) { continue; }
@@ -10981,12 +11092,15 @@ function classToString() {
10981
11092
  }
10982
11093
 
10983
11094
  function processAllNamespaces() {
10984
- if (!Namespace.PROCESSED) {
11095
+ var unprocessedNamespaces = !Namespace.PROCESSED,
11096
+ unprocessedMixins = Ember.anyUnprocessedMixins;
11097
+
11098
+ if (unprocessedNamespaces) {
10985
11099
  findNamespaces();
10986
11100
  Namespace.PROCESSED = true;
10987
11101
  }
10988
11102
 
10989
- if (Ember.anyUnprocessedMixins) {
11103
+ if (unprocessedNamespaces || unprocessedMixins) {
10990
11104
  var namespaces = Namespace.NAMESPACES, namespace;
10991
11105
  for (var i=0, l=namespaces.length; i<l; i++) {
10992
11106
  namespace = namespaces[i];
@@ -11112,9 +11226,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
11112
11226
 
11113
11227
  @property arrangedContent
11114
11228
  */
11115
- arrangedContent: Ember.computed('content', function() {
11116
- return get(this, 'content');
11117
- }),
11229
+ arrangedContent: Ember.computed.alias('content'),
11118
11230
 
11119
11231
  /**
11120
11232
  Should actually retrieve the object at the specified index from the
@@ -11399,6 +11511,10 @@ Ember.ObjectProxy = Ember.Object.extend(
11399
11511
  Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this);
11400
11512
  }, 'content'),
11401
11513
 
11514
+ isTruthy: Ember.computed.bool('content'),
11515
+
11516
+ _debugContainerKey: null,
11517
+
11402
11518
  willWatchProperty: function (key) {
11403
11519
  var contentKey = 'content.' + key;
11404
11520
  addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
@@ -11823,7 +11939,7 @@ Ember.Deferred = Deferred;
11823
11939
  @submodule ember-runtime
11824
11940
  */
11825
11941
 
11826
- var loadHooks = {};
11942
+ var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {};
11827
11943
  var loaded = {};
11828
11944
 
11829
11945
  /**
@@ -11910,6 +12026,9 @@ var get = Ember.get;
11910
12026
  @extends Ember.Mixin
11911
12027
  */
11912
12028
  Ember.ControllerMixin = Ember.Mixin.create({
12029
+ /* ducktype as a controller */
12030
+ isController: true,
12031
+
11913
12032
  /**
11914
12033
  The object to which events from the view should be sent.
11915
12034
 
@@ -11928,6 +12047,8 @@ Ember.ControllerMixin = Ember.Mixin.create({
11928
12047
 
11929
12048
  store: null,
11930
12049
 
12050
+ model: Ember.computed.alias('content'),
12051
+
11931
12052
  send: function(actionName) {
11932
12053
  var args = [].slice.call(arguments, 1), target;
11933
12054
 
@@ -11976,7 +12097,8 @@ var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
11976
12097
 
11977
12098
  songsController = Ember.ArrayController.create({
11978
12099
  content: songs,
11979
- sortProperties: ['trackNumber']
12100
+ sortProperties: ['trackNumber'],
12101
+ sortAscending: true
11980
12102
  });
11981
12103
 
11982
12104
  songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'}
@@ -11991,7 +12113,19 @@ var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
11991
12113
  @uses Ember.MutableEnumerable
11992
12114
  */
11993
12115
  Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
12116
+
12117
+ /**
12118
+ Specifies which properties dictate the arrangedContent's sort order.
12119
+
12120
+ @property {Array} sortProperties
12121
+ */
11994
12122
  sortProperties: null,
12123
+
12124
+ /**
12125
+ Specifies the arrangedContent's sort direction
12126
+
12127
+ @property {Boolean} sortAscending
12128
+ */
11995
12129
  sortAscending: true,
11996
12130
 
11997
12131
  orderBy: function(item1, item2) {
@@ -12028,9 +12162,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
12028
12162
  return this._super();
12029
12163
  },
12030
12164
 
12031
- isSorted: Ember.computed('sortProperties', function() {
12032
- return !!get(this, 'sortProperties');
12033
- }),
12165
+ isSorted: Ember.computed.bool('sortProperties'),
12034
12166
 
12035
12167
  arrangedContent: Ember.computed('content', 'sortProperties.@each', function(key, value) {
12036
12168
  var content = get(this, 'content'),
@@ -12305,20 +12437,22 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
12305
12437
 
12306
12438
  objectAtContent: function(idx) {
12307
12439
  var length = get(this, 'length'),
12308
- object = get(this,'arrangedContent').objectAt(idx),
12309
- controllerClass = this.lookupItemController(object);
12440
+ object = get(this,'arrangedContent').objectAt(idx);
12310
12441
 
12311
- if (controllerClass && idx < length) {
12312
- return this.controllerAt(idx, object, controllerClass);
12313
- } else {
12314
- // When controllerClass is falsy we have not opted in to using item
12315
- // controllers, so return the object directly. However, when
12316
- // controllerClass is defined but the index is out of range, we want to
12317
- // return the "out of range" value, whatever that might be. Rather than
12318
- // make assumptions (e.g. guessing `null` or `undefined`) we defer this to
12319
- // `arrangedContent`.
12320
- return object;
12442
+ if (idx >= 0 && idx < length) {
12443
+ var controllerClass = this.lookupItemController(object);
12444
+ if (controllerClass) {
12445
+ return this.controllerAt(idx, object, controllerClass);
12446
+ }
12321
12447
  }
12448
+
12449
+ // When `controllerClass` is falsy, we have not opted in to using item
12450
+ // controllers, so return the object directly.
12451
+
12452
+ // When the index is out of range, we want to return the "out of range"
12453
+ // value, whatever that might be. Rather than make assumptions
12454
+ // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`.
12455
+ return object;
12322
12456
  },
12323
12457
 
12324
12458
  arrangedContentDidChange: function() {
@@ -12344,6 +12478,7 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
12344
12478
 
12345
12479
  init: function() {
12346
12480
  this._super();
12481
+ if (!this.get('content')) { this.set('content', Ember.A()); }
12347
12482
  this._resetSubContainers();
12348
12483
  },
12349
12484
 
@@ -12437,7 +12572,7 @@ Ember Runtime
12437
12572
  */
12438
12573
 
12439
12574
  var jQuery = Ember.imports.jQuery;
12440
- Ember.assert("Ember Views require jQuery 1.7 (>= 1.7.2), 1.8 or 1.9", jQuery && (jQuery().jquery.match(/^1\.(7(?!$)(?!\.[01])|8|9)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));
12575
+ Ember.assert("Ember Views require jQuery 1.8 or 1.9", jQuery && (jQuery().jquery.match(/^1\.(8|9)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));
12441
12576
 
12442
12577
  /**
12443
12578
  Alias for jQuery
@@ -12716,6 +12851,21 @@ Ember._RenderBuffer.prototype =
12716
12851
  */
12717
12852
  elementAttributes: null,
12718
12853
 
12854
+ /**
12855
+ A hash keyed on the name of the properties and whose value will be
12856
+ applied to that property. For example, if you wanted to apply a
12857
+ `checked=true` property to an element, you would set the
12858
+ elementProperties hash to `{'checked':true}`.
12859
+
12860
+ You should not maintain this hash yourself, rather, you should use
12861
+ the `prop()` method of `Ember.RenderBuffer`.
12862
+
12863
+ @property elementProperties
12864
+ @type Hash
12865
+ @default {}
12866
+ */
12867
+ elementProperties: null,
12868
+
12719
12869
  /**
12720
12870
  The tagname of the element an instance of `Ember.RenderBuffer` represents.
12721
12871
 
@@ -12838,6 +12988,41 @@ Ember._RenderBuffer.prototype =
12838
12988
  return this;
12839
12989
  },
12840
12990
 
12991
+ /**
12992
+ Adds an property which will be rendered to the element.
12993
+
12994
+ @method prop
12995
+ @param {String} name The name of the property
12996
+ @param {String} value The value to add to the property
12997
+ @chainable
12998
+ @return {Ember.RenderBuffer|String} this or the current property value
12999
+ */
13000
+ prop: function(name, value) {
13001
+ var properties = this.elementProperties = (this.elementProperties || {});
13002
+
13003
+ if (arguments.length === 1) {
13004
+ return properties[name];
13005
+ } else {
13006
+ properties[name] = value;
13007
+ }
13008
+
13009
+ return this;
13010
+ },
13011
+
13012
+ /**
13013
+ Remove an property from the list of properties to render.
13014
+
13015
+ @method removeProp
13016
+ @param {String} name The name of the property
13017
+ @chainable
13018
+ */
13019
+ removeProp: function(name) {
13020
+ var properties = this.elementProperties;
13021
+ if (properties) { delete properties[name]; }
13022
+
13023
+ return this;
13024
+ },
13025
+
12841
13026
  /**
12842
13027
  Adds a style to the style attribute which will be rendered to the element.
12843
13028
 
@@ -12871,8 +13056,9 @@ Ember._RenderBuffer.prototype =
12871
13056
  id = this.elementId,
12872
13057
  classes = this.classes,
12873
13058
  attrs = this.elementAttributes,
13059
+ props = this.elementProperties,
12874
13060
  style = this.elementStyle,
12875
- prop;
13061
+ attr, prop;
12876
13062
 
12877
13063
  buffer.push('<' + tagName);
12878
13064
 
@@ -12900,15 +13086,32 @@ Ember._RenderBuffer.prototype =
12900
13086
  }
12901
13087
 
12902
13088
  if (attrs) {
12903
- for (prop in attrs) {
12904
- if (attrs.hasOwnProperty(prop)) {
12905
- buffer.push(' ' + prop + '="' + this._escapeAttribute(attrs[prop]) + '"');
13089
+ for (attr in attrs) {
13090
+ if (attrs.hasOwnProperty(attr)) {
13091
+ buffer.push(' ' + attr + '="' + this._escapeAttribute(attrs[attr]) + '"');
12906
13092
  }
12907
13093
  }
12908
13094
 
12909
13095
  this.elementAttributes = null;
12910
13096
  }
12911
13097
 
13098
+ if (props) {
13099
+ for (prop in props) {
13100
+ if (props.hasOwnProperty(prop)) {
13101
+ var value = props[prop];
13102
+ if (value || typeof(value) === 'number') {
13103
+ if (value === true) {
13104
+ buffer.push(' ' + prop + '="' + prop + '"');
13105
+ } else {
13106
+ buffer.push(' ' + prop + '="' + this._escapeAttribute(props[prop]) + '"');
13107
+ }
13108
+ }
13109
+ }
13110
+ }
13111
+
13112
+ this.elementProperties = null;
13113
+ }
13114
+
12912
13115
  buffer.push('>');
12913
13116
  },
12914
13117
 
@@ -12928,8 +13131,9 @@ Ember._RenderBuffer.prototype =
12928
13131
  id = this.elementId,
12929
13132
  classes = this.classes,
12930
13133
  attrs = this.elementAttributes,
13134
+ props = this.elementProperties,
12931
13135
  style = this.elementStyle,
12932
- styleBuffer = '', prop;
13136
+ styleBuffer = '', attr, prop;
12933
13137
 
12934
13138
  if (id) {
12935
13139
  $element.attr('id', id);
@@ -12953,15 +13157,25 @@ Ember._RenderBuffer.prototype =
12953
13157
  }
12954
13158
 
12955
13159
  if (attrs) {
12956
- for (prop in attrs) {
12957
- if (attrs.hasOwnProperty(prop)) {
12958
- $element.attr(prop, attrs[prop]);
13160
+ for (attr in attrs) {
13161
+ if (attrs.hasOwnProperty(attr)) {
13162
+ $element.attr(attr, attrs[attr]);
12959
13163
  }
12960
13164
  }
12961
13165
 
12962
13166
  this.elementAttributes = null;
12963
13167
  }
12964
13168
 
13169
+ if (props) {
13170
+ for (prop in props) {
13171
+ if (props.hasOwnProperty(prop)) {
13172
+ $element.prop(prop, props[prop]);
13173
+ }
13174
+ }
13175
+
13176
+ this.elementProperties = null;
13177
+ }
13178
+
12965
13179
  return element;
12966
13180
  },
12967
13181
 
@@ -13177,11 +13391,13 @@ Ember.EventDispatcher = Ember.Object.extend(
13177
13391
  rootElement.delegate('[data-ember-action]', event + '.ember', function(evt) {
13178
13392
  return Ember.handleErrors(function() {
13179
13393
  var actionId = Ember.$(evt.currentTarget).attr('data-ember-action'),
13180
- action = Ember.Handlebars.ActionHelper.registeredActions[actionId],
13181
- handler = action.handler;
13394
+ action = Ember.Handlebars.ActionHelper.registeredActions[actionId];
13182
13395
 
13183
- if (action.eventName === eventName) {
13184
- return handler(evt);
13396
+ // We have to check for action here since in some cases, jQuery will trigger
13397
+ // an event on `removeChild` (i.e. focusout) after we've already torn down the
13398
+ // action handlers for the view.
13399
+ if (action && action.eventName === eventName) {
13400
+ return action.handler(evt);
13185
13401
  }
13186
13402
  }, this);
13187
13403
  });
@@ -13270,7 +13486,25 @@ Ember.ControllerMixin.reopen({
13270
13486
  target: null,
13271
13487
  namespace: null,
13272
13488
  view: null,
13273
- container: null
13489
+ container: null,
13490
+ _childContainers: null,
13491
+
13492
+ init: function() {
13493
+ this._super();
13494
+ set(this, '_childContainers', {});
13495
+ },
13496
+
13497
+ _modelDidChange: Ember.observer(function() {
13498
+ var containers = get(this, '_childContainers'),
13499
+ container;
13500
+
13501
+ for (var prop in containers) {
13502
+ if (!containers.hasOwnProperty(prop)) { continue; }
13503
+ containers[prop].destroy();
13504
+ }
13505
+
13506
+ set(this, '_childContainers', {});
13507
+ }, 'model')
13274
13508
  });
13275
13509
 
13276
13510
  })();
@@ -13298,9 +13532,7 @@ var a_forEach = Ember.EnumerableUtils.forEach;
13298
13532
  var a_addObject = Ember.EnumerableUtils.addObject;
13299
13533
 
13300
13534
  var childViewsProperty = Ember.computed(function() {
13301
- var childViews = this._childViews;
13302
-
13303
- var ret = Ember.A();
13535
+ var childViews = this._childViews, ret = Ember.A(), view = this;
13304
13536
 
13305
13537
  a_forEach(childViews, function(view) {
13306
13538
  if (view.isVirtual) {
@@ -13310,6 +13542,14 @@ var childViewsProperty = Ember.computed(function() {
13310
13542
  }
13311
13543
  });
13312
13544
 
13545
+ ret.replace = function (idx, removedCount, addedViews) {
13546
+ if (view instanceof Ember.ContainerView) {
13547
+ Ember.deprecate("Manipulating a Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray.");
13548
+ return view.replace(idx, removedCount, addedViews);
13549
+ }
13550
+ throw new Error("childViews is immutable");
13551
+ };
13552
+
13313
13553
  return ret;
13314
13554
  });
13315
13555
 
@@ -13336,7 +13576,10 @@ Ember.CoreView = Ember.Object.extend(Ember.Evented, {
13336
13576
 
13337
13577
  // Register the view for event handling. This hash is used by
13338
13578
  // Ember.EventDispatcher to dispatch incoming events.
13339
- if (!this.isVirtual) Ember.View.views[this.elementId] = this;
13579
+ if (!this.isVirtual) {
13580
+ Ember.assert("Attempted to register a view with an id already in use: "+this.elementId, !Ember.View.views[this.elementId]);
13581
+ Ember.View.views[this.elementId] = this;
13582
+ }
13340
13583
 
13341
13584
  this.addBeforeObserver('elementId', function() {
13342
13585
  throw new Error("Changing a view's elementId after creation is not allowed");
@@ -14103,6 +14346,8 @@ Ember.View = Ember.CoreView.extend(
14103
14346
  var templateName = get(this, 'templateName'),
14104
14347
  template = this.templateForName(templateName, 'template');
14105
14348
 
14349
+ Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template);
14350
+
14106
14351
  return template || get(this, 'defaultTemplate');
14107
14352
  }).property('templateName'),
14108
14353
 
@@ -14144,6 +14389,8 @@ Ember.View = Ember.CoreView.extend(
14144
14389
  var layoutName = get(this, 'layoutName'),
14145
14390
  layout = this.templateForName(layoutName, 'layout');
14146
14391
 
14392
+ Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout);
14393
+
14147
14394
  return layout || get(this, 'defaultLayout');
14148
14395
  }).property('layoutName'),
14149
14396
 
@@ -14522,11 +14769,16 @@ Ember.View = Ember.CoreView.extend(
14522
14769
  oldClass = dasherizedClass;
14523
14770
  }
14524
14771
 
14525
- addObserver(this, parsedPath.path, observer);
14526
-
14772
+ this.registerObserver(this, parsedPath.path, observer);
14773
+ // Remove className so when the view is rerendered,
14774
+ // the className is added based on binding reevaluation
14527
14775
  this.one('willClearRender', function() {
14528
- removeObserver(this, parsedPath.path, observer);
14776
+ if (oldClass) {
14777
+ classNames.removeObject(oldClass);
14778
+ oldClass = null;
14779
+ }
14529
14780
  });
14781
+
14530
14782
  }, this);
14531
14783
  },
14532
14784
 
@@ -14558,11 +14810,7 @@ Ember.View = Ember.CoreView.extend(
14558
14810
  Ember.View.applyAttributeBindings(elem, attributeName, attributeValue);
14559
14811
  };
14560
14812
 
14561
- addObserver(this, property, observer);
14562
-
14563
- this.one('willClearRender', function() {
14564
- removeObserver(this, property, observer);
14565
- });
14813
+ this.registerObserver(this, property, observer);
14566
14814
 
14567
14815
  // Determine the current value and add it to the render buffer
14568
14816
  // if necessary.
@@ -14773,7 +15021,7 @@ Ember.View = Ember.CoreView.extend(
14773
15021
  // element.
14774
15022
  // In the interim, we will just re-render if that happens. It is more
14775
15023
  // important than elements get garbage collected.
14776
- this.destroyElement();
15024
+ if (!this.removedFromDOM) { this.destroyElement(); }
14777
15025
  this.invokeRecursively(function(view) {
14778
15026
  if (view.clearRenderedChildren) { view.clearRenderedChildren(); }
14779
15027
  });
@@ -15248,12 +15496,17 @@ Ember.View = Ember.CoreView.extend(
15248
15496
  // so collect any information we need before calling super.
15249
15497
  var childViews = this._childViews,
15250
15498
  parent = this._parentView,
15251
- childLen;
15499
+ childLen, i;
15252
15500
 
15253
15501
  // destroy the element -- this will avoid each child view destroying
15254
15502
  // the element over and over again...
15255
15503
  if (!this.removedFromDOM) { this.destroyElement(); }
15256
15504
 
15505
+ childLen = childViews.length;
15506
+ for (i=childLen-1; i>=0; i--) {
15507
+ childViews[i].removedFromDOM = true;
15508
+ }
15509
+
15257
15510
  // remove from non-virtual parent view if viewName was specified
15258
15511
  if (this.viewName) {
15259
15512
  var nonVirtualParentView = get(this, 'parentView');
@@ -15270,8 +15523,7 @@ Ember.View = Ember.CoreView.extend(
15270
15523
  this.transitionTo('destroyed');
15271
15524
 
15272
15525
  childLen = childViews.length;
15273
- for (var i=childLen-1; i>=0; i--) {
15274
- childViews[i].removedFromDOM = true;
15526
+ for (i=childLen-1; i>=0; i--) {
15275
15527
  childViews[i].destroy();
15276
15528
  }
15277
15529
 
@@ -15416,6 +15668,14 @@ Ember.View = Ember.CoreView.extend(
15416
15668
  */
15417
15669
  handleEvent: function(eventName, evt) {
15418
15670
  return this.currentState.handleEvent(this, eventName, evt);
15671
+ },
15672
+
15673
+ registerObserver: function(root, path, target, observer) {
15674
+ Ember.addObserver(root, path, target, observer);
15675
+
15676
+ this.one('willClearRender', function() {
15677
+ Ember.removeObserver(root, path, target, observer);
15678
+ });
15419
15679
  }
15420
15680
 
15421
15681
  });
@@ -15606,13 +15866,17 @@ Ember.View.childViewsProperty = childViewsProperty;
15606
15866
 
15607
15867
  Ember.View.applyAttributeBindings = function(elem, name, value) {
15608
15868
  var type = Ember.typeOf(value);
15609
- var currentValue = elem.attr(name);
15610
15869
 
15611
15870
  // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js
15612
- if ((type === 'string' || (type === 'number' && !isNaN(value))) && value !== currentValue) {
15613
- elem.attr(name, value);
15614
- } else if (value && type === 'boolean') {
15615
- elem.attr(name, name);
15871
+ if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) {
15872
+ if (value !== elem.attr(name)) {
15873
+ elem.attr(name, value);
15874
+ }
15875
+ } else if (name === 'value' || type === 'boolean') {
15876
+ if (value !== elem.prop(name)) {
15877
+ // value and booleans should always be properties
15878
+ elem.prop(name, value);
15879
+ }
15616
15880
  } else if (!value) {
15617
15881
  elem.removeAttr(name);
15618
15882
  }
@@ -15965,14 +16229,9 @@ var states = Ember.View.cloneStates(Ember.View.states);
15965
16229
  var get = Ember.get, set = Ember.set, meta = Ember.meta;
15966
16230
  var forEach = Ember.EnumerableUtils.forEach;
15967
16231
 
15968
- var childViewsProperty = Ember.computed(function() {
15969
- return get(this, '_childViews');
15970
- }).property('_childViews');
15971
-
15972
16232
  /**
15973
- A `ContainerView` is an `Ember.View` subclass that allows for manual or
15974
- programatic management of a view's `childViews` array that will correctly
15975
- update the `ContainerView` instance's rendered DOM representation.
16233
+ A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray`
16234
+ allowing programatic management of its child views.
15976
16235
 
15977
16236
  ## Setting Initial Child Views
15978
16237
 
@@ -16012,11 +16271,9 @@ var childViewsProperty = Ember.computed(function() {
16012
16271
 
16013
16272
  ## Adding and Removing Child Views
16014
16273
 
16015
- The views in a container's `childViews` array should be added and removed by
16016
- manipulating the `childViews` property directly.
16274
+ The container view implements `Ember.MutableArray` allowing programatic management of its child views.
16017
16275
 
16018
- To remove a view pass that view into a `removeObject` call on the container's
16019
- `childViews` property.
16276
+ To remove a view, pass that view into a `removeObject` call on the container view.
16020
16277
 
16021
16278
  Given an empty `<body>` the following code
16022
16279
 
@@ -16047,9 +16304,9 @@ var childViewsProperty = Ember.computed(function() {
16047
16304
  Removing a view
16048
16305
 
16049
16306
  ```javascript
16050
- aContainer.get('childViews'); // [aContainer.aView, aContainer.bView]
16051
- aContainer.get('childViews').removeObject(aContainer.get('bView'));
16052
- aContainer.get('childViews'); // [aContainer.aView]
16307
+ aContainer.toArray(); // [aContainer.aView, aContainer.bView]
16308
+ aContainer.removeObject(aContainer.get('bView'));
16309
+ aContainer.toArray(); // [aContainer.aView]
16053
16310
  ```
16054
16311
 
16055
16312
  Will result in the following HTML
@@ -16061,7 +16318,7 @@ var childViewsProperty = Ember.computed(function() {
16061
16318
  ```
16062
16319
 
16063
16320
  Similarly, adding a child view is accomplished by adding `Ember.View` instances to the
16064
- container's `childViews` property.
16321
+ container view.
16065
16322
 
16066
16323
  Given an empty `<body>` the following code
16067
16324
 
@@ -16096,9 +16353,9 @@ var childViewsProperty = Ember.computed(function() {
16096
16353
  template: Ember.Handlebars.compile("Another view")
16097
16354
  });
16098
16355
 
16099
- aContainer.get('childViews'); // [aContainer.aView, aContainer.bView]
16100
- aContainer.get('childViews').pushObject(AnotherViewClass.create());
16101
- aContainer.get('childViews'); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>]
16356
+ aContainer.toArray(); // [aContainer.aView, aContainer.bView]
16357
+ aContainer.pushObject(AnotherViewClass.create());
16358
+ aContainer.toArray(); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>]
16102
16359
  ```
16103
16360
 
16104
16361
  Will result in the following HTML
@@ -16111,57 +16368,7 @@ var childViewsProperty = Ember.computed(function() {
16111
16368
  </div>
16112
16369
  ```
16113
16370
 
16114
- Direct manipulation of `childViews` presence or absence in the DOM via calls
16115
- to `remove` or `removeFromParent` or calls to a container's `removeChild` may
16116
- not behave correctly.
16117
-
16118
- Calling `remove()` on a child view will remove the view's HTML, but it will
16119
- remain as part of its container's `childView`s property.
16120
-
16121
- Calling `removeChild()` on the container will remove the passed view instance
16122
- from the container's `childView`s but keep its HTML within the container's
16123
- rendered view.
16124
-
16125
- Calling `removeFromParent()` behaves as expected but should be avoided in
16126
- favor of direct manipulation of a container's `childViews` property.
16127
-
16128
- ```javascript
16129
- aContainer = Ember.ContainerView.create({
16130
- classNames: ['the-container'],
16131
- childViews: ['aView', 'bView'],
16132
- aView: Ember.View.create({
16133
- template: Ember.Handlebars.compile("A")
16134
- }),
16135
- bView: Ember.View.create({
16136
- template: Ember.Handlebars.compile("B")
16137
- })
16138
- });
16139
-
16140
- aContainer.appendTo('body');
16141
- ```
16142
-
16143
- Results in the HTML
16144
-
16145
- ```html
16146
- <div class="ember-view the-container">
16147
- <div class="ember-view">A</div>
16148
- <div class="ember-view">B</div>
16149
- </div>
16150
- ```
16151
-
16152
- Calling `aContainer.get('aView').removeFromParent()` will result in the
16153
- following HTML
16154
-
16155
- ```html
16156
- <div class="ember-view the-container">
16157
- <div class="ember-view">B</div>
16158
- </div>
16159
- ```
16160
-
16161
- And the `Ember.View` instance stored in `aContainer.aView` will be removed from `aContainer`'s
16162
- `childViews` array.
16163
-
16164
- ## Templates and Layout
16371
+ ## Templates and Layout
16165
16372
 
16166
16373
  A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or
16167
16374
  `defaultLayout` property on a container view will not result in the template
@@ -16172,10 +16379,9 @@ var childViewsProperty = Ember.computed(function() {
16172
16379
 
16173
16380
  If you would like to display a single view in your ContainerView, you can set
16174
16381
  its `currentView` property. When the `currentView` property is set to a view
16175
- instance, it will be added to the ContainerView's `childViews` array. If the
16176
- `currentView` property is later changed to a different view, the new view
16177
- will replace the old view. If `currentView` is set to `null`, the last
16178
- `currentView` will be removed.
16382
+ instance, it will be added to the ContainerView. If the `currentView` property
16383
+ is later changed to a different view, the new view will replace the old view.
16384
+ If `currentView` is set to `null`, the last `currentView` will be removed.
16179
16385
 
16180
16386
  This functionality is useful for cases where you want to bind the display of
16181
16387
  a ContainerView to a controller or state manager. For example, you can bind
@@ -16197,15 +16403,16 @@ var childViewsProperty = Ember.computed(function() {
16197
16403
  @namespace Ember
16198
16404
  @extends Ember.View
16199
16405
  */
16200
-
16201
- Ember.ContainerView = Ember.View.extend({
16406
+ Ember.ContainerView = Ember.View.extend(Ember.MutableArray, {
16202
16407
  states: states,
16203
16408
 
16204
16409
  init: function() {
16205
16410
  this._super();
16206
16411
 
16207
16412
  var childViews = get(this, 'childViews');
16208
- Ember.defineProperty(this, 'childViews', childViewsProperty);
16413
+
16414
+ // redefine view's childViews property that was obliterated
16415
+ Ember.defineProperty(this, 'childViews', Ember.View.childViewsProperty);
16209
16416
 
16210
16417
  var _childViews = this._childViews;
16211
16418
 
@@ -16224,20 +16431,38 @@ Ember.ContainerView = Ember.View.extend({
16224
16431
  }, this);
16225
16432
 
16226
16433
  var currentView = get(this, 'currentView');
16227
- if (currentView) _childViews.push(this.createChildView(currentView));
16434
+ if (currentView) {
16435
+ _childViews.push(this.createChildView(currentView));
16436
+ }
16437
+ },
16228
16438
 
16229
- // Make the _childViews array observable
16230
- Ember.A(_childViews);
16439
+ replace: function(idx, removedCount, addedViews) {
16440
+ var addedCount = addedViews ? get(addedViews, 'length') : 0;
16231
16441
 
16232
- // Sets up an array observer on the child views array. This
16233
- // observer will detect when child views are added or removed
16234
- // and update the DOM to reflect the mutation.
16235
- get(this, 'childViews').addArrayObserver(this, {
16236
- willChange: 'childViewsWillChange',
16237
- didChange: 'childViewsDidChange'
16238
- });
16442
+ this.arrayContentWillChange(idx, removedCount, addedCount);
16443
+ this.childViewsWillChange(this._childViews, idx, removedCount);
16444
+
16445
+ if (addedCount === 0) {
16446
+ this._childViews.splice(idx, removedCount) ;
16447
+ } else {
16448
+ var args = [idx, removedCount].concat(addedViews);
16449
+ this._childViews.splice.apply(this._childViews, args);
16450
+ }
16451
+
16452
+ this.arrayContentDidChange(idx, removedCount, addedCount);
16453
+ this.childViewsDidChange(this._childViews, idx, removedCount, addedCount);
16454
+
16455
+ return this;
16456
+ },
16457
+
16458
+ objectAt: function(idx) {
16459
+ return this._childViews[idx];
16239
16460
  },
16240
16461
 
16462
+ length: Ember.computed(function () {
16463
+ return this._childViews.length;
16464
+ }),
16465
+
16241
16466
  /**
16242
16467
  @private
16243
16468
 
@@ -16254,23 +16479,6 @@ Ember.ContainerView = Ember.View.extend({
16254
16479
 
16255
16480
  instrumentName: 'render.container',
16256
16481
 
16257
- /**
16258
- @private
16259
-
16260
- When the container view is destroyed, tear down the child views
16261
- array observer.
16262
-
16263
- @method willDestroy
16264
- */
16265
- willDestroy: function() {
16266
- get(this, 'childViews').removeArrayObserver(this, {
16267
- willChange: 'childViewsWillChange',
16268
- didChange: 'childViewsDidChange'
16269
- });
16270
-
16271
- this._super();
16272
- },
16273
-
16274
16482
  /**
16275
16483
  @private
16276
16484
 
@@ -16286,12 +16494,19 @@ Ember.ContainerView = Ember.View.extend({
16286
16494
  @param {Number} removed the number of child views removed
16287
16495
  **/
16288
16496
  childViewsWillChange: function(views, start, removed) {
16289
- if (removed === 0) { return; }
16497
+ this.propertyWillChange('childViews');
16290
16498
 
16291
- var changedViews = views.slice(start, start+removed);
16292
- this.initializeViews(changedViews, null, null);
16499
+ if (removed > 0) {
16500
+ var changedViews = views.slice(start, start+removed);
16501
+ // transition to preRender before clearing parentView
16502
+ this.currentState.childViewsWillChange(this, views, start, removed);
16503
+ this.initializeViews(changedViews, null, null);
16504
+ }
16505
+ },
16293
16506
 
16294
- this.currentState.childViewsWillChange(this, views, start, removed);
16507
+ removeChild: function(child) {
16508
+ this.removeObject(child);
16509
+ return this;
16295
16510
  },
16296
16511
 
16297
16512
  /**
@@ -16312,16 +16527,12 @@ Ember.ContainerView = Ember.View.extend({
16312
16527
  @param {Number} the number of child views added
16313
16528
  */
16314
16529
  childViewsDidChange: function(views, start, removed, added) {
16315
- var len = get(views, 'length');
16316
-
16317
- // No new child views were added; bail out.
16318
- if (added === 0) return;
16319
-
16320
- var changedViews = views.slice(start, start+added);
16321
- this.initializeViews(changedViews, this, get(this, 'templateData'));
16322
-
16323
- // Let the current state handle the changes
16324
- this.currentState.childViewsDidChange(this, views, start, added);
16530
+ if (added > 0) {
16531
+ var changedViews = views.slice(start, start+added);
16532
+ this.initializeViews(changedViews, this, get(this, 'templateData'));
16533
+ this.currentState.childViewsDidChange(this, views, start, added);
16534
+ }
16535
+ this.propertyDidChange('childViews');
16325
16536
  },
16326
16537
 
16327
16538
  initializeViews: function(views, parentView, templateData) {
@@ -16337,21 +16548,16 @@ Ember.ContainerView = Ember.View.extend({
16337
16548
  currentView: null,
16338
16549
 
16339
16550
  _currentViewWillChange: Ember.beforeObserver(function() {
16340
- var childViews = get(this, 'childViews'),
16341
- currentView = get(this, 'currentView');
16342
-
16551
+ var currentView = get(this, 'currentView');
16343
16552
  if (currentView) {
16344
16553
  currentView.destroy();
16345
- childViews.removeObject(currentView);
16346
16554
  }
16347
16555
  }, 'currentView'),
16348
16556
 
16349
16557
  _currentViewDidChange: Ember.observer(function() {
16350
- var childViews = get(this, 'childViews'),
16351
- currentView = get(this, 'currentView');
16352
-
16558
+ var currentView = get(this, 'currentView');
16353
16559
  if (currentView) {
16354
- childViews.pushObject(currentView);
16560
+ this.pushObject(currentView);
16355
16561
  }
16356
16562
  }, 'currentView'),
16357
16563
 
@@ -16384,7 +16590,7 @@ Ember.merge(states.hasElement, {
16384
16590
  },
16385
16591
 
16386
16592
  ensureChildrenAreInDOM: function(view) {
16387
- var childViews = view.get('childViews'), i, len, childView, previous, buffer;
16593
+ var childViews = view._childViews, i, len, childView, previous, buffer;
16388
16594
  for (i = 0, len = childViews.length; i < len; i++) {
16389
16595
  childView = childViews[i];
16390
16596
  buffer = childView.renderToBufferIfNeeded();
@@ -16649,6 +16855,10 @@ Ember.CollectionView = Ember.ContainerView.extend(
16649
16855
  if (content) { content.removeArrayObserver(this); }
16650
16856
 
16651
16857
  this._super();
16858
+
16859
+ if (this._createdEmptyView) {
16860
+ this._createdEmptyView.destroy();
16861
+ }
16652
16862
  },
16653
16863
 
16654
16864
  arrayWillChange: function(content, start, removedCount) {
@@ -16662,9 +16872,9 @@ Ember.CollectionView = Ember.ContainerView.extend(
16662
16872
  // Loop through child views that correspond with the removed items.
16663
16873
  // Note that we loop from the end of the array to the beginning because
16664
16874
  // we are mutating it as we go.
16665
- var childViews = get(this, 'childViews'), childView, idx, len;
16875
+ var childViews = this._childViews, childView, idx, len;
16666
16876
 
16667
- len = get(childViews, 'length');
16877
+ len = this._childViews.length;
16668
16878
 
16669
16879
  var removingAll = removedCount === len;
16670
16880
 
@@ -16694,7 +16904,6 @@ Ember.CollectionView = Ember.ContainerView.extend(
16694
16904
  */
16695
16905
  arrayDidChange: function(content, start, removed, added) {
16696
16906
  var itemViewClass = get(this, 'itemViewClass'),
16697
- childViews = get(this, 'childViews'),
16698
16907
  addedViews = [], view, item, idx, len, itemTagName;
16699
16908
 
16700
16909
  if ('string' === typeof itemViewClass) {
@@ -16719,11 +16928,15 @@ Ember.CollectionView = Ember.ContainerView.extend(
16719
16928
  var emptyView = get(this, 'emptyView');
16720
16929
  if (!emptyView) { return; }
16721
16930
 
16931
+ var isClass = Ember.CoreView.detect(emptyView);
16932
+
16722
16933
  emptyView = this.createChildView(emptyView);
16723
16934
  addedViews.push(emptyView);
16724
16935
  set(this, 'emptyView', emptyView);
16936
+
16937
+ if (isClass) { this._createdEmptyView = emptyView; }
16725
16938
  }
16726
- childViews.replace(start, 0, addedViews);
16939
+ this.replace(start, 0, addedViews);
16727
16940
  },
16728
16941
 
16729
16942
  createChildView: function(view, attrs) {
@@ -17258,7 +17471,7 @@ var objectCreate = Object.create || function(parent) {
17258
17471
  };
17259
17472
 
17260
17473
  var Handlebars = this.Handlebars || Ember.imports.Handlebars;
17261
- Ember.assert("Ember Handlebars requires Handlebars 1.0.beta.5 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.beta\.[56789]$|^1\.0\.rc\.[123456789]+/));
17474
+ Ember.assert("Ember Handlebars requires Handlebars 1.0.0-rc.3 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.[0-9](\.rc\.[23456789]+)?/));
17262
17475
 
17263
17476
  /**
17264
17477
  Prepares the Handlebars templating library for use inside Ember's view
@@ -17335,6 +17548,8 @@ Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string)
17335
17548
  return "data.buffer.push("+string+");";
17336
17549
  };
17337
17550
 
17551
+ var prefix = "ember" + (+new Date()), incr = 1;
17552
+
17338
17553
  /**
17339
17554
  @private
17340
17555
 
@@ -17347,8 +17562,11 @@ Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string)
17347
17562
  @param mustache
17348
17563
  */
17349
17564
  Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
17350
- if (mustache.params.length || mustache.hash) {
17351
- return Handlebars.Compiler.prototype.mustache.call(this, mustache);
17565
+ if (mustache.isHelper && mustache.id.string === 'control') {
17566
+ mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
17567
+ mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
17568
+ } else if (mustache.params.length || mustache.hash) {
17569
+ // no changes required
17352
17570
  } else {
17353
17571
  var id = new Handlebars.AST.IdNode(['_triageMustache']);
17354
17572
 
@@ -17360,8 +17578,9 @@ Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
17360
17578
  mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
17361
17579
  }
17362
17580
  mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
17363
- return Handlebars.Compiler.prototype.mustache.call(this, mustache);
17364
17581
  }
17582
+
17583
+ return Handlebars.Compiler.prototype.mustache.call(this, mustache);
17365
17584
  };
17366
17585
 
17367
17586
  /**
@@ -17420,6 +17639,8 @@ if (Handlebars.compile) {
17420
17639
  })();
17421
17640
 
17422
17641
  (function() {
17642
+ var slice = Array.prototype.slice;
17643
+
17423
17644
  /**
17424
17645
  @private
17425
17646
 
@@ -17474,7 +17695,7 @@ var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data)
17474
17695
  @param {String} path The path to be lookedup
17475
17696
  @param {Object} options The template's option hash
17476
17697
  */
17477
- Ember.Handlebars.get = function(root, path, options) {
17698
+ var handlebarsGet = Ember.Handlebars.get = function(root, path, options) {
17478
17699
  var data = options && options.data,
17479
17700
  normalizedPath = normalizePath(root, path, data),
17480
17701
  value;
@@ -17496,6 +17717,41 @@ Ember.Handlebars.get = function(root, path, options) {
17496
17717
  };
17497
17718
  Ember.Handlebars.getPath = Ember.deprecateFunc('`Ember.Handlebars.getPath` has been changed to `Ember.Handlebars.get` for consistency.', Ember.Handlebars.get);
17498
17719
 
17720
+ Ember.Handlebars.resolveParams = function(context, params, options) {
17721
+ var resolvedParams = [], types = options.types, param, type;
17722
+
17723
+ for (var i=0, l=params.length; i<l; i++) {
17724
+ param = params[i];
17725
+ type = types[i];
17726
+
17727
+ if (type === 'ID') {
17728
+ resolvedParams.push(handlebarsGet(context, param, options));
17729
+ } else {
17730
+ resolvedParams.push(param);
17731
+ }
17732
+ }
17733
+
17734
+ return resolvedParams;
17735
+ };
17736
+
17737
+ Ember.Handlebars.resolveHash = function(context, hash, options) {
17738
+ var resolvedHash = {}, types = options.hashTypes, type;
17739
+
17740
+ for (var key in hash) {
17741
+ if (!hash.hasOwnProperty(key)) { continue; }
17742
+
17743
+ type = types[key];
17744
+
17745
+ if (type === 'ID') {
17746
+ resolvedHash[key] = handlebarsGet(context, hash[key], options);
17747
+ } else {
17748
+ resolvedHash[key] = hash[key];
17749
+ }
17750
+ }
17751
+
17752
+ return resolvedHash;
17753
+ };
17754
+
17499
17755
  /**
17500
17756
  @private
17501
17757
 
@@ -17565,6 +17821,18 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
17565
17821
  {{repeat text count=3}}
17566
17822
  ```
17567
17823
 
17824
+ ## Example with bound options
17825
+
17826
+ Bound hash options are also supported. Example:
17827
+
17828
+ ```handlebars
17829
+ {{repeat text countBinding="numRepeats"}}
17830
+ ```
17831
+
17832
+ In this example, count will be bound to the value of
17833
+ the `numRepeats` property on the context. If that property
17834
+ changes, the helper will be re-rendered.
17835
+
17568
17836
  ## Example with extra dependencies
17569
17837
 
17570
17838
  The `Ember.Handlebars.registerBoundHelper` method takes a variable length
@@ -17577,6 +17845,37 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
17577
17845
  }, 'name');
17578
17846
  ```
17579
17847
 
17848
+ ## Example with multiple bound properties
17849
+
17850
+ `Ember.Handlebars.registerBoundHelper` supports binding to
17851
+ multiple properties, e.g.:
17852
+
17853
+ ```javascript
17854
+ Ember.Handlebars.registerBoundHelper('concatenate', function() {
17855
+ var values = arguments[arguments.length - 1];
17856
+ return values.join('||');
17857
+ });
17858
+ ```
17859
+
17860
+ Which allows for template syntax such as {{concatenate prop1 prop2}} or
17861
+ {{concatenate prop1 prop2 prop3}}. If any of the properties change,
17862
+ the helpr will re-render. Note that dependency keys cannot be
17863
+ using in conjunction with multi-property helpers, since it is ambiguous
17864
+ which property the dependent keys would belong to.
17865
+
17866
+ ## Use with unbound helper
17867
+
17868
+ The {{unbound}} helper can be used with bound helper invocations
17869
+ to render them in their unbound form, e.g.
17870
+
17871
+ ```handlebars
17872
+ {{unbound capitalize name}}
17873
+ ```
17874
+
17875
+ In this example, if the name property changes, the helper
17876
+ will not re-render.
17877
+
17878
+
17580
17879
  @method registerBoundHelper
17581
17880
  @for Ember.Handlebars
17582
17881
  @param {String} name
@@ -17584,15 +17883,50 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
17584
17883
  @param {String} dependentKeys*
17585
17884
  */
17586
17885
  Ember.Handlebars.registerBoundHelper = function(name, fn) {
17587
- var dependentKeys = Array.prototype.slice.call(arguments, 2);
17588
- Ember.Handlebars.registerHelper(name, function(property, options) {
17589
- var data = options.data,
17886
+ var dependentKeys = slice.call(arguments, 2);
17887
+
17888
+ function helper() {
17889
+ var properties = slice.call(arguments, 0, -1),
17890
+ numProperties = properties.length,
17891
+ options = arguments[arguments.length - 1],
17892
+ normalizedProperties = [],
17893
+ data = options.data,
17894
+ hash = options.hash,
17590
17895
  view = data.view,
17591
17896
  currentContext = (options.contexts && options.contexts[0]) || this,
17592
- pathRoot, path, normalized,
17593
- observer, loc;
17897
+ normalized,
17898
+ pathRoot, path,
17899
+ loc, hashOption;
17900
+
17901
+ // Detect bound options (e.g. countBinding="otherCount")
17902
+ hash.boundOptions = {};
17903
+ for (hashOption in hash) {
17904
+ if (!hash.hasOwnProperty(hashOption)) { continue; }
17905
+
17906
+ if (Ember.IS_BINDING.test(hashOption) && typeof hash[hashOption] === 'string') {
17907
+ // Lop off 'Binding' suffix.
17908
+ hash.boundOptions[hashOption.slice(0, -7)] = hash[hashOption];
17909
+ }
17910
+ }
17594
17911
 
17595
- normalized = Ember.Handlebars.normalizePath(currentContext, property, data);
17912
+ // Expose property names on data.properties object.
17913
+ data.properties = [];
17914
+ for (loc = 0; loc < numProperties; ++loc) {
17915
+ data.properties.push(properties[loc]);
17916
+ normalizedProperties.push(normalizePath(currentContext, properties[loc], data));
17917
+ }
17918
+
17919
+ if (data.isUnbound) {
17920
+ return evaluateUnboundHelper(this, fn, normalizedProperties, options);
17921
+ }
17922
+
17923
+ if (dependentKeys.length === 0) {
17924
+ return evaluateMultiPropertyBoundHelper(currentContext, fn, normalizedProperties, options);
17925
+ }
17926
+
17927
+ Ember.assert("Dependent keys can only be used with single-property helpers.", properties.length === 1);
17928
+
17929
+ normalized = normalizedProperties[0];
17596
17930
 
17597
17931
  pathRoot = normalized.root;
17598
17932
  path = normalized.path;
@@ -17608,28 +17942,116 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) {
17608
17942
 
17609
17943
  view.appendChild(bindView);
17610
17944
 
17611
- observer = function() {
17612
- Ember.run.scheduleOnce('render', bindView, 'rerender');
17613
- };
17945
+ view.registerObserver(pathRoot, path, bindView, rerenderBoundHelperView);
17614
17946
 
17615
- Ember.addObserver(pathRoot, path, observer);
17616
- loc = 0;
17617
- while(loc < dependentKeys.length) {
17618
- Ember.addObserver(pathRoot, path + '.' + dependentKeys[loc], observer);
17619
- loc += 1;
17947
+ for (var i=0, l=dependentKeys.length; i<l; i++) {
17948
+ view.registerObserver(pathRoot, path + '.' + dependentKeys[i], bindView, rerenderBoundHelperView);
17620
17949
  }
17950
+ }
17621
17951
 
17622
- view.one('willClearRender', function() {
17623
- Ember.removeObserver(pathRoot, path, observer);
17624
- loc = 0;
17625
- while(loc < dependentKeys.length) {
17626
- Ember.removeObserver(pathRoot, path + '.' + dependentKeys[loc], observer);
17627
- loc += 1;
17628
- }
17629
- });
17630
- });
17952
+ helper._rawFunction = fn;
17953
+ Ember.Handlebars.registerHelper(name, helper);
17631
17954
  };
17632
17955
 
17956
+ /**
17957
+ @private
17958
+
17959
+ Renders the unbound form of an otherwise bound helper function.
17960
+
17961
+ @param {Function} fn
17962
+ @param {Object} context
17963
+ @param {Array} normalizedProperties
17964
+ @param {String} options
17965
+ */
17966
+ function evaluateMultiPropertyBoundHelper(context, fn, normalizedProperties, options) {
17967
+ var numProperties = normalizedProperties.length,
17968
+ self = this,
17969
+ data = options.data,
17970
+ view = data.view,
17971
+ hash = options.hash,
17972
+ boundOptions = hash.boundOptions,
17973
+ watchedProperties,
17974
+ boundOption, bindView, loc, property, len;
17975
+
17976
+ bindView = new Ember._SimpleHandlebarsView(null, null, !hash.unescaped, data);
17977
+ bindView.normalizedValue = function() {
17978
+ var args = [], value, boundOption;
17979
+
17980
+ // Copy over bound options.
17981
+ for (boundOption in boundOptions) {
17982
+ if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
17983
+ property = normalizePath(context, boundOptions[boundOption], data);
17984
+ bindView.path = property.path;
17985
+ bindView.pathRoot = property.root;
17986
+ hash[boundOption] = Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView);
17987
+ }
17988
+
17989
+ for (loc = 0; loc < numProperties; ++loc) {
17990
+ property = normalizedProperties[loc];
17991
+ bindView.path = property.path;
17992
+ bindView.pathRoot = property.root;
17993
+ args.push(Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView));
17994
+ }
17995
+ args.push(options);
17996
+ return fn.apply(context, args);
17997
+ };
17998
+
17999
+ view.appendChild(bindView);
18000
+
18001
+ // Assemble liast of watched properties that'll re-render this helper.
18002
+ watchedProperties = [];
18003
+ for (boundOption in boundOptions) {
18004
+ if (boundOptions.hasOwnProperty(boundOption)) {
18005
+ watchedProperties.push(normalizePath(context, boundOptions[boundOption], data));
18006
+ }
18007
+ }
18008
+ watchedProperties = watchedProperties.concat(normalizedProperties);
18009
+
18010
+ // Observe each property.
18011
+ for (loc = 0, len = watchedProperties.length; loc < len; ++loc) {
18012
+ property = watchedProperties[loc];
18013
+ view.registerObserver(property.root, property.path, bindView, rerenderBoundHelperView);
18014
+ }
18015
+
18016
+ }
18017
+
18018
+ /**
18019
+ @private
18020
+
18021
+ An observer function used with bound helpers which
18022
+ will schedule a re-render of the _SimpleHandlebarsView
18023
+ connected with the helper.
18024
+ */
18025
+ function rerenderBoundHelperView() {
18026
+ Ember.run.scheduleOnce('render', this, 'rerender');
18027
+ }
18028
+
18029
+ /**
18030
+ @private
18031
+
18032
+ Renders the unbound form of an otherwise bound helper function.
18033
+
18034
+ @param {Function} fn
18035
+ @param {Object} context
18036
+ @param {Array} normalizedProperties
18037
+ @param {String} options
18038
+ */
18039
+ function evaluateUnboundHelper(context, fn, normalizedProperties, options) {
18040
+ var args = [], hash = options.hash, boundOptions = hash.boundOptions, loc, len, property, boundOption;
18041
+
18042
+ for (boundOption in boundOptions) {
18043
+ if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
18044
+ hash[boundOption] = Ember.Handlebars.get(context, boundOptions[boundOption], options);
18045
+ }
18046
+
18047
+ for(loc = 0, len = normalizedProperties.length; loc < len; ++loc) {
18048
+ property = normalizedProperties[loc];
18049
+ args.push(Ember.Handlebars.get(context, property.path, options));
18050
+ }
18051
+ args.push(options);
18052
+ return fn.apply(context, args);
18053
+ }
18054
+
17633
18055
  /**
17634
18056
  @private
17635
18057
 
@@ -17733,7 +18155,7 @@ var DOMManager = {
17733
18155
  view.transitionTo('preRender');
17734
18156
 
17735
18157
  Ember.run.schedule('render', this, function() {
17736
- if (get(view, 'isDestroyed')) { return; }
18158
+ if (view.isDestroying) { return; }
17737
18159
 
17738
18160
  view.clearRenderedChildren();
17739
18161
  var buffer = view.renderToBuffer();
@@ -18154,20 +18576,16 @@ var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
18154
18576
 
18155
18577
  // Binds a property into the DOM. This will create a hook in DOM that the
18156
18578
  // KVO system will look for and update if the property changes.
18157
- function bind(property, options, preserveContext, shouldDisplay, valueNormalizer) {
18579
+ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties) {
18158
18580
  var data = options.data,
18159
18581
  fn = options.fn,
18160
18582
  inverse = options.inverse,
18161
18583
  view = data.view,
18162
18584
  currentContext = this,
18163
- pathRoot, path, normalized,
18164
- observer;
18585
+ normalized, observer, i;
18165
18586
 
18166
18587
  normalized = normalizePath(currentContext, property, data);
18167
18588
 
18168
- pathRoot = normalized.root;
18169
- path = normalized.path;
18170
-
18171
18589
  // Set up observers for observable objects
18172
18590
  if ('object' === typeof this) {
18173
18591
  if (data.insideGroup) {
@@ -18175,7 +18593,7 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
18175
18593
  Ember.run.once(view, 'rerender');
18176
18594
  };
18177
18595
 
18178
- var template, context, result = handlebarsGet(pathRoot, path, options);
18596
+ var template, context, result = handlebarsGet(currentContext, property, options);
18179
18597
 
18180
18598
  result = valueNormalizer(result);
18181
18599
 
@@ -18197,8 +18615,8 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
18197
18615
  valueNormalizerFunc: valueNormalizer,
18198
18616
  displayTemplate: fn,
18199
18617
  inverseTemplate: inverse,
18200
- path: path,
18201
- pathRoot: pathRoot,
18618
+ path: property,
18619
+ pathRoot: currentContext,
18202
18620
  previousContext: currentContext,
18203
18621
  isEscaped: !options.hash.unescaped,
18204
18622
  templateData: options.data
@@ -18215,17 +18633,18 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
18215
18633
  // tells the Ember._HandlebarsBoundView to re-render. If property
18216
18634
  // is an empty string, we are printing the current context
18217
18635
  // object ({{this}}) so updating it is not our responsibility.
18218
- if (path !== '') {
18219
- Ember.addObserver(pathRoot, path, observer);
18220
-
18221
- view.one('willClearRender', function() {
18222
- Ember.removeObserver(pathRoot, path, observer);
18223
- });
18636
+ if (normalized.path !== '') {
18637
+ view.registerObserver(normalized.root, normalized.path, observer);
18638
+ if (childProperties) {
18639
+ for (i=0; i<childProperties.length; i++) {
18640
+ view.registerObserver(normalized.root, normalized.path+'.'+childProperties[i], observer);
18641
+ }
18642
+ }
18224
18643
  }
18225
18644
  } else {
18226
18645
  // The object is not observable, so just render it out and
18227
18646
  // be done with it.
18228
- data.buffer.push(handlebarsGet(pathRoot, path, options));
18647
+ data.buffer.push(handlebarsGet(currentContext, property, options));
18229
18648
  }
18230
18649
  }
18231
18650
 
@@ -18233,14 +18652,10 @@ function simpleBind(property, options) {
18233
18652
  var data = options.data,
18234
18653
  view = data.view,
18235
18654
  currentContext = this,
18236
- pathRoot, path, normalized,
18237
- observer;
18655
+ normalized, observer;
18238
18656
 
18239
18657
  normalized = normalizePath(currentContext, property, data);
18240
18658
 
18241
- pathRoot = normalized.root;
18242
- path = normalized.path;
18243
-
18244
18659
  // Set up observers for observable objects
18245
18660
  if ('object' === typeof this) {
18246
18661
  if (data.insideGroup) {
@@ -18248,12 +18663,12 @@ function simpleBind(property, options) {
18248
18663
  Ember.run.once(view, 'rerender');
18249
18664
  };
18250
18665
 
18251
- var result = handlebarsGet(pathRoot, path, options);
18666
+ var result = handlebarsGet(currentContext, property, options);
18252
18667
  if (result === null || result === undefined) { result = ""; }
18253
18668
  data.buffer.push(result);
18254
18669
  } else {
18255
18670
  var bindView = new Ember._SimpleHandlebarsView(
18256
- path, pathRoot, !options.hash.unescaped, options.data
18671
+ property, currentContext, !options.hash.unescaped, options.data
18257
18672
  );
18258
18673
 
18259
18674
  bindView._parentView = view;
@@ -18268,17 +18683,13 @@ function simpleBind(property, options) {
18268
18683
  // tells the Ember._HandlebarsBoundView to re-render. If property
18269
18684
  // is an empty string, we are printing the current context
18270
18685
  // object ({{this}}) so updating it is not our responsibility.
18271
- if (path !== '') {
18272
- Ember.addObserver(pathRoot, path, observer);
18273
-
18274
- view.one('willClearRender', function() {
18275
- Ember.removeObserver(pathRoot, path, observer);
18276
- });
18686
+ if (normalized.path !== '') {
18687
+ view.registerObserver(normalized.root, normalized.path, observer);
18277
18688
  }
18278
18689
  } else {
18279
18690
  // The object is not observable, so just render it out and
18280
18691
  // be done with it.
18281
- data.buffer.push(handlebarsGet(pathRoot, path, options));
18692
+ data.buffer.push(handlebarsGet(currentContext, property, options));
18282
18693
  }
18283
18694
  }
18284
18695
 
@@ -18367,14 +18778,17 @@ EmberHandlebars.registerHelper('bind', function(property, options) {
18367
18778
  EmberHandlebars.registerHelper('boundIf', function(property, fn) {
18368
18779
  var context = (fn.contexts && fn.contexts[0]) || this;
18369
18780
  var func = function(result) {
18370
- if (Ember.typeOf(result) === 'array') {
18781
+ var truthy = result && get(result, 'isTruthy');
18782
+ if (typeof truthy === 'boolean') { return truthy; }
18783
+
18784
+ if (Ember.isArray(result)) {
18371
18785
  return get(result, 'length') !== 0;
18372
18786
  } else {
18373
18787
  return !!result;
18374
18788
  }
18375
18789
  };
18376
18790
 
18377
- return bind.call(context, property, fn, true, func, func);
18791
+ return bind.call(context, property, fn, true, func, func, ['isTruthy', 'length']);
18378
18792
  });
18379
18793
 
18380
18794
  /**
@@ -18611,16 +19025,13 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18611
19025
  // current value of the property as an attribute.
18612
19026
  forEach.call(attrKeys, function(attr) {
18613
19027
  var path = attrs[attr],
18614
- pathRoot, normalized;
19028
+ normalized;
18615
19029
 
18616
19030
  Ember.assert(fmt("You must provide a String for a bound attribute, not %@", [path]), typeof path === 'string');
18617
19031
 
18618
19032
  normalized = normalizePath(ctx, path, options.data);
18619
19033
 
18620
- pathRoot = normalized.root;
18621
- path = normalized.path;
18622
-
18623
- var value = (path === 'this') ? pathRoot : handlebarsGet(pathRoot, path, options),
19034
+ var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options),
18624
19035
  type = Ember.typeOf(value);
18625
19036
 
18626
19037
  Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean');
@@ -18628,7 +19039,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18628
19039
  var observer, invoker;
18629
19040
 
18630
19041
  observer = function observer() {
18631
- var result = handlebarsGet(pathRoot, path, options);
19042
+ var result = handlebarsGet(ctx, path, options);
18632
19043
 
18633
19044
  Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), result === null || result === undefined || typeof result === 'number' || typeof result === 'string' || typeof result === 'boolean');
18634
19045
 
@@ -18639,7 +19050,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18639
19050
  // In that case, we can assume the template has been re-rendered
18640
19051
  // and we need to clean up the observer.
18641
19052
  if (!elem || elem.length === 0) {
18642
- Ember.removeObserver(pathRoot, path, invoker);
19053
+ Ember.removeObserver(normalized.root, normalized.path, invoker);
18643
19054
  return;
18644
19055
  }
18645
19056
 
@@ -18654,11 +19065,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18654
19065
  // When the observer fires, find the element using the
18655
19066
  // unique data id and update the attribute to the new value.
18656
19067
  if (path !== 'this') {
18657
- Ember.addObserver(pathRoot, path, invoker);
18658
-
18659
- view.one('willClearRender', function() {
18660
- Ember.removeObserver(pathRoot, path, invoker);
18661
- });
19068
+ view.registerObserver(normalized.root, normalized.path, invoker);
18662
19069
  }
18663
19070
 
18664
19071
  // if this changes, also change the logic in ember-views/lib/views/view.js
@@ -18748,7 +19155,7 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId,
18748
19155
  // class name.
18749
19156
  observer = function() {
18750
19157
  // Get the current value of the property
18751
- newClass = classStringForPath(pathRoot, parsedPath, options);
19158
+ newClass = classStringForPath(context, parsedPath, options);
18752
19159
  elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$();
18753
19160
 
18754
19161
  // If we can't find the element anymore, a parent template has been
@@ -18777,16 +19184,12 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId,
18777
19184
  };
18778
19185
 
18779
19186
  if (path !== '' && path !== 'this') {
18780
- Ember.addObserver(pathRoot, path, invoker);
18781
-
18782
- view.one('willClearRender', function() {
18783
- Ember.removeObserver(pathRoot, path, invoker);
18784
- });
19187
+ view.registerObserver(pathRoot, path, invoker);
18785
19188
  }
18786
19189
 
18787
19190
  // We've already setup the observer; now we just need to figure out the
18788
19191
  // correct behavior right now on the first pass through.
18789
- value = classStringForPath(pathRoot, parsedPath, options);
19192
+ value = classStringForPath(context, parsedPath, options);
18790
19193
 
18791
19194
  if (value) {
18792
19195
  ret.push(value);
@@ -19307,7 +19710,7 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
19307
19710
  if (hash.hasOwnProperty(prop)) {
19308
19711
  match = prop.match(/^item(.)(.*)$/);
19309
19712
 
19310
- if(match) {
19713
+ if(match && prop !== 'itemController') {
19311
19714
  // Convert itemShouldFoo -> shouldFoo
19312
19715
  itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
19313
19716
  // Delete from hash as this will end up getting passed to the
@@ -19334,13 +19737,10 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
19334
19737
  } else if (hash.emptyViewClass) {
19335
19738
  emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
19336
19739
  }
19337
- hash.emptyView = emptyViewClass;
19740
+ if (emptyViewClass) { hash.emptyView = emptyViewClass; }
19338
19741
 
19339
- if (hash.eachHelper === 'each') {
19340
- itemHash._context = Ember.computed(function() {
19341
- return get(this, 'content');
19342
- }).property('content');
19343
- delete hash.eachHelper;
19742
+ if(!hash.keyword){
19743
+ itemHash._context = Ember.computed.alias('content');
19344
19744
  }
19345
19745
 
19346
19746
  var viewString = view.toString();
@@ -19373,13 +19773,31 @@ var handlebarsGet = Ember.Handlebars.get;
19373
19773
  <div>{{unbound somePropertyThatDoesntChange}}</div>
19374
19774
  ```
19375
19775
 
19776
+ `unbound` can also be used in conjunction with a bound helper to
19777
+ render it in its unbound form:
19778
+
19779
+ ```handlebars
19780
+ <div>{{unbound helperName somePropertyThatDoesntChange}}</div>
19781
+ ```
19782
+
19376
19783
  @method unbound
19377
19784
  @for Ember.Handlebars.helpers
19378
19785
  @param {String} property
19379
19786
  @return {String} HTML string
19380
19787
  */
19381
19788
  Ember.Handlebars.registerHelper('unbound', function(property, fn) {
19382
- var context = (fn.contexts && fn.contexts[0]) || this;
19789
+ var options = arguments[arguments.length - 1], helper, context, out;
19790
+
19791
+ if(arguments.length > 2) {
19792
+ // Unbound helper call.
19793
+ options.data.isUnbound = true;
19794
+ helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing;
19795
+ out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
19796
+ delete options.data.isUnbound;
19797
+ return out;
19798
+ }
19799
+
19800
+ context = (fn.contexts && fn.contexts[0]) || this;
19383
19801
  return handlebarsGet(context, property, fn);
19384
19802
  });
19385
19803
 
@@ -19445,6 +19863,44 @@ Ember.Handlebars.registerHelper('debugger', function() {
19445
19863
  var get = Ember.get, set = Ember.set;
19446
19864
 
19447
19865
  Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
19866
+ init: function() {
19867
+ var itemController = get(this, 'itemController');
19868
+ var binding;
19869
+
19870
+ if (itemController) {
19871
+ var controller = Ember.ArrayController.create();
19872
+ set(controller, 'itemController', itemController);
19873
+ set(controller, 'container', get(this, 'controller.container'));
19874
+ set(controller, '_eachView', this);
19875
+ set(controller, 'target', get(this, 'controller'));
19876
+
19877
+ this.disableContentObservers(function() {
19878
+ set(this, 'content', controller);
19879
+ binding = new Ember.Binding('content', '_eachView.dataSource').oneWay();
19880
+ binding.connect(controller);
19881
+ });
19882
+
19883
+ set(this, '_arrayController', controller);
19884
+ } else {
19885
+ this.disableContentObservers(function() {
19886
+ binding = new Ember.Binding('content', 'dataSource').oneWay();
19887
+ binding.connect(this);
19888
+ });
19889
+ }
19890
+
19891
+ return this._super();
19892
+ },
19893
+
19894
+ disableContentObservers: function(callback) {
19895
+ Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange');
19896
+ Ember.removeObserver(this, 'content', null, '_contentDidChange');
19897
+
19898
+ callback.apply(this);
19899
+
19900
+ Ember.addBeforeObserver(this, 'content', null, '_contentWillChange');
19901
+ Ember.addObserver(this, 'content', null, '_contentDidChange');
19902
+ },
19903
+
19448
19904
  itemViewClass: Ember._MetamorphView,
19449
19905
  emptyViewClass: Ember._MetamorphView,
19450
19906
 
@@ -19455,6 +19911,7 @@ Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
19455
19911
  // to insert keywords, it is responsible for cloning
19456
19912
  // the keywords hash. This will be fixed momentarily.
19457
19913
  var keyword = get(this, 'keyword');
19914
+ var content = get(view, 'content');
19458
19915
 
19459
19916
  if (keyword) {
19460
19917
  var data = get(view, 'templateData');
@@ -19463,14 +19920,28 @@ Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
19463
19920
  data.keywords = view.cloneKeywords();
19464
19921
  set(view, 'templateData', data);
19465
19922
 
19466
- var content = get(view, 'content');
19467
-
19468
19923
  // In this case, we do not bind, because the `content` of
19469
19924
  // a #each item cannot change.
19470
19925
  data.keywords[keyword] = content;
19471
19926
  }
19472
19927
 
19928
+ // If {{#each}} is looping over an array of controllers,
19929
+ // point each child view at their respective controller.
19930
+ if (content && get(content, 'isController')) {
19931
+ set(view, 'controller', content);
19932
+ }
19933
+
19473
19934
  return view;
19935
+ },
19936
+
19937
+ willDestroy: function() {
19938
+ var arrayController = get(this, '_arrayController');
19939
+
19940
+ if (arrayController) {
19941
+ arrayController.destroy();
19942
+ }
19943
+
19944
+ return this._super();
19474
19945
  }
19475
19946
  });
19476
19947
 
@@ -19564,7 +20035,8 @@ GroupedEach.prototype = {
19564
20035
 
19565
20036
  /**
19566
20037
  The `{{#each}}` helper loops over elements in a collection, rendering its
19567
- block once for each item:
20038
+ block once for each item. It is an extension of the base Handlebars `{{#each}}`
20039
+ helper:
19568
20040
 
19569
20041
  ```javascript
19570
20042
  Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
@@ -19596,12 +20068,20 @@ GroupedEach.prototype = {
19596
20068
  {{this}}
19597
20069
  {{/each}}
19598
20070
  ```
20071
+ ### {{else}} condition
20072
+ `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
20073
+ if the collection is empty.
19599
20074
 
19600
- ### Blockless Use
19601
-
19602
- If you provide an `itemViewClass` option that has its own `template` you can
19603
- omit the block in a similar way to how it can be done with the collection
19604
- helper.
20075
+ ```
20076
+ {{#each person in Developers}}
20077
+ {{person.name}}
20078
+ {{else}}
20079
+ <p>Sorry, nobody is available for this task.</p>
20080
+ {{/each}}
20081
+ ```
20082
+ ### Specifying a View class for items
20083
+ If you provide an `itemViewClass` option that references a view class
20084
+ with its own `template` you can omit the block.
19605
20085
 
19606
20086
  The following template:
19607
20087
 
@@ -19627,8 +20107,6 @@ GroupedEach.prototype = {
19627
20107
  App.AnItemView = Ember.View.extend({
19628
20108
  template: Ember.Handlebars.compile("Greetings {{name}}")
19629
20109
  });
19630
-
19631
- App.initialize();
19632
20110
  ```
19633
20111
 
19634
20112
  Will result in the HTML structure below
@@ -19640,11 +20118,39 @@ GroupedEach.prototype = {
19640
20118
  <div class="ember-view">Greetings Sara</div>
19641
20119
  </div>
19642
20120
  ```
19643
-
20121
+
20122
+ ### Representing each item with a Controller.
20123
+ By default the controller lookup within an `{{#each}}` block will be
20124
+ the controller of the template where the `{{#each}}` was used. If each
20125
+ item needs to be presented by a custom controller you can provide a
20126
+ `itemController` option which references a controller by lookup name.
20127
+ Each item in the loop will be wrapped in an instance of this controller
20128
+ and the item itself will be set to the `content` property of that controller.
20129
+
20130
+ This is useful in cases where properties of model objects need transformation
20131
+ or synthesis for display:
20132
+
20133
+ ```javascript
20134
+ App.DeveloperController = Ember.ObjectController.extend({
20135
+ isAvailableForHire: function(){
20136
+ return !this.get('content.isEmployed') && this.get('content.isSeekingWork');
20137
+ }.property('isEmployed', 'isSeekingWork')
20138
+ })
20139
+ ```
20140
+
20141
+ ```handlebars
20142
+ {{#each person in Developers itemController="developer"}}
20143
+ {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
20144
+ {{/each}}
20145
+ ```
20146
+
19644
20147
  @method each
19645
20148
  @for Ember.Handlebars.helpers
19646
20149
  @param [name] {String} name for item (used with `in`)
19647
20150
  @param path {String} path
20151
+ @param [options] {Object} Handlebars key/value pairs of options
20152
+ @param [options.itemViewClass] {String} a path to a view class used for each item
20153
+ @param [options.itemController] {String} name of a controller to be created for each item
19648
20154
  */
19649
20155
  Ember.Handlebars.registerHelper('each', function(path, options) {
19650
20156
  if (arguments.length === 4) {
@@ -19657,11 +20163,9 @@ Ember.Handlebars.registerHelper('each', function(path, options) {
19657
20163
  if (path === '') { path = "this"; }
19658
20164
 
19659
20165
  options.hash.keyword = keywordName;
19660
- } else {
19661
- options.hash.eachHelper = 'each';
19662
20166
  }
19663
20167
 
19664
- options.hash.contentBinding = path;
20168
+ options.hash.dataSourceBinding = path;
19665
20169
  // Set up emptyView as a metamorph with no tag
19666
20170
  //options.hash.emptyViewClass = Ember._MetamorphView;
19667
20171
 
@@ -20020,7 +20524,7 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
20020
20524
 
20021
20525
  classNames: ['ember-text-field'],
20022
20526
  tagName: "input",
20023
- attributeBindings: ['type', 'value', 'size'],
20527
+ attributeBindings: ['type', 'value', 'size', 'pattern'],
20024
20528
 
20025
20529
  /**
20026
20530
  The `value` attribute of the input element. As the user inputs text, this
@@ -20050,6 +20554,15 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
20050
20554
  */
20051
20555
  size: null,
20052
20556
 
20557
+ /**
20558
+ The `pattern` the pattern attribute of input element.
20559
+
20560
+ @property pattern
20561
+ @type String
20562
+ @default null
20563
+ */
20564
+ pattern: null,
20565
+
20053
20566
  /**
20054
20567
  The action to be sent when the user presses the return key.
20055
20568
 
@@ -20063,15 +20576,34 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
20063
20576
  */
20064
20577
  action: null,
20065
20578
 
20066
- insertNewline: function() {
20579
+ /**
20580
+ Whether they `keyUp` event that triggers an `action` to be sent continues
20581
+ propagating to other views.
20582
+
20583
+ By default, when the user presses the return key on their keyboard and
20584
+ the text field has an `action` set, the action will be sent to the view's
20585
+ controller and the key event will stop propagating.
20586
+
20587
+ If you would like parent views to receive the `keyUp` event even after an
20588
+ action has been dispatched, set `bubbles` to true.
20589
+
20590
+ @property bubbles
20591
+ @type Boolean
20592
+ @default false
20593
+ */
20594
+ bubbles: false,
20595
+
20596
+ insertNewline: function(event) {
20067
20597
  var controller = get(this, 'controller'),
20068
20598
  action = get(this, 'action');
20069
20599
 
20070
20600
  if (action) {
20071
- controller.send(action, get(this, 'value'));
20072
- }
20601
+ controller.send(action, get(this, 'value'), this);
20073
20602
 
20074
- return false;
20603
+ if (!get(this, 'bubbles')) {
20604
+ event.stopPropagation();
20605
+ }
20606
+ }
20075
20607
  }
20076
20608
  });
20077
20609
 
@@ -20545,30 +21077,37 @@ Ember.Select = Ember.View.extend(
20545
21077
  tagName: 'select',
20546
21078
  classNames: ['ember-select'],
20547
21079
  defaultTemplate: Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) {
21080
+ this.compilerInfo = [2,'>= 1.0.0-rc.3'];
20548
21081
  helpers = helpers || Ember.Handlebars.helpers; data = data || {};
20549
- var buffer = '', stack1, escapeExpression=this.escapeExpression, self=this;
21082
+ var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this;
20550
21083
 
20551
21084
  function program1(depth0,data) {
20552
21085
 
20553
- var buffer = '', stack1;
21086
+ var buffer = '', hashTypes;
20554
21087
  data.buffer.push("<option value=\"\">");
20555
- stack1 = helpers._triageMustache.call(depth0, "view.prompt", {hash:{},contexts:[depth0],data:data});
20556
- data.buffer.push(escapeExpression(stack1) + "</option>");
20557
- return buffer;}
21088
+ hashTypes = {};
21089
+ data.buffer.push(escapeExpression(helpers._triageMustache.call(depth0, "view.prompt", {hash:{},contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data})));
21090
+ data.buffer.push("</option>");
21091
+ return buffer;
21092
+ }
20558
21093
 
20559
21094
  function program3(depth0,data) {
20560
21095
 
20561
- var stack1;
20562
- stack1 = {};
20563
- stack1['contentBinding'] = "this";
20564
- stack1 = helpers.view.call(depth0, "Ember.SelectOption", {hash:stack1,contexts:[depth0],data:data});
20565
- data.buffer.push(escapeExpression(stack1));}
21096
+ var hashTypes;
21097
+ hashTypes = {'contentBinding': "STRING"};
21098
+ data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{
21099
+ 'contentBinding': ("this")
21100
+ },contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data})));
21101
+ }
20566
21102
 
20567
- stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],data:data});
21103
+ hashTypes = {};
21104
+ stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
20568
21105
  if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
20569
- stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],data:data});
21106
+ hashTypes = {};
21107
+ stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
20570
21108
  if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
20571
21109
  return buffer;
21110
+
20572
21111
  }),
20573
21112
  attributeBindings: ['multiple', 'disabled', 'tabindex'],
20574
21113
 
@@ -21904,10 +22443,16 @@ define("router",
21904
22443
  if (handler.setup) { handler.setup(context); }
21905
22444
  });
21906
22445
 
22446
+ var aborted = false;
21907
22447
  eachHandler(partition.entered, function(handler, context) {
22448
+ if (aborted) { return; }
21908
22449
  if (handler.enter) { handler.enter(); }
21909
22450
  setContext(handler, context);
21910
- if (handler.setup) { handler.setup(context); }
22451
+ if (handler.setup) {
22452
+ if (false === handler.setup(context)) {
22453
+ aborted = true;
22454
+ }
22455
+ }
21911
22456
  });
21912
22457
 
21913
22458
  if (router.didTransition) {
@@ -22031,21 +22576,23 @@ define("router",
22031
22576
  function trigger(router, args) {
22032
22577
  var currentHandlerInfos = router.currentHandlerInfos;
22033
22578
 
22579
+ var name = args.shift();
22580
+
22034
22581
  if (!currentHandlerInfos) {
22035
- throw new Error("Could not trigger event. There are no active handlers");
22582
+ throw new Error("Could not trigger event '" + name + "'. There are no active handlers");
22036
22583
  }
22037
22584
 
22038
- var name = args.shift();
22039
-
22040
22585
  for (var i=currentHandlerInfos.length-1; i>=0; i--) {
22041
22586
  var handlerInfo = currentHandlerInfos[i],
22042
22587
  handler = handlerInfo.handler;
22043
22588
 
22044
22589
  if (handler.events && handler.events[name]) {
22045
22590
  handler.events[name].apply(handler, args);
22046
- break;
22591
+ return;
22047
22592
  }
22048
22593
  }
22594
+
22595
+ throw new Error("Nothing handled the event '" + name + "'.");
22049
22596
  }
22050
22597
 
22051
22598
  function setContext(handler, context) {
@@ -22191,7 +22738,7 @@ Ember.generateController = function(container, controllerName, context) {
22191
22738
  var Router = requireModule("router");
22192
22739
  var get = Ember.get, set = Ember.set, classify = Ember.String.classify;
22193
22740
 
22194
- var DefaultView = Ember.View.extend(Ember._Metamorph);
22741
+ var DefaultView = Ember._MetamorphView;
22195
22742
  function setupLocation(router) {
22196
22743
  var location = get(router, 'location'),
22197
22744
  rootURL = get(router, 'rootURL');
@@ -22207,6 +22754,14 @@ function setupLocation(router) {
22207
22754
  }
22208
22755
  }
22209
22756
 
22757
+ /**
22758
+ The `Ember.Router` class manages the application state and URLs. Refer to
22759
+ the [routing guide](http://emberjs.com/guides/routing/) for documentation.
22760
+
22761
+ @class Router
22762
+ @namespace Ember
22763
+ @extends Ember.Object
22764
+ */
22210
22765
  Ember.Router = Ember.Object.extend({
22211
22766
  location: 'hash',
22212
22767
 
@@ -22216,6 +22771,10 @@ Ember.Router = Ember.Object.extend({
22216
22771
  setupLocation(this);
22217
22772
  },
22218
22773
 
22774
+ url: Ember.computed(function() {
22775
+ return get(this, 'location').getURL();
22776
+ }),
22777
+
22219
22778
  startRouting: function() {
22220
22779
  this.router = this.router || this.constructor.map(Ember.K);
22221
22780
 
@@ -22229,15 +22788,18 @@ Ember.Router = Ember.Object.extend({
22229
22788
  container.register('view', 'default', DefaultView);
22230
22789
  container.register('view', 'toplevel', Ember.View.extend());
22231
22790
 
22232
- router.handleURL(location.getURL());
22233
22791
  location.onUpdateURL(function(url) {
22234
- router.handleURL(url);
22792
+ self.handleURL(url);
22235
22793
  });
22794
+
22795
+ this.handleURL(location.getURL());
22236
22796
  },
22237
22797
 
22238
22798
  didTransition: function(infos) {
22239
22799
  // Don't do any further action here if we redirected
22240
- if (infos[infos.length-1].handler.transitioned) { return; }
22800
+ for (var i=0, l=infos.length; i<l; i++) {
22801
+ if (infos[i].handler.redirected) { return; }
22802
+ }
22241
22803
 
22242
22804
  var appController = this.container.lookup('controller:application'),
22243
22805
  path = routePath(infos);
@@ -22255,24 +22817,14 @@ Ember.Router = Ember.Object.extend({
22255
22817
  this.notifyPropertyChange('url');
22256
22818
  },
22257
22819
 
22258
- transitionTo: function(passedName) {
22259
- var args = [].slice.call(arguments), name;
22260
-
22261
- if (!this.router.hasRoute(passedName)) {
22262
- name = args[0] = passedName + '.index';
22263
- } else {
22264
- name = passedName;
22265
- }
22266
-
22267
- Ember.assert("The route " + passedName + " was not found", this.router.hasRoute(name));
22268
-
22269
- this.router.transitionTo.apply(this.router, args);
22270
- this.notifyPropertyChange('url');
22820
+ transitionTo: function(name) {
22821
+ var args = [].slice.call(arguments);
22822
+ doTransition(this, 'transitionTo', args);
22271
22823
  },
22272
22824
 
22273
22825
  replaceWith: function() {
22274
- this.router.replaceWith.apply(this.router, arguments);
22275
- this.notifyPropertyChange('url');
22826
+ var args = [].slice.call(arguments);
22827
+ doTransition(this, 'replaceWith', args);
22276
22828
  },
22277
22829
 
22278
22830
  generate: function() {
@@ -22286,11 +22838,7 @@ Ember.Router = Ember.Object.extend({
22286
22838
  },
22287
22839
 
22288
22840
  send: function(name, context) {
22289
- if (Ember.$ && context instanceof Ember.$.Event) {
22290
- context = context.context;
22291
- }
22292
-
22293
- this.router.trigger(name, context);
22841
+ this.router.trigger.apply(this.router, arguments);
22294
22842
  },
22295
22843
 
22296
22844
  hasRoute: function(route) {
@@ -22407,6 +22955,21 @@ function setupRouter(emberRouter, router, location) {
22407
22955
  };
22408
22956
  }
22409
22957
 
22958
+ function doTransition(router, method, args) {
22959
+ var passedName = args[0], name;
22960
+
22961
+ if (!router.router.hasRoute(args[0])) {
22962
+ name = args[0] = passedName + '.index';
22963
+ } else {
22964
+ name = passedName;
22965
+ }
22966
+
22967
+ Ember.assert("The route " + passedName + " was not found", router.router.hasRoute(name));
22968
+
22969
+ router.router[method].apply(router.router, args);
22970
+ router.notifyPropertyChange('url');
22971
+ }
22972
+
22410
22973
  Ember.Router.reopenClass({
22411
22974
  map: function(callback) {
22412
22975
  var router = this.router = new Router();
@@ -22436,12 +22999,70 @@ var get = Ember.get, set = Ember.set,
22436
22999
  classify = Ember.String.classify,
22437
23000
  decamelize = Ember.String.decamelize;
22438
23001
 
23002
+ /**
23003
+ The `Ember.Route` class is used to define individual routes. Refer to
23004
+ the [routing guide](http://emberjs.com/guides/routing/) for documentation.
22439
23005
 
23006
+ @class Route
23007
+ @namespace Ember
23008
+ @extends Ember.Object
23009
+ */
22440
23010
  Ember.Route = Ember.Object.extend({
23011
+ /**
23012
+ @private
23013
+
23014
+ @method exit
23015
+ */
22441
23016
  exit: function() {
23017
+ this.deactivate();
22442
23018
  teardownView(this);
22443
23019
  },
22444
23020
 
23021
+ /**
23022
+ @private
23023
+
23024
+ @method enter
23025
+ */
23026
+ enter: function() {
23027
+ this.activate();
23028
+ },
23029
+
23030
+ /**
23031
+ The collection of functions keyed by name available on this route as
23032
+ action targets.
23033
+
23034
+ These functions will be invoked when a matching `{{action}}` is triggered
23035
+ from within a template and the application's current route is this route.
23036
+
23037
+ Events can also be invoked from other parts of your application via `Route#send`.
23038
+
23039
+ The context of event will be the this route.
23040
+
23041
+ @see {Ember.Route#send}
23042
+ @see {Handlebars.helpers.action}
23043
+
23044
+ @property events
23045
+ @type Hash
23046
+ @default null
23047
+ */
23048
+ events: null,
23049
+
23050
+ /**
23051
+ This hook is executed when the router completely exits this route. It is
23052
+ not executed when the model for the route changes.
23053
+
23054
+ @method deactivate
23055
+ */
23056
+ deactivate: Ember.K,
23057
+
23058
+ /**
23059
+ This hook is executed when the router enters the route for the first time.
23060
+ It is not executed when the model for the route changes.
23061
+
23062
+ @method activate
23063
+ */
23064
+ activate: Ember.K,
23065
+
22445
23066
  /**
22446
23067
  Transition into another route. Optionally supply a model for the
22447
23068
  route in question. The model will be serialized into the URL
@@ -22452,7 +23073,7 @@ Ember.Route = Ember.Object.extend({
22452
23073
  @param {...Object} models the
22453
23074
  */
22454
23075
  transitionTo: function() {
22455
- this.transitioned = true;
23076
+ if (this._checkingRedirect) { this.redirected = true; }
22456
23077
  return this.router.transitionTo.apply(this.router, arguments);
22457
23078
  },
22458
23079
 
@@ -22465,7 +23086,7 @@ Ember.Route = Ember.Object.extend({
22465
23086
  @param {...Object} models the
22466
23087
  */
22467
23088
  replaceWith: function() {
22468
- this.transitioned = true;
23089
+ if (this._checkingRedirect) { this.redirected = true; }
22469
23090
  return this.router.replaceWith.apply(this.router, arguments);
22470
23091
  },
22471
23092
 
@@ -22481,14 +23102,18 @@ Ember.Route = Ember.Object.extend({
22481
23102
  @method setup
22482
23103
  */
22483
23104
  setup: function(context) {
22484
- this.transitioned = false;
23105
+ this.redirected = false;
23106
+ this._checkingRedirect = true;
23107
+
22485
23108
  this.redirect(context);
22486
23109
 
22487
- if (this.transitioned) { return; }
23110
+ this._checkingRedirect = false;
23111
+ if (this.redirected) { return false; }
22488
23112
 
22489
23113
  var controller = this.controllerFor(this.routeName, context);
22490
23114
 
22491
23115
  if (controller) {
23116
+ this.controller = controller;
22492
23117
  set(controller, 'model', context);
22493
23118
  }
22494
23119
 
@@ -22563,16 +23188,18 @@ Ember.Route = Ember.Object.extend({
22563
23188
  @param {Object} params the parameters extracted from the URL
22564
23189
  */
22565
23190
  model: function(params) {
22566
- var match, name, value;
23191
+ var match, name, sawParams, value;
22567
23192
 
22568
23193
  for (var prop in params) {
22569
23194
  if (match = prop.match(/^(.*)_id$/)) {
22570
23195
  name = match[1];
22571
23196
  value = params[prop];
22572
23197
  }
23198
+ sawParams = true;
22573
23199
  }
22574
23200
 
22575
- if (!name) { return; }
23201
+ if (!name && sawParams) { return params; }
23202
+ else if (!name) { return; }
22576
23203
 
22577
23204
  var className = classify(name),
22578
23205
  namespace = this.router.namespace,
@@ -22620,7 +23247,12 @@ Ember.Route = Ember.Object.extend({
22620
23247
  if (params.length !== 1) { return; }
22621
23248
 
22622
23249
  var name = params[0], object = {};
22623
- object[name] = get(model, 'id');
23250
+
23251
+ if (/_id$/.test(name)) {
23252
+ object[name] = get(model, 'id');
23253
+ } else {
23254
+ object[name] = model;
23255
+ }
22624
23256
 
22625
23257
  return object;
22626
23258
  },
@@ -22789,12 +23421,16 @@ Ember.Route = Ember.Object.extend({
22789
23421
 
22790
23422
  if (!view && !template) { return; }
22791
23423
 
22792
- this.lastRenderedTemplate = name;
22793
-
22794
23424
  options = normalizeOptions(this, name, template, options);
22795
23425
  view = setupView(view, container, options);
22796
23426
 
23427
+ if (options.outlet === 'main') { this.lastRenderedTemplate = name; }
23428
+
22797
23429
  appendView(this, view, options);
23430
+ },
23431
+
23432
+ willDestroy: function() {
23433
+ teardownView(this);
22798
23434
  }
22799
23435
  });
22800
23436
 
@@ -22810,15 +23446,17 @@ function parentRoute(route) {
22810
23446
  }
22811
23447
  }
22812
23448
 
22813
- function parentTemplate(route) {
23449
+ function parentTemplate(route, isRecursive) {
22814
23450
  var parent = parentRoute(route), template;
22815
23451
 
22816
23452
  if (!parent) { return; }
22817
23453
 
23454
+ Ember.warn("The immediate parent route did not render into the main outlet and the default 'into' option may not be expected", !isRecursive);
23455
+
22818
23456
  if (template = parent.lastRenderedTemplate) {
22819
23457
  return template;
22820
23458
  } else {
22821
- return parentTemplate(parent);
23459
+ return parentTemplate(parent, true);
22822
23460
  }
22823
23461
  }
22824
23462
 
@@ -22829,6 +23467,8 @@ function normalizeOptions(route, name, template, options) {
22829
23467
  options.name = name;
22830
23468
  options.template = template;
22831
23469
 
23470
+ Ember.assert("An outlet ("+options.outlet+") was specified but this view will render at the root level.", options.outlet === 'main' || options.into);
23471
+
22832
23472
  var controller = options.controller, namedController;
22833
23473
 
22834
23474
  if (options.controller) {
@@ -22855,6 +23495,8 @@ function setupView(view, container, options) {
22855
23495
 
22856
23496
  if (!get(view, 'templateName')) {
22857
23497
  set(view, 'template', options.template);
23498
+
23499
+ set(view, '_debugTemplateName', options.name);
22858
23500
  }
22859
23501
 
22860
23502
  set(view, 'renderedName', options.name);
@@ -22877,7 +23519,7 @@ function appendView(route, view, options) {
22877
23519
  }
22878
23520
 
22879
23521
  function teardownTopLevel(view) {
22880
- return function() { view.remove(); };
23522
+ return function() { view.destroy(); };
22881
23523
  }
22882
23524
 
22883
23525
  function teardownOutlet(parentView, outlet) {
@@ -22902,10 +23544,15 @@ function teardownView(route) {
22902
23544
 
22903
23545
 
22904
23546
  (function() {
23547
+ /**
23548
+ @module ember
23549
+ @submodule ember-routing
23550
+ */
23551
+
22905
23552
  var get = Ember.get, set = Ember.set;
22906
23553
  Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22907
23554
 
22908
- var resolvePaths = Ember.Handlebars.resolvePaths,
23555
+ var resolveParams = Ember.Handlebars.resolveParams,
22909
23556
  isSimpleClick = Ember.ViewUtils.isSimpleClick;
22910
23557
 
22911
23558
  function fullRouteName(router, name) {
@@ -22916,8 +23563,11 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22916
23563
  return name;
22917
23564
  }
22918
23565
 
22919
- function resolvedPaths(linkView) {
22920
- return resolvePaths(linkView.parameters);
23566
+ function resolvedPaths(options) {
23567
+ var types = options.options.types.slice(1),
23568
+ data = options.options.data;
23569
+
23570
+ return resolveParams(options.context, options.params, { types: types, data: data });
22921
23571
  }
22922
23572
 
22923
23573
  function args(linkView, router, route) {
@@ -22928,7 +23578,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22928
23578
  Ember.assert("The route " + passedRouteName + " was not found", router.hasRoute(routeName));
22929
23579
 
22930
23580
  var ret = [ routeName ];
22931
- return ret.concat(resolvePaths(linkView.parameters));
23581
+ return ret.concat(resolvedPaths(linkView.parameters));
22932
23582
  }
22933
23583
 
22934
23584
  var LinkView = Ember.View.extend({
@@ -22941,9 +23591,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22941
23591
  attributeBindings: ['href', 'title'],
22942
23592
  classNameBindings: 'active',
22943
23593
 
23594
+ // Even though this isn't a virtual view, we want to treat it as if it is
23595
+ // so that you can access the parent with {{view.prop}}
23596
+ concreteView: Ember.computed(function() {
23597
+ return get(this, 'parentView');
23598
+ }).property('parentView').volatile(),
23599
+
22944
23600
  active: Ember.computed(function() {
22945
23601
  var router = this.get('router'),
22946
- params = resolvedPaths(this),
23602
+ params = resolvedPaths(this.parameters),
22947
23603
  currentWithIndex = this.currentWhen + '.index',
22948
23604
  isActive = router.isActive.apply(router, [this.currentWhen].concat(params)) ||
22949
23605
  router.isActive.apply(router, [currentWithIndex].concat(params));
@@ -22978,9 +23634,16 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22978
23634
 
22979
23635
  LinkView.toString = function() { return "LinkView"; };
22980
23636
 
23637
+ /**
23638
+ @method linkTo
23639
+ @for Ember.Handlebars.helpers
23640
+ @param {String} routeName
23641
+ @param {Object} [context]*
23642
+ @return {String} HTML string
23643
+ */
22981
23644
  Ember.Handlebars.registerHelper('linkTo', function(name) {
22982
23645
  var options = [].slice.call(arguments, -1)[0];
22983
- var contexts = [].slice.call(arguments, 1, -1);
23646
+ var params = [].slice.call(arguments, 1, -1);
22984
23647
 
22985
23648
  var hash = options.hash;
22986
23649
 
@@ -22988,9 +23651,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22988
23651
  hash.currentWhen = hash.currentWhen || name;
22989
23652
 
22990
23653
  hash.parameters = {
22991
- data: options.data,
22992
- contexts: contexts,
22993
- roots: options.contexts
23654
+ context: this,
23655
+ options: options,
23656
+ params: params
22994
23657
  };
22995
23658
 
22996
23659
  return Ember.Handlebars.helpers.view.call(this, LinkView, options);
@@ -23074,45 +23737,6 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23074
23737
 
23075
23738
  return Handlebars.helpers.view.call(this, Handlebars.OutletView, options);
23076
23739
  });
23077
-
23078
- Ember.View.reopen({
23079
- init: function() {
23080
- set(this, '_outlets', {});
23081
- this._super();
23082
- },
23083
-
23084
- connectOutlet: function(outletName, view) {
23085
- var outlets = get(this, '_outlets'),
23086
- container = get(this, 'container'),
23087
- router = container && container.lookup('router:main'),
23088
- oldView = get(outlets, outletName),
23089
- renderedName = get(view, 'renderedName');
23090
-
23091
- set(outlets, outletName, view);
23092
-
23093
- if (router) {
23094
- if (oldView) {
23095
- router._disconnectActiveView(oldView);
23096
- }
23097
- if (renderedName) {
23098
- router._connectActiveView(renderedName, view);
23099
- }
23100
- }
23101
- },
23102
-
23103
- disconnectOutlet: function(outletName) {
23104
- var outlets = get(this, '_outlets'),
23105
- container = get(this, 'container'),
23106
- router = container && container.lookup('router:main'),
23107
- view = get(outlets, outletName);
23108
-
23109
- set(outlets, outletName, null);
23110
-
23111
- if (router && view) {
23112
- router._disconnectActiveView(view);
23113
- }
23114
- }
23115
- });
23116
23740
  });
23117
23741
 
23118
23742
  })();
@@ -23128,17 +23752,34 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23128
23752
  var get = Ember.get, set = Ember.set;
23129
23753
  Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23130
23754
 
23131
- Ember.Handlebars.registerHelper('render', function(name, context, options) {
23755
+ /**
23756
+ Renders the named template in the current context using the singleton
23757
+ instance of the same-named controller.
23758
+
23759
+ If a view class with the same name exists, uses the view class.
23760
+
23761
+ If a `model` is specified, it becomes the model for that controller.
23762
+
23763
+ The default target for `{{action}}`s in the rendered template is the
23764
+ named controller.
23765
+
23766
+ @method action
23767
+ @for Ember.Handlebars.helpers
23768
+ @param {String} actionName
23769
+ @param {Object?} model
23770
+ @param {Hash} options
23771
+ */
23772
+ Ember.Handlebars.registerHelper('render', function(name, contextString, options) {
23132
23773
  Ember.assert("You must pass a template to render", arguments.length >= 2);
23133
- var container, router, controller, view;
23774
+ var container, router, controller, view, context;
23134
23775
 
23135
23776
  if (arguments.length === 2) {
23136
- options = context;
23137
- context = undefined;
23777
+ options = contextString;
23778
+ contextString = undefined;
23138
23779
  }
23139
23780
 
23140
- if (typeof context === 'string') {
23141
- context = Ember.Handlebars.get(options.contexts[1], context, options);
23781
+ if (typeof contextString === 'string') {
23782
+ context = Ember.Handlebars.get(options.contexts[1], contextString, options);
23142
23783
  }
23143
23784
 
23144
23785
  name = name.replace(/\//g, '.');
@@ -23159,6 +23800,14 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23159
23800
  controller.set('model', context);
23160
23801
  }
23161
23802
 
23803
+ var root = options.contexts[1];
23804
+
23805
+ if (root) {
23806
+ view.registerObserver(root, contextString, function() {
23807
+ controller.set('model', Ember.Handlebars.get(root, contextString, options));
23808
+ });
23809
+ }
23810
+
23162
23811
  controller.set('target', options.data.keywords.controller);
23163
23812
 
23164
23813
  options.hash.viewName = Ember.String.camelize(name);
@@ -23185,7 +23834,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23185
23834
  */
23186
23835
  Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23187
23836
 
23188
- var resolvePaths = Ember.Handlebars.resolvePaths,
23837
+ var resolveParams = Ember.Handlebars.resolveParams,
23189
23838
  isSimpleClick = Ember.ViewUtils.isSimpleClick;
23190
23839
 
23191
23840
  var EmberHandlebars = Ember.Handlebars,
@@ -23197,7 +23846,11 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23197
23846
  function args(options, actionName) {
23198
23847
  var ret = [];
23199
23848
  if (actionName) { ret.push(actionName); }
23200
- return ret.concat(resolvePaths(options.parameters));
23849
+
23850
+ var types = options.options.types.slice(1),
23851
+ data = options.options.data;
23852
+
23853
+ return ret.concat(resolveParams(options.context, options.params, { types: types, data: data }));
23201
23854
  }
23202
23855
 
23203
23856
  var ActionHelper = EmberHandlebars.ActionHelper = {
@@ -23221,12 +23874,20 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23221
23874
  contexts = options.contexts,
23222
23875
  target = options.target;
23223
23876
 
23224
- if (target.send) {
23225
- return target.send.apply(target, args(options, actionName));
23877
+ if (target.target) {
23878
+ target = handlebarsGet(target.root, target.target, target.options);
23226
23879
  } else {
23227
- Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
23228
- return target[actionName].apply(target, args(options));
23880
+ target = target.root;
23229
23881
  }
23882
+
23883
+ Ember.run(function() {
23884
+ if (target.send) {
23885
+ target.send.apply(target, args(options.parameters, actionName));
23886
+ } else {
23887
+ Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
23888
+ target[actionName].apply(target, args(options.parameters));
23889
+ }
23890
+ });
23230
23891
  }
23231
23892
  };
23232
23893
 
@@ -23406,7 +24067,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23406
24067
  @method action
23407
24068
  @for Ember.Handlebars.helpers
23408
24069
  @param {String} actionName
23409
- @param {Object...} contexts
24070
+ @param {Object} [context]*
23410
24071
  @param {Hash} options
23411
24072
  */
23412
24073
  EmberHandlebars.registerHelper('action', function(actionName) {
@@ -23415,7 +24076,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23415
24076
 
23416
24077
  var hash = options.hash,
23417
24078
  view = options.data.view,
23418
- target, controller, link;
24079
+ controller, link;
23419
24080
 
23420
24081
  // create a hash to pass along to registerAction
23421
24082
  var action = {
@@ -23423,20 +24084,23 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23423
24084
  };
23424
24085
 
23425
24086
  action.parameters = {
23426
- data: options.data,
23427
- contexts: contexts,
23428
- roots: options.contexts
24087
+ context: this,
24088
+ options: options,
24089
+ params: contexts
23429
24090
  };
23430
24091
 
23431
24092
  action.view = view = get(view, 'concreteView');
23432
24093
 
24094
+ var root, target;
24095
+
23433
24096
  if (hash.target) {
23434
- target = handlebarsGet(this, hash.target, options);
24097
+ root = this;
24098
+ target = hash.target;
23435
24099
  } else if (controller = options.data.keywords.controller) {
23436
- target = controller;
24100
+ root = controller;
23437
24101
  }
23438
24102
 
23439
- action.target = target;
24103
+ action.target = { root: root, target: target, options: options };
23440
24104
  action.bubbles = hash.bubbles;
23441
24105
 
23442
24106
  var actionId = ActionHelper.registerAction(actionName, action);
@@ -23449,6 +24113,86 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23449
24113
 
23450
24114
 
23451
24115
 
24116
+ (function() {
24117
+ /**
24118
+ @module ember
24119
+ @submodule ember-routing
24120
+ */
24121
+
24122
+ if (Ember.ENV.EXPERIMENTAL_CONTROL_HELPER) {
24123
+ var get = Ember.get, set = Ember.set;
24124
+
24125
+ /**
24126
+ The control helper is currently under development and is considered experimental.
24127
+ To enable it, set `ENV.EXPERIMENTAL_CONTROL_HELPER = true` before requiring Ember.
24128
+
24129
+ @method control
24130
+ @for Ember.Handlebars.helpers
24131
+ @param {String} path
24132
+ @param {String} modelPath
24133
+ @param {Hash} options
24134
+ @return {String} HTML string
24135
+ */
24136
+ Ember.Handlebars.registerHelper('control', function(path, modelPath, options) {
24137
+ if (arguments.length === 2) {
24138
+ options = modelPath;
24139
+ modelPath = undefined;
24140
+ }
24141
+
24142
+ var model;
24143
+
24144
+ if (modelPath) {
24145
+ model = Ember.Handlebars.get(this, modelPath, options);
24146
+ }
24147
+
24148
+ var controller = options.data.keywords.controller,
24149
+ view = options.data.keywords.view,
24150
+ children = get(controller, '_childContainers'),
24151
+ controlID = options.hash.controlID,
24152
+ container, subContainer;
24153
+
24154
+ if (children.hasOwnProperty(controlID)) {
24155
+ subContainer = children[controlID];
24156
+ } else {
24157
+ container = get(controller, 'container'),
24158
+ subContainer = container.child();
24159
+ children[controlID] = subContainer;
24160
+ }
24161
+
24162
+ var normalizedPath = path.replace(/\//g, '.');
24163
+
24164
+ var childView = subContainer.lookup('view:' + normalizedPath) || subContainer.lookup('view:default'),
24165
+ childController = subContainer.lookup('controller:' + normalizedPath),
24166
+ childTemplate = subContainer.lookup('template:' + path);
24167
+
24168
+ Ember.assert("Could not find controller for path: " + normalizedPath, childController);
24169
+ Ember.assert("Could not find view for path: " + normalizedPath, childView);
24170
+
24171
+ set(childController, 'target', controller);
24172
+ set(childController, 'model', model);
24173
+
24174
+ options.hash.template = childTemplate;
24175
+ options.hash.controller = childController;
24176
+
24177
+ function observer() {
24178
+ var model = Ember.Handlebars.get(this, modelPath, options);
24179
+ set(childController, 'model', model);
24180
+ childView.rerender();
24181
+ }
24182
+
24183
+ Ember.addObserver(this, modelPath, observer);
24184
+ childView.one('willDestroyElement', this, function() {
24185
+ Ember.removeObserver(this, modelPath, observer);
24186
+ });
24187
+
24188
+ Ember.Handlebars.helpers.view.call(this, childView, options);
24189
+ });
24190
+ }
24191
+
24192
+ })();
24193
+
24194
+
24195
+
23452
24196
  (function() {
23453
24197
 
23454
24198
  })();
@@ -23462,95 +24206,32 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23462
24206
  */
23463
24207
 
23464
24208
  var get = Ember.get, set = Ember.set;
23465
- var ControllersProxy = Ember.Object.extend({
23466
- controller: null,
23467
-
23468
- unknownProperty: function(controllerName) {
23469
- var controller = get(this, 'controller'),
23470
- needs = get(controller, 'needs'),
23471
- dependency;
23472
-
23473
- for (var i=0, l=needs.length; i<l; i++) {
23474
- dependency = needs[i];
23475
- if (dependency === controllerName) {
23476
- return controller.controllerFor(controllerName);
23477
- }
23478
- }
23479
- }
23480
- });
23481
24209
 
23482
24210
  Ember.ControllerMixin.reopen({
23483
- concatenatedProperties: ['needs'],
23484
- needs: [],
23485
-
23486
- init: function() {
23487
- this._super.apply(this, arguments);
23488
-
23489
- // Structure asserts to still do verification but not string concat in production
23490
- if(!verifyDependencies(this)) {
23491
- Ember.assert("Missing dependencies", false);
23492
- }
23493
- },
23494
-
23495
24211
  transitionToRoute: function() {
23496
- var target = get(this, 'target');
23497
-
23498
- return target.transitionTo.apply(target, arguments);
24212
+ // target may be either another controller or a router
24213
+ var target = get(this, 'target'),
24214
+ method = target.transitionToRoute || target.transitionTo;
24215
+ return method.apply(target, arguments);
23499
24216
  },
23500
24217
 
23501
- // TODO: Deprecate this, see https://github.com/emberjs/ember.js/issues/1785
23502
24218
  transitionTo: function() {
24219
+ Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute.");
23503
24220
  return this.transitionToRoute.apply(this, arguments);
23504
24221
  },
23505
24222
 
23506
24223
  replaceRoute: function() {
23507
- var target = get(this, 'target');
23508
-
23509
- return target.replaceWith.apply(target, arguments);
24224
+ // target may be either another controller or a router
24225
+ var target = get(this, 'target'),
24226
+ method = target.replaceRoute || target.replaceWith;
24227
+ return method.apply(target, arguments);
23510
24228
  },
23511
24229
 
23512
- // TODO: Deprecate this, see https://github.com/emberjs/ember.js/issues/1785
23513
24230
  replaceWith: function() {
24231
+ Ember.deprecate("replaceWith is deprecated. Please use replaceRoute.");
23514
24232
  return this.replaceRoute.apply(this, arguments);
23515
- },
23516
-
23517
- controllerFor: function(controllerName) {
23518
- var container = get(this, 'container');
23519
- return container.lookup('controller:' + controllerName);
23520
- },
23521
-
23522
- model: Ember.computed(function(key, value) {
23523
- if (arguments.length > 1) {
23524
- return set(this, 'content', value);
23525
- } else {
23526
- return get(this, 'content');
23527
- }
23528
- }).property('content'),
23529
-
23530
- controllers: Ember.computed(function() {
23531
- return ControllersProxy.create({ controller: this });
23532
- })
23533
- });
23534
-
23535
- function verifyDependencies(controller) {
23536
- var needs = get(controller, 'needs'),
23537
- container = get(controller, 'container'),
23538
- dependency, satisfied = true;
23539
-
23540
- for (var i=0, l=needs.length; i<l; i++) {
23541
- dependency = needs[i];
23542
- if (dependency.indexOf(':') === -1) {
23543
- dependency = "controller:" + dependency;
23544
- }
23545
-
23546
- if (!container.has(dependency)) {
23547
- satisfied = false;
23548
- Ember.assert(controller + " needs " + dependency + " but it does not exist", false);
23549
- }
23550
24233
  }
23551
-
23552
- return satisfied;
23553
- }
24234
+ });
23554
24235
 
23555
24236
  })();
23556
24237
 
@@ -23687,7 +24368,12 @@ Ember.NoneLocation = Ember.Object.extend({
23687
24368
  },
23688
24369
 
23689
24370
  onUpdateURL: function(callback) {
23690
- // We are not wired up to the browser, so we'll never trigger the callback.
24371
+ this.updateCallback = callback;
24372
+ },
24373
+
24374
+ handleURL: function(url) {
24375
+ set(this, 'path', url);
24376
+ this.updateCallback(url);
23691
24377
  },
23692
24378
 
23693
24379
  formatURL: function(url) {
@@ -23768,12 +24454,14 @@ Ember.HashLocation = Ember.Object.extend({
23768
24454
  var guid = Ember.guidFor(this);
23769
24455
 
23770
24456
  Ember.$(window).bind('hashchange.ember-location-'+guid, function() {
23771
- var path = location.hash.substr(1);
23772
- if (get(self, 'lastSetURL') === path) { return; }
24457
+ Ember.run(function() {
24458
+ var path = location.hash.substr(1);
24459
+ if (get(self, 'lastSetURL') === path) { return; }
23773
24460
 
23774
- set(self, 'lastSetURL', null);
24461
+ set(self, 'lastSetURL', null);
23775
24462
 
23776
- callback(location.hash.substr(1));
24463
+ callback(location.hash.substr(1));
24464
+ });
23777
24465
  });
23778
24466
  },
23779
24467
 
@@ -23838,7 +24526,7 @@ Ember.HistoryLocation = Ember.Object.extend({
23838
24526
  @method initState
23839
24527
  */
23840
24528
  initState: function() {
23841
- this.replaceState(get(this, 'location').pathname);
24529
+ this.replaceState(this.formatURL(this.getURL()));
23842
24530
  set(this, 'history', window.history);
23843
24531
  },
23844
24532
 
@@ -23853,12 +24541,18 @@ Ember.HistoryLocation = Ember.Object.extend({
23853
24541
  /**
23854
24542
  @private
23855
24543
 
23856
- Returns the current `location.pathname`.
24544
+ Returns the current `location.pathname` without rootURL
23857
24545
 
23858
24546
  @method getURL
23859
24547
  */
23860
24548
  getURL: function() {
23861
- return get(this, 'location').pathname;
24549
+ var rootURL = get(this, 'rootURL'),
24550
+ url = get(this, 'location').pathname;
24551
+
24552
+ rootURL = rootURL.replace(/\/$/, '');
24553
+ url = url.replace(rootURL, '');
24554
+
24555
+ return url;
23862
24556
  },
23863
24557
 
23864
24558
  /**
@@ -23941,13 +24635,14 @@ Ember.HistoryLocation = Ember.Object.extend({
23941
24635
  @param callback {Function}
23942
24636
  */
23943
24637
  onUpdateURL: function(callback) {
23944
- var guid = Ember.guidFor(this);
24638
+ var guid = Ember.guidFor(this),
24639
+ self = this;
23945
24640
 
23946
24641
  Ember.$(window).bind('popstate.ember-location-'+guid, function(e) {
23947
24642
  if(!popstateReady) {
23948
24643
  return;
23949
24644
  }
23950
- callback(location.pathname);
24645
+ callback(self.getURL());
23951
24646
  });
23952
24647
  },
23953
24648
 
@@ -24209,68 +24904,32 @@ var get = Ember.get, set = Ember.set,
24209
24904
  layer, and a list of the event listeners that are setup by default, visit the
24210
24905
  [Ember View Layer guide](http://emberjs.com/guides/view_layer#toc_event-delegation).
24211
24906
 
24212
- ### Dependency Injection
24907
+ ### Initializers
24213
24908
 
24214
- One thing you may have noticed while using Ember is that you define
24215
- *classes*, not *instances*. When your application loads, all of the instances
24216
- are created for you. Creating these instances is the responsibility of
24217
- `Ember.Application`.
24218
-
24219
- When the `Ember.Application` initializes, it will look for an `Ember.Router`
24220
- class defined on the applications's `Router` property, like this:
24909
+ Libraries on top of Ember can register additional initializers, like so:
24221
24910
 
24222
24911
  ```javascript
24223
- App.Router = Ember.Router.extend({
24224
- // ...
24225
- });
24226
- ```
24912
+ Ember.Application.initializer({
24913
+ name: "store",
24227
24914
 
24228
- If found, the router is instantiated and saved on the application's `router`
24229
- property (note the lowercase 'r'). While you should *not* reference this
24230
- router instance directly from your application code, having access to
24231
- `App.router` from the console can be useful during debugging.
24232
-
24233
- After the router is created, the application loops through all of the
24234
- registered _injections_ and invokes them once for each property on the
24235
- `Ember.Application` object.
24236
-
24237
- An injection is a function that is responsible for instantiating objects from
24238
- classes defined on the application. By default, the only injection registered
24239
- instantiates controllers and makes them available on the router.
24240
-
24241
- For example, if you define a controller class:
24242
-
24243
- ```javascript
24244
- App.MyController = Ember.Controller.extend({
24245
- // ...
24915
+ initialize: function(container, application) {
24916
+ container.register('store', 'main', application.Store);
24917
+ }
24246
24918
  });
24247
24919
  ```
24248
24920
 
24249
- Your router will receive an instance of `App.MyController` saved on its
24250
- `myController` property.
24921
+ ### Routing
24251
24922
 
24252
- Libraries on top of Ember can register additional injections. For example,
24253
- if your application is using Ember Data, it registers an injection that
24254
- instantiates `DS.Store`:
24923
+ In addition to creating your application's router, `Ember.Application` is
24924
+ also responsible for telling the router when to start routing. Transitions
24925
+ between routes can be logged with the LOG_TRANSITIONS flag:
24255
24926
 
24256
24927
  ```javascript
24257
- Ember.Application.registerInjection({
24258
- name: 'store',
24259
- before: 'controllers',
24260
-
24261
- injection: function(app, router, property) {
24262
- if (property === 'Store') {
24263
- set(router, 'store', app[property].create());
24264
- }
24265
- }
24928
+ window.App = Ember.Application.create({
24929
+ LOG_TRANSITIONS: true
24266
24930
  });
24267
24931
  ```
24268
24932
 
24269
- ### Routing
24270
-
24271
- In addition to creating your application's router, `Ember.Application` is
24272
- also responsible for telling the router when to start routing.
24273
-
24274
24933
  By default, the router will begin trying to translate the current URL into
24275
24934
  application state once the browser emits the `DOMContentReady` event. If you
24276
24935
  need to defer routing, you can call the application's `deferReadiness()`
@@ -24278,14 +24937,7 @@ var get = Ember.get, set = Ember.set,
24278
24937
 
24279
24938
  If there is any setup required before routing begins, you can implement a
24280
24939
  `ready()` method on your app that will be invoked immediately before routing
24281
- begins:
24282
-
24283
- ```javascript
24284
- window.App = Ember.Application.create({
24285
- ready: function() {
24286
- this.set('router.enableLogging', true);
24287
- }
24288
- });
24940
+ begins.
24289
24941
 
24290
24942
  To begin routing, you must have at a minimum a top-level controller and view.
24291
24943
  You define these as `App.ApplicationController` and `App.ApplicationView`,
@@ -24303,8 +24955,7 @@ var get = Ember.get, set = Ember.set,
24303
24955
  @namespace Ember
24304
24956
  @extends Ember.Namespace
24305
24957
  */
24306
- var Application = Ember.Application = Ember.Namespace.extend(
24307
- /** @scope Ember.Application.prototype */{
24958
+ var Application = Ember.Application = Ember.Namespace.extend({
24308
24959
 
24309
24960
  /**
24310
24961
  The root DOM element of the Application. This can be specified as an
@@ -24383,6 +25034,12 @@ var Application = Ember.Application = Ember.Namespace.extend(
24383
25034
 
24384
25035
  this.deferUntilDOMReady();
24385
25036
  this.scheduleInitialize();
25037
+
25038
+ Ember.debug('-------------------------------');
25039
+ Ember.debug('Ember.VERSION : ' + Ember.VERSION);
25040
+ Ember.debug('Handlebars.VERSION : ' + Ember.Handlebars.VERSION);
25041
+ Ember.debug('jQuery.VERSION : ' + Ember.$().jquery);
25042
+ Ember.debug('-------------------------------');
24386
25043
  },
24387
25044
 
24388
25045
  /**
@@ -24514,9 +25171,52 @@ var Application = Ember.Application = Ember.Namespace.extend(
24514
25171
  }
24515
25172
  },
24516
25173
 
25174
+ /**
25175
+ registers a factory for later injection
25176
+
25177
+ Example:
25178
+
25179
+ ```javascript
25180
+ App = Ember.Application.create();
25181
+
25182
+ App.Person = Ember.Object.extend({});
25183
+ App.Orange = Ember.Object.extend({});
25184
+ App.Email = Ember.Object.extend({});
25185
+
25186
+ App.register('model:user', App.Person, {singleton: false });
25187
+ App.register('fruit:favorite', App.Orange);
25188
+ App.register('communication:main', App.Email, {singleton: false});
25189
+ ```
25190
+
25191
+ @method register
25192
+ @param type {String}
25193
+ @param name {String}
25194
+ @param factory {String}
25195
+ @param options {String} (optional)
25196
+ **/
24517
25197
  register: function() {
24518
25198
  var container = this.__container__;
24519
- return container.register.apply(container, arguments);
25199
+ container.register.apply(container, arguments);
25200
+ },
25201
+ /**
25202
+ defines an injection or typeInjection
25203
+
25204
+ Example:
25205
+
25206
+ ```javascript
25207
+ App.inject(<full_name or type>, <property name>, <full_name>)
25208
+ App.inject('model:user', 'email', 'model:email')
25209
+ App.inject('model', 'source', 'source:main')
25210
+ ```
25211
+
25212
+ @method inject
25213
+ @param factoryNameOrType {String}
25214
+ @param property {String}
25215
+ @param injectionName {String}
25216
+ **/
25217
+ inject: function(){
25218
+ var container = this.__container__;
25219
+ container.injection.apply(container, arguments);
24520
25220
  },
24521
25221
 
24522
25222
  /**
@@ -24524,7 +25224,7 @@ var Application = Ember.Application = Ember.Namespace.extend(
24524
25224
 
24525
25225
  Initialize the application. This happens automatically.
24526
25226
 
24527
- Run any injections and run the application load hook. These hooks may
25227
+ Run any initializers and run the application load hook. These hooks may
24528
25228
  choose to defer readiness. For example, an authentication hook might want
24529
25229
  to defer readiness until the auth token has been retrieved.
24530
25230
 
@@ -24538,13 +25238,10 @@ var Application = Ember.Application = Ember.Namespace.extend(
24538
25238
  // At this point, the App.Router must already be assigned
24539
25239
  this.__container__.register('router', 'main', this.Router);
24540
25240
 
24541
- // Run any injections and run the application load hook. These hooks may
24542
- // choose to defer readiness. For example, an authentication hook might want
24543
- // to defer readiness until the auth token has been retrieved.
24544
25241
  this.runInitializers();
24545
25242
  Ember.runLoadHooks('application', this);
24546
25243
 
24547
- // At this point, any injections or load hooks that would have wanted
25244
+ // At this point, any initializers or load hooks that would have wanted
24548
25245
  // to defer readiness have fired. In general, advancing readiness here
24549
25246
  // will proceed to didBecomeReady.
24550
25247
  this.advanceReadiness();
@@ -24552,6 +25249,15 @@ var Application = Ember.Application = Ember.Namespace.extend(
24552
25249
  return this;
24553
25250
  },
24554
25251
 
25252
+ reset: function() {
25253
+ get(this, '__container__').destroy();
25254
+ this.buildContainer();
25255
+
25256
+ this.isInitialized = false;
25257
+ this.initialize();
25258
+ this.startRouting();
25259
+ },
25260
+
24555
25261
  /**
24556
25262
  @private
24557
25263
  @method runInitializers
@@ -24639,6 +25345,12 @@ var Application = Ember.Application = Ember.Namespace.extend(
24639
25345
  router.startRouting();
24640
25346
  },
24641
25347
 
25348
+ handleURL: function(url) {
25349
+ var router = this.__container__.lookup('router:main');
25350
+
25351
+ router.handleURL(url);
25352
+ },
25353
+
24642
25354
  /**
24643
25355
  Called when the Application has become ready.
24644
25356
  The call will be delayed until the DOM has become ready.
@@ -24653,7 +25365,7 @@ var Application = Ember.Application = Ember.Namespace.extend(
24653
25365
  var eventDispatcher = get(this, 'eventDispatcher');
24654
25366
  if (eventDispatcher) { eventDispatcher.destroy(); }
24655
25367
 
24656
- this.__container__.destroy();
25368
+ get(this, '__container__').destroy();
24657
25369
  },
24658
25370
 
24659
25371
  initializer: function(options) {
@@ -24702,7 +25414,7 @@ Ember.Application.reopenClass({
24702
25414
  */
24703
25415
  buildContainer: function(namespace) {
24704
25416
  var container = new Ember.Container();
24705
- Ember.Container.defaultContainer = container;
25417
+ Ember.Container.defaultContainer = Ember.Container.defaultContainer || container;
24706
25418
 
24707
25419
  container.set = Ember.set;
24708
25420
  container.resolver = resolverFor(namespace);
@@ -24777,6 +25489,85 @@ Ember.runLoadHooks('Ember.Application', Ember.Application);
24777
25489
 
24778
25490
 
24779
25491
 
25492
+ (function() {
25493
+ /**
25494
+ @module ember
25495
+ @submodule ember-routing
25496
+ */
25497
+
25498
+ var get = Ember.get, set = Ember.set;
25499
+ var ControllersProxy = Ember.Object.extend({
25500
+ controller: null,
25501
+
25502
+ unknownProperty: function(controllerName) {
25503
+ var controller = get(this, 'controller'),
25504
+ needs = get(controller, 'needs'),
25505
+ container = controller.get('container'),
25506
+ dependency;
25507
+
25508
+ for (var i=0, l=needs.length; i<l; i++) {
25509
+ dependency = needs[i];
25510
+ if (dependency === controllerName) {
25511
+ return container.lookup('controller:' + controllerName);
25512
+ }
25513
+ }
25514
+ }
25515
+ });
25516
+
25517
+ function verifyDependencies(controller) {
25518
+ var needs = get(controller, 'needs'),
25519
+ container = get(controller, 'container'),
25520
+ dependency, satisfied = true;
25521
+
25522
+ for (var i=0, l=needs.length; i<l; i++) {
25523
+ dependency = needs[i];
25524
+ if (dependency.indexOf(':') === -1) {
25525
+ dependency = "controller:" + dependency;
25526
+ }
25527
+
25528
+ if (!container.has(dependency)) {
25529
+ satisfied = false;
25530
+ Ember.assert(controller + " needs " + dependency + " but it does not exist", false);
25531
+ }
25532
+ }
25533
+
25534
+ return satisfied;
25535
+ }
25536
+
25537
+ Ember.ControllerMixin.reopen({
25538
+ concatenatedProperties: ['needs'],
25539
+ needs: [],
25540
+
25541
+ init: function() {
25542
+ this._super.apply(this, arguments);
25543
+
25544
+ // Structure asserts to still do verification but not string concat in production
25545
+ if(!verifyDependencies(this)) {
25546
+ Ember.assert("Missing dependencies", false);
25547
+ }
25548
+ },
25549
+
25550
+ controllerFor: function(controllerName) {
25551
+ Ember.deprecate("Controller#controllerFor is depcrecated, please use Controller#needs instead");
25552
+ var container = get(this, 'container');
25553
+ return container.lookup('controller:' + controllerName);
25554
+ },
25555
+
25556
+ controllers: Ember.computed(function() {
25557
+ return ControllersProxy.create({ controller: this });
25558
+ })
25559
+ });
25560
+
25561
+ })();
25562
+
25563
+
25564
+
25565
+ (function() {
25566
+
25567
+ })();
25568
+
25569
+
25570
+
24780
25571
  (function() {
24781
25572
  /**
24782
25573
  Ember Application
@@ -25745,9 +26536,7 @@ Ember.StateManager = Ember.State.extend({
25745
26536
  @property currentPath
25746
26537
  @type String
25747
26538
  */
25748
- currentPath: Ember.computed('currentState', function() {
25749
- return get(this, 'currentState.path');
25750
- }),
26539
+ currentPath: Ember.computed.alias('currentState.path'),
25751
26540
 
25752
26541
  /**
25753
26542
  The name of transitionEvent that this stateManager will dispatch
@@ -26035,8 +26824,8 @@ Ember States
26035
26824
 
26036
26825
 
26037
26826
  })();
26038
- // Version: v1.0.0-pre.3-19-g015138e
26039
- // Last commit: 015138e (2013-01-17 23:02:17 -0800)
26827
+ // Version: v1.0.0-rc.1
26828
+ // Last commit: 8b061b4 (2013-02-15 12:10:22 -0800)
26040
26829
 
26041
26830
 
26042
26831
  (function() {