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.
@@ -55,7 +55,7 @@ var define, requireModule;
55
55
 
56
56
  @class Ember
57
57
  @static
58
- @version 1.0.0-pre.4
58
+ @version 1.0.0-rc.1
59
59
  */
60
60
 
61
61
  if ('undefined' === typeof Ember) {
@@ -82,10 +82,10 @@ Ember.toString = function() { return "Ember"; };
82
82
  /**
83
83
  @property VERSION
84
84
  @type String
85
- @default '1.0.0-pre.4'
85
+ @default '1.0.0-rc.1'
86
86
  @final
87
87
  */
88
- Ember.VERSION = '1.0.0-pre.4';
88
+ Ember.VERSION = '1.0.0-rc.1';
89
89
 
90
90
  /**
91
91
  Standard environmental variables. You can define these in a global `ENV`
@@ -155,20 +155,12 @@ Ember.K = function() { return this; };
155
155
 
156
156
  if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; }
157
157
  if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; }
158
+ if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; }
158
159
  if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; }
159
160
  if ('undefined' === typeof Ember.deprecateFunc) {
160
161
  Ember.deprecateFunc = function(_, func) { return func; };
161
162
  }
162
163
 
163
- // These are deprecated but still supported
164
-
165
- if ('undefined' === typeof ember_assert) { exports.ember_assert = Ember.K; }
166
- if ('undefined' === typeof ember_warn) { exports.ember_warn = Ember.K; }
167
- if ('undefined' === typeof ember_deprecate) { exports.ember_deprecate = Ember.K; }
168
- if ('undefined' === typeof ember_deprecateFunc) {
169
- exports.ember_deprecateFunc = function(_, func) { return func; };
170
- }
171
-
172
164
  /**
173
165
  Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from
174
166
  jQuery master. We'll just bootstrap our own uuid now.
@@ -183,14 +175,36 @@ Ember.uuid = 0;
183
175
  // LOGGER
184
176
  //
185
177
 
178
+ function consoleMethod(name) {
179
+ if (imports.console && imports.console[name]) {
180
+ // Older IE doesn't support apply, but Chrome needs it
181
+ if (imports.console[name].apply) {
182
+ return function() {
183
+ imports.console[name].apply(imports.console, arguments);
184
+ };
185
+ } else {
186
+ return function() {
187
+ var message = Array.prototype.join.call(arguments, ', ');
188
+ imports.console[name](message);
189
+ };
190
+ }
191
+ }
192
+ }
193
+
186
194
  /**
187
- Inside Ember-Metal, simply uses the `imports.console` object.
195
+ Inside Ember-Metal, simply uses the methods from `imports.console`.
188
196
  Override this to provide more robust logging functionality.
189
197
 
190
198
  @class Logger
191
199
  @namespace Ember
192
200
  */
193
- Ember.Logger = imports.console || { log: Ember.K, warn: Ember.K, error: Ember.K, info: Ember.K, debug: Ember.K };
201
+ Ember.Logger = {
202
+ log: consoleMethod('log') || Ember.K,
203
+ warn: consoleMethod('warn') || Ember.K,
204
+ error: consoleMethod('error') || Ember.K,
205
+ info: consoleMethod('info') || Ember.K,
206
+ debug: consoleMethod('debug') || consoleMethod('info') || Ember.K
207
+ };
194
208
 
195
209
 
196
210
  // ..........................................................
@@ -1109,8 +1123,63 @@ Ember.subscribe = Ember.Instrumentation.subscribe;
1109
1123
 
1110
1124
 
1111
1125
  (function() {
1112
- /*jshint newcap:false*/
1126
+ var utils = Ember.EnumerableUtils = {
1127
+ map: function(obj, callback, thisArg) {
1128
+ return obj.map ? obj.map.call(obj, callback, thisArg) : Array.prototype.map.call(obj, callback, thisArg);
1129
+ },
1130
+
1131
+ forEach: function(obj, callback, thisArg) {
1132
+ return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : Array.prototype.forEach.call(obj, callback, thisArg);
1133
+ },
1134
+
1135
+ indexOf: function(obj, element, index) {
1136
+ return obj.indexOf ? obj.indexOf.call(obj, element, index) : Array.prototype.indexOf.call(obj, element, index);
1137
+ },
1138
+
1139
+ indexesOf: function(obj, elements) {
1140
+ return elements === undefined ? [] : utils.map(elements, function(item) {
1141
+ return utils.indexOf(obj, item);
1142
+ });
1143
+ },
1144
+
1145
+ addObject: function(array, item) {
1146
+ var index = utils.indexOf(array, item);
1147
+ if (index === -1) { array.push(item); }
1148
+ },
1113
1149
 
1150
+ removeObject: function(array, item) {
1151
+ var index = utils.indexOf(array, item);
1152
+ if (index !== -1) { array.splice(index, 1); }
1153
+ },
1154
+
1155
+ replace: function(array, idx, amt, objects) {
1156
+ if (array.replace) {
1157
+ return array.replace(idx, amt, objects);
1158
+ } else {
1159
+ var args = Array.prototype.concat.apply([idx, amt], objects);
1160
+ return array.splice.apply(array, args);
1161
+ }
1162
+ },
1163
+
1164
+ intersection: function(array1, array2) {
1165
+ var intersection = [];
1166
+
1167
+ array1.forEach(function(element) {
1168
+ if (array2.indexOf(element) >= 0) {
1169
+ intersection.push(element);
1170
+ }
1171
+ });
1172
+
1173
+ return intersection;
1174
+ }
1175
+ };
1176
+
1177
+ })();
1178
+
1179
+
1180
+
1181
+ (function() {
1182
+ /*jshint newcap:false*/
1114
1183
  /**
1115
1184
  @module ember-metal
1116
1185
  */
@@ -1188,46 +1257,6 @@ Ember.ArrayPolyfills = {
1188
1257
  indexOf: arrayIndexOf
1189
1258
  };
1190
1259
 
1191
- var utils = Ember.EnumerableUtils = {
1192
- map: function(obj, callback, thisArg) {
1193
- return obj.map ? obj.map.call(obj, callback, thisArg) : arrayMap.call(obj, callback, thisArg);
1194
- },
1195
-
1196
- forEach: function(obj, callback, thisArg) {
1197
- return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : arrayForEach.call(obj, callback, thisArg);
1198
- },
1199
-
1200
- indexOf: function(obj, element, index) {
1201
- return obj.indexOf ? obj.indexOf.call(obj, element, index) : arrayIndexOf.call(obj, element, index);
1202
- },
1203
-
1204
- indexesOf: function(obj, elements) {
1205
- return elements === undefined ? [] : utils.map(elements, function(item) {
1206
- return utils.indexOf(obj, item);
1207
- });
1208
- },
1209
-
1210
- addObject: function(array, item) {
1211
- var index = utils.indexOf(array, item);
1212
- if (index === -1) { array.push(item); }
1213
- },
1214
-
1215
- removeObject: function(array, item) {
1216
- var index = utils.indexOf(array, item);
1217
- if (index !== -1) { array.splice(index, 1); }
1218
- },
1219
-
1220
- replace: function(array, idx, amt, objects) {
1221
- if (array.replace) {
1222
- return array.replace(idx, amt, objects);
1223
- } else {
1224
- var args = Array.prototype.concat.apply([idx, amt], objects);
1225
- return array.splice.apply(array, args);
1226
- }
1227
- }
1228
- };
1229
-
1230
-
1231
1260
  if (Ember.SHIM_ES5) {
1232
1261
  if (!Array.prototype.map) {
1233
1262
  Array.prototype.map = arrayMap;
@@ -1962,6 +1991,17 @@ var Descriptor = Ember.Descriptor = function() {};
1962
1991
  // DEFINING PROPERTIES API
1963
1992
  //
1964
1993
 
1994
+ var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) {
1995
+
1996
+ };
1997
+
1998
+ var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) {
1999
+ return function() {
2000
+ var meta = this[META_KEY];
2001
+ return meta && meta.values[name];
2002
+ };
2003
+ };
2004
+
1965
2005
  /**
1966
2006
  @private
1967
2007
 
@@ -2045,13 +2085,8 @@ Ember.defineProperty = function(obj, keyName, desc, data, meta) {
2045
2085
  objectDefineProperty(obj, keyName, {
2046
2086
  configurable: true,
2047
2087
  enumerable: true,
2048
- set: function() {
2049
-
2050
- },
2051
- get: function() {
2052
- var meta = this[META_KEY];
2053
- return meta && meta.values[keyName];
2054
- }
2088
+ set: MANDATORY_SETTER_FUNCTION,
2089
+ get: DEFAULT_GETTER_FUNCTION(keyName)
2055
2090
  });
2056
2091
  } else {
2057
2092
  obj[keyName] = data;
@@ -2775,13 +2810,8 @@ Ember.watch = function(obj, keyName) {
2775
2810
  o_defineProperty(obj, keyName, {
2776
2811
  configurable: true,
2777
2812
  enumerable: true,
2778
- set: function() {
2779
-
2780
- },
2781
- get: function() {
2782
- var meta = this[META_KEY];
2783
- return meta && meta.values[keyName];
2784
- }
2813
+ set: Ember.MANDATORY_SETTER_FUNCTION,
2814
+ get: Ember.DEFAULT_GETTER_FUNCTION(keyName)
2785
2815
  });
2786
2816
  }
2787
2817
  } else {
@@ -5693,7 +5723,8 @@ define("rsvp",
5693
5723
  callbacks, callbackTuple, callback, binding, event;
5694
5724
 
5695
5725
  if (callbacks = allCallbacks[eventName]) {
5696
- for (var i=0, l=callbacks.length; i<l; i++) {
5726
+ // Don't cache the callbacks.length since it may grow
5727
+ for (var i=0; i<callbacks.length; i++) {
5697
5728
  callbackTuple = callbacks[i];
5698
5729
  callback = callbackTuple[0];
5699
5730
  binding = callbackTuple[1];
@@ -5811,9 +5842,41 @@ define("rsvp",
5811
5842
  });
5812
5843
  }
5813
5844
 
5845
+ function all(promises) {
5846
+ var i, results = [];
5847
+ var allPromise = new Promise();
5848
+ var remaining = promises.length;
5849
+
5850
+ if (remaining === 0) {
5851
+ allPromise.resolve([]);
5852
+ }
5853
+
5854
+ var resolver = function(index) {
5855
+ return function(value) {
5856
+ resolve(index, value);
5857
+ };
5858
+ };
5859
+
5860
+ var resolve = function(index, value) {
5861
+ results[index] = value;
5862
+ if (--remaining === 0) {
5863
+ allPromise.resolve(results);
5864
+ }
5865
+ };
5866
+
5867
+ var reject = function(error) {
5868
+ allPromise.reject(error);
5869
+ };
5870
+
5871
+ for (i = 0; i < remaining; i++) {
5872
+ promises[i].then(resolver(i), reject);
5873
+ }
5874
+ return allPromise;
5875
+ }
5876
+
5814
5877
  EventTarget.mixin(Promise.prototype);
5815
5878
 
5816
- RSVP = { async: async, Promise: Promise, Event: Event, EventTarget: EventTarget };
5879
+ RSVP = { async: async, Promise: Promise, Event: Event, EventTarget: EventTarget, all: all, raiseOnUncaughtExceptions: true };
5817
5880
  return RSVP;
5818
5881
  });
5819
5882
 
@@ -5884,10 +5947,10 @@ define("container",
5884
5947
  this.resolver = parent && parent.resolver || function() {};
5885
5948
  this.registry = new InheritingDict(parent && parent.registry);
5886
5949
  this.cache = new InheritingDict(parent && parent.cache);
5887
- this.typeInjections = {};
5950
+ this.typeInjections = new InheritingDict(parent && parent.typeInjections);
5888
5951
  this.injections = {};
5889
- this.options = {};
5890
- this.typeOptions = {};
5952
+ this._options = new InheritingDict(parent && parent._options);
5953
+ this._typeOptions = new InheritingDict(parent && parent._typeOptions);
5891
5954
  }
5892
5955
 
5893
5956
  Container.prototype = {
@@ -5902,8 +5965,20 @@ define("container",
5902
5965
  },
5903
5966
 
5904
5967
  register: function(type, name, factory, options) {
5905
- this.registry.set(type + ":" + name, factory);
5906
- this.options[type + ":" + name] = options || {};
5968
+ var fullName;
5969
+
5970
+
5971
+ if (type.indexOf(':') !== -1){
5972
+ options = factory;
5973
+ factory = name;
5974
+ fullName = type;
5975
+ } else {
5976
+
5977
+ fullName = type + ":" + name;
5978
+ }
5979
+
5980
+ this.registry.set(fullName, factory);
5981
+ this._options.set(fullName, options || {});
5907
5982
  },
5908
5983
 
5909
5984
  resolve: function(fullName) {
@@ -5937,19 +6012,31 @@ define("container",
5937
6012
  optionsForType: function(type, options) {
5938
6013
  if (this.parent) { illegalChildOperation('optionsForType'); }
5939
6014
 
5940
- this.typeOptions[type] = options;
6015
+ this._typeOptions.set(type, options);
6016
+ },
6017
+
6018
+ options: function(type, options) {
6019
+ this.optionsForType(type, options);
5941
6020
  },
5942
6021
 
5943
6022
  typeInjection: function(type, property, fullName) {
5944
6023
  if (this.parent) { illegalChildOperation('typeInjection'); }
5945
6024
 
5946
- var injections = this.typeInjections[type] = this.typeInjections[type] || [];
6025
+ var injections = this.typeInjections.get(type);
6026
+ if (!injections) {
6027
+ injections = [];
6028
+ this.typeInjections.set(type, injections);
6029
+ }
5947
6030
  injections.push({ property: property, fullName: fullName });
5948
6031
  },
5949
6032
 
5950
6033
  injection: function(factoryName, property, injectionName) {
5951
6034
  if (this.parent) { illegalChildOperation('injection'); }
5952
6035
 
6036
+ if (factoryName.indexOf(':') === -1) {
6037
+ return this.typeInjection(factoryName, property, injectionName);
6038
+ }
6039
+
5953
6040
  var injections = this.injections[factoryName] = this.injections[factoryName] || [];
5954
6041
  injections.push({ property: property, fullName: injectionName });
5955
6042
  },
@@ -6010,14 +6097,14 @@ define("container",
6010
6097
  }
6011
6098
 
6012
6099
  function option(container, fullName, optionName) {
6013
- var options = container.options[fullName];
6100
+ var options = container._options.get(fullName);
6014
6101
 
6015
6102
  if (options && options[optionName] !== undefined) {
6016
6103
  return options[optionName];
6017
6104
  }
6018
6105
 
6019
6106
  var type = fullName.split(":")[0];
6020
- options = container.typeOptions[type];
6107
+ options = container._typeOptions.get(type);
6021
6108
 
6022
6109
  if (options) {
6023
6110
  return options[optionName];
@@ -6041,11 +6128,12 @@ define("container",
6041
6128
 
6042
6129
  if (factory) {
6043
6130
  var injections = [];
6044
- injections = injections.concat(container.typeInjections[type] || []);
6131
+ injections = injections.concat(container.typeInjections.get(type) || []);
6045
6132
  injections = injections.concat(container.injections[fullName] || []);
6046
6133
 
6047
6134
  var hash = buildInjections(container, injections);
6048
6135
  hash.container = container;
6136
+ hash._debugContainerKey = fullName;
6049
6137
 
6050
6138
  value = factory.create(hash);
6051
6139
 
@@ -6221,7 +6309,7 @@ Ember.empty = Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.i
6221
6309
  Ember.compare('hello', 'hello'); // 0
6222
6310
  Ember.compare('abc', 'dfg'); // -1
6223
6311
  Ember.compare(2, 1); // 1
6224
- ```javascript
6312
+ ```
6225
6313
 
6226
6314
  @method compare
6227
6315
  @for Ember
@@ -7434,7 +7522,7 @@ Ember.Enumerable = Ember.Mixin.create(
7434
7522
  @method find
7435
7523
  @param {Function} callback The callback to execute
7436
7524
  @param {Object} [target] The target object to use
7437
- @return {Object} Found item or `null`.
7525
+ @return {Object} Found item or `undefined`.
7438
7526
  */
7439
7527
  find: function(callback, target) {
7440
7528
  var len = get(this, 'length') ;
@@ -7462,7 +7550,7 @@ Ember.Enumerable = Ember.Mixin.create(
7462
7550
  @method findProperty
7463
7551
  @param {String} key the property to test
7464
7552
  @param {String} [value] optional value to test against.
7465
- @return {Object} found item or `null`
7553
+ @return {Object} found item or `undefined`
7466
7554
  */
7467
7555
  findProperty: function(key, value) {
7468
7556
  return this.find(iter.apply(this, arguments));
@@ -7522,7 +7610,7 @@ Ember.Enumerable = Ember.Mixin.create(
7522
7610
 
7523
7611
  /**
7524
7612
  Returns `true` if the passed function returns true for any item in the
7525
- enumeration. This corresponds with the `every()` method in JavaScript 1.6.
7613
+ enumeration. This corresponds with the `some()` method in JavaScript 1.6.
7526
7614
 
7527
7615
  The callback method you provide should have the following signature (all
7528
7616
  parameters are optional):
@@ -8042,7 +8130,7 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
8042
8130
  arr.indexOf("a", -1); // 4
8043
8131
  arr.indexOf("b", 3); // -1
8044
8132
  arr.indexOf("a", 100); // -1
8045
- ```javascript
8133
+ ```
8046
8134
 
8047
8135
  @method indexOf
8048
8136
  @param {Object} object the item to search for
@@ -8687,7 +8775,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
8687
8775
  var colors = ["red", "green", "blue"];
8688
8776
  colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"]
8689
8777
  colors.insertAt(5, "orange"); // Error: Index out of range
8690
- ```javascript
8778
+ ```
8691
8779
 
8692
8780
  @method insertAt
8693
8781
  @param {Number} idx index of insert the object at.
@@ -8988,9 +9076,6 @@ var get = Ember.get, set = Ember.set, defineProperty = Ember.defineProperty;
8988
9076
  */
8989
9077
  Ember.Observable = Ember.Mixin.create(/** @scope Ember.Observable.prototype */ {
8990
9078
 
8991
- // compatibility
8992
- isObserverable: true,
8993
-
8994
9079
  /**
8995
9080
  Retrieves the value of a property from the object.
8996
9081
 
@@ -9577,7 +9662,7 @@ Ember.Evented = Ember.Mixin.create({
9577
9662
  event.
9578
9663
 
9579
9664
  ```javascript
9580
- person.on('didEat', food) {
9665
+ person.on('didEat', function(food) {
9581
9666
  console.log('person ate some ' + food);
9582
9667
  });
9583
9668
 
@@ -9856,9 +9941,9 @@ function makeCtor() {
9856
9941
  }
9857
9942
 
9858
9943
  var CoreObject = makeCtor();
9944
+ CoreObject.toString = function() { return "Ember.CoreObject"; };
9859
9945
 
9860
9946
  CoreObject.PrototypeMixin = Mixin.create({
9861
-
9862
9947
  reopen: function() {
9863
9948
  applyMixin(this, arguments, true);
9864
9949
  return this;
@@ -9959,9 +10044,10 @@ CoreObject.PrototypeMixin = Mixin.create({
9959
10044
  @return {Ember.Object} receiver
9960
10045
  */
9961
10046
  destroy: function() {
9962
- if (this.isDestroying) { return; }
10047
+ if (this._didCallDestroy) { return; }
9963
10048
 
9964
10049
  this.isDestroying = true;
10050
+ this._didCallDestroy = true;
9965
10051
 
9966
10052
  if (this.willDestroy) { this.willDestroy(); }
9967
10053
 
@@ -10029,6 +10115,8 @@ CoreObject.PrototypeMixin = Mixin.create({
10029
10115
  }
10030
10116
  });
10031
10117
 
10118
+ CoreObject.PrototypeMixin.ownerConstructor = CoreObject;
10119
+
10032
10120
  function makeToString(ret) {
10033
10121
  return function() { return ret; };
10034
10122
  }
@@ -10166,6 +10254,8 @@ var ClassMixin = Mixin.create({
10166
10254
 
10167
10255
  });
10168
10256
 
10257
+ ClassMixin.ownerConstructor = CoreObject;
10258
+
10169
10259
  if (Ember.config.overrideClassMixin) {
10170
10260
  Ember.config.overrideClassMixin(ClassMixin);
10171
10261
  }
@@ -10657,6 +10747,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb
10657
10747
  @uses Ember.Observable
10658
10748
  */
10659
10749
  Ember.Object = Ember.CoreObject.extend(Ember.Observable);
10750
+ Ember.Object.toString = function() { return "Ember.Object"; };
10660
10751
 
10661
10752
  })();
10662
10753
 
@@ -10717,16 +10808,28 @@ var Namespace = Ember.Namespace = Ember.Object.extend({
10717
10808
 
10718
10809
  Namespace.reopenClass({
10719
10810
  NAMESPACES: [Ember],
10811
+ NAMESPACES_BY_ID: {},
10720
10812
  PROCESSED: false,
10721
- processAll: processAllNamespaces
10813
+ processAll: processAllNamespaces,
10814
+ byName: function(name) {
10815
+ if (!Ember.BOOTED) {
10816
+ processAllNamespaces();
10817
+ }
10818
+
10819
+ return NAMESPACES_BY_ID[name];
10820
+ }
10722
10821
  });
10723
10822
 
10823
+ var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID;
10824
+
10724
10825
  var hasOwnProp = ({}).hasOwnProperty,
10725
10826
  guidFor = Ember.guidFor;
10726
10827
 
10727
10828
  function processNamespace(paths, root, seen) {
10728
10829
  var idx = paths.length;
10729
10830
 
10831
+ NAMESPACES_BY_ID[paths.join('.')] = root;
10832
+
10730
10833
  // Loop over all of the keys in the namespace, looking for classes
10731
10834
  for(var key in root) {
10732
10835
  if (!hasOwnProp.call(root, key)) { continue; }
@@ -10826,12 +10929,15 @@ function classToString() {
10826
10929
  }
10827
10930
 
10828
10931
  function processAllNamespaces() {
10829
- if (!Namespace.PROCESSED) {
10932
+ var unprocessedNamespaces = !Namespace.PROCESSED,
10933
+ unprocessedMixins = Ember.anyUnprocessedMixins;
10934
+
10935
+ if (unprocessedNamespaces) {
10830
10936
  findNamespaces();
10831
10937
  Namespace.PROCESSED = true;
10832
10938
  }
10833
10939
 
10834
- if (Ember.anyUnprocessedMixins) {
10940
+ if (unprocessedNamespaces || unprocessedMixins) {
10835
10941
  var namespaces = Namespace.NAMESPACES, namespace;
10836
10942
  for (var i=0, l=namespaces.length; i<l; i++) {
10837
10943
  namespace = namespaces[i];
@@ -10957,9 +11063,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,
10957
11063
 
10958
11064
  @property arrangedContent
10959
11065
  */
10960
- arrangedContent: Ember.computed('content', function() {
10961
- return get(this, 'content');
10962
- }),
11066
+ arrangedContent: Ember.computed.alias('content'),
10963
11067
 
10964
11068
  /**
10965
11069
  Should actually retrieve the object at the specified index from the
@@ -11242,6 +11346,10 @@ Ember.ObjectProxy = Ember.Object.extend(
11242
11346
 
11243
11347
  }, 'content'),
11244
11348
 
11349
+ isTruthy: Ember.computed.bool('content'),
11350
+
11351
+ _debugContainerKey: null,
11352
+
11245
11353
  willWatchProperty: function (key) {
11246
11354
  var contentKey = 'content.' + key;
11247
11355
  addBeforeObserver(this, contentKey, null, contentPropertyWillChange);
@@ -11666,7 +11774,7 @@ Ember.Deferred = Deferred;
11666
11774
  @submodule ember-runtime
11667
11775
  */
11668
11776
 
11669
- var loadHooks = {};
11777
+ var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {};
11670
11778
  var loaded = {};
11671
11779
 
11672
11780
  /**
@@ -11753,6 +11861,9 @@ var get = Ember.get;
11753
11861
  @extends Ember.Mixin
11754
11862
  */
11755
11863
  Ember.ControllerMixin = Ember.Mixin.create({
11864
+ /* ducktype as a controller */
11865
+ isController: true,
11866
+
11756
11867
  /**
11757
11868
  The object to which events from the view should be sent.
11758
11869
 
@@ -11771,6 +11882,8 @@ Ember.ControllerMixin = Ember.Mixin.create({
11771
11882
 
11772
11883
  store: null,
11773
11884
 
11885
+ model: Ember.computed.alias('content'),
11886
+
11774
11887
  send: function(actionName) {
11775
11888
  var args = [].slice.call(arguments, 1), target;
11776
11889
 
@@ -11819,7 +11932,8 @@ var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
11819
11932
 
11820
11933
  songsController = Ember.ArrayController.create({
11821
11934
  content: songs,
11822
- sortProperties: ['trackNumber']
11935
+ sortProperties: ['trackNumber'],
11936
+ sortAscending: true
11823
11937
  });
11824
11938
 
11825
11939
  songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'}
@@ -11834,7 +11948,19 @@ var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach;
11834
11948
  @uses Ember.MutableEnumerable
11835
11949
  */
11836
11950
  Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
11951
+
11952
+ /**
11953
+ Specifies which properties dictate the arrangedContent's sort order.
11954
+
11955
+ @property {Array} sortProperties
11956
+ */
11837
11957
  sortProperties: null,
11958
+
11959
+ /**
11960
+ Specifies the arrangedContent's sort direction
11961
+
11962
+ @property {Boolean} sortAscending
11963
+ */
11838
11964
  sortAscending: true,
11839
11965
 
11840
11966
  orderBy: function(item1, item2) {
@@ -11870,9 +11996,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
11870
11996
  return this._super();
11871
11997
  },
11872
11998
 
11873
- isSorted: Ember.computed('sortProperties', function() {
11874
- return !!get(this, 'sortProperties');
11875
- }),
11999
+ isSorted: Ember.computed.bool('sortProperties'),
11876
12000
 
11877
12001
  arrangedContent: Ember.computed('content', 'sortProperties.@each', function(key, value) {
11878
12002
  var content = get(this, 'content'),
@@ -12147,20 +12271,22 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
12147
12271
 
12148
12272
  objectAtContent: function(idx) {
12149
12273
  var length = get(this, 'length'),
12150
- object = get(this,'arrangedContent').objectAt(idx),
12151
- controllerClass = this.lookupItemController(object);
12274
+ object = get(this,'arrangedContent').objectAt(idx);
12152
12275
 
12153
- if (controllerClass && idx < length) {
12154
- return this.controllerAt(idx, object, controllerClass);
12155
- } else {
12156
- // When controllerClass is falsy we have not opted in to using item
12157
- // controllers, so return the object directly. However, when
12158
- // controllerClass is defined but the index is out of range, we want to
12159
- // return the "out of range" value, whatever that might be. Rather than
12160
- // make assumptions (e.g. guessing `null` or `undefined`) we defer this to
12161
- // `arrangedContent`.
12162
- return object;
12276
+ if (idx >= 0 && idx < length) {
12277
+ var controllerClass = this.lookupItemController(object);
12278
+ if (controllerClass) {
12279
+ return this.controllerAt(idx, object, controllerClass);
12280
+ }
12163
12281
  }
12282
+
12283
+ // When `controllerClass` is falsy, we have not opted in to using item
12284
+ // controllers, so return the object directly.
12285
+
12286
+ // When the index is out of range, we want to return the "out of range"
12287
+ // value, whatever that might be. Rather than make assumptions
12288
+ // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`.
12289
+ return object;
12164
12290
  },
12165
12291
 
12166
12292
  arrangedContentDidChange: function() {
@@ -12186,6 +12312,7 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
12186
12312
 
12187
12313
  init: function() {
12188
12314
  this._super();
12315
+ if (!this.get('content')) { this.set('content', Ember.A()); }
12189
12316
  this._resetSubContainers();
12190
12317
  },
12191
12318
 
@@ -12558,6 +12685,21 @@ Ember._RenderBuffer.prototype =
12558
12685
  */
12559
12686
  elementAttributes: null,
12560
12687
 
12688
+ /**
12689
+ A hash keyed on the name of the properties and whose value will be
12690
+ applied to that property. For example, if you wanted to apply a
12691
+ `checked=true` property to an element, you would set the
12692
+ elementProperties hash to `{'checked':true}`.
12693
+
12694
+ You should not maintain this hash yourself, rather, you should use
12695
+ the `prop()` method of `Ember.RenderBuffer`.
12696
+
12697
+ @property elementProperties
12698
+ @type Hash
12699
+ @default {}
12700
+ */
12701
+ elementProperties: null,
12702
+
12561
12703
  /**
12562
12704
  The tagname of the element an instance of `Ember.RenderBuffer` represents.
12563
12705
 
@@ -12680,6 +12822,41 @@ Ember._RenderBuffer.prototype =
12680
12822
  return this;
12681
12823
  },
12682
12824
 
12825
+ /**
12826
+ Adds an property which will be rendered to the element.
12827
+
12828
+ @method prop
12829
+ @param {String} name The name of the property
12830
+ @param {String} value The value to add to the property
12831
+ @chainable
12832
+ @return {Ember.RenderBuffer|String} this or the current property value
12833
+ */
12834
+ prop: function(name, value) {
12835
+ var properties = this.elementProperties = (this.elementProperties || {});
12836
+
12837
+ if (arguments.length === 1) {
12838
+ return properties[name];
12839
+ } else {
12840
+ properties[name] = value;
12841
+ }
12842
+
12843
+ return this;
12844
+ },
12845
+
12846
+ /**
12847
+ Remove an property from the list of properties to render.
12848
+
12849
+ @method removeProp
12850
+ @param {String} name The name of the property
12851
+ @chainable
12852
+ */
12853
+ removeProp: function(name) {
12854
+ var properties = this.elementProperties;
12855
+ if (properties) { delete properties[name]; }
12856
+
12857
+ return this;
12858
+ },
12859
+
12683
12860
  /**
12684
12861
  Adds a style to the style attribute which will be rendered to the element.
12685
12862
 
@@ -12713,8 +12890,9 @@ Ember._RenderBuffer.prototype =
12713
12890
  id = this.elementId,
12714
12891
  classes = this.classes,
12715
12892
  attrs = this.elementAttributes,
12893
+ props = this.elementProperties,
12716
12894
  style = this.elementStyle,
12717
- prop;
12895
+ attr, prop;
12718
12896
 
12719
12897
  buffer.push('<' + tagName);
12720
12898
 
@@ -12742,15 +12920,32 @@ Ember._RenderBuffer.prototype =
12742
12920
  }
12743
12921
 
12744
12922
  if (attrs) {
12745
- for (prop in attrs) {
12746
- if (attrs.hasOwnProperty(prop)) {
12747
- buffer.push(' ' + prop + '="' + this._escapeAttribute(attrs[prop]) + '"');
12923
+ for (attr in attrs) {
12924
+ if (attrs.hasOwnProperty(attr)) {
12925
+ buffer.push(' ' + attr + '="' + this._escapeAttribute(attrs[attr]) + '"');
12748
12926
  }
12749
12927
  }
12750
12928
 
12751
12929
  this.elementAttributes = null;
12752
12930
  }
12753
12931
 
12932
+ if (props) {
12933
+ for (prop in props) {
12934
+ if (props.hasOwnProperty(prop)) {
12935
+ var value = props[prop];
12936
+ if (value || typeof(value) === 'number') {
12937
+ if (value === true) {
12938
+ buffer.push(' ' + prop + '="' + prop + '"');
12939
+ } else {
12940
+ buffer.push(' ' + prop + '="' + this._escapeAttribute(props[prop]) + '"');
12941
+ }
12942
+ }
12943
+ }
12944
+ }
12945
+
12946
+ this.elementProperties = null;
12947
+ }
12948
+
12754
12949
  buffer.push('>');
12755
12950
  },
12756
12951
 
@@ -12770,8 +12965,9 @@ Ember._RenderBuffer.prototype =
12770
12965
  id = this.elementId,
12771
12966
  classes = this.classes,
12772
12967
  attrs = this.elementAttributes,
12968
+ props = this.elementProperties,
12773
12969
  style = this.elementStyle,
12774
- styleBuffer = '', prop;
12970
+ styleBuffer = '', attr, prop;
12775
12971
 
12776
12972
  if (id) {
12777
12973
  $element.attr('id', id);
@@ -12795,15 +12991,25 @@ Ember._RenderBuffer.prototype =
12795
12991
  }
12796
12992
 
12797
12993
  if (attrs) {
12798
- for (prop in attrs) {
12799
- if (attrs.hasOwnProperty(prop)) {
12800
- $element.attr(prop, attrs[prop]);
12994
+ for (attr in attrs) {
12995
+ if (attrs.hasOwnProperty(attr)) {
12996
+ $element.attr(attr, attrs[attr]);
12801
12997
  }
12802
12998
  }
12803
12999
 
12804
13000
  this.elementAttributes = null;
12805
13001
  }
12806
13002
 
13003
+ if (props) {
13004
+ for (prop in props) {
13005
+ if (props.hasOwnProperty(prop)) {
13006
+ $element.prop(prop, props[prop]);
13007
+ }
13008
+ }
13009
+
13010
+ this.elementProperties = null;
13011
+ }
13012
+
12807
13013
  return element;
12808
13014
  },
12809
13015
 
@@ -13017,11 +13223,13 @@ Ember.EventDispatcher = Ember.Object.extend(
13017
13223
  rootElement.delegate('[data-ember-action]', event + '.ember', function(evt) {
13018
13224
  return Ember.handleErrors(function() {
13019
13225
  var actionId = Ember.$(evt.currentTarget).attr('data-ember-action'),
13020
- action = Ember.Handlebars.ActionHelper.registeredActions[actionId],
13021
- handler = action.handler;
13226
+ action = Ember.Handlebars.ActionHelper.registeredActions[actionId];
13022
13227
 
13023
- if (action.eventName === eventName) {
13024
- return handler(evt);
13228
+ // We have to check for action here since in some cases, jQuery will trigger
13229
+ // an event on `removeChild` (i.e. focusout) after we've already torn down the
13230
+ // action handlers for the view.
13231
+ if (action && action.eventName === eventName) {
13232
+ return action.handler(evt);
13025
13233
  }
13026
13234
  }, this);
13027
13235
  });
@@ -13110,7 +13318,25 @@ Ember.ControllerMixin.reopen({
13110
13318
  target: null,
13111
13319
  namespace: null,
13112
13320
  view: null,
13113
- container: null
13321
+ container: null,
13322
+ _childContainers: null,
13323
+
13324
+ init: function() {
13325
+ this._super();
13326
+ set(this, '_childContainers', {});
13327
+ },
13328
+
13329
+ _modelDidChange: Ember.observer(function() {
13330
+ var containers = get(this, '_childContainers'),
13331
+ container;
13332
+
13333
+ for (var prop in containers) {
13334
+ if (!containers.hasOwnProperty(prop)) { continue; }
13335
+ containers[prop].destroy();
13336
+ }
13337
+
13338
+ set(this, '_childContainers', {});
13339
+ }, 'model')
13114
13340
  });
13115
13341
 
13116
13342
  })();
@@ -13138,9 +13364,7 @@ var a_forEach = Ember.EnumerableUtils.forEach;
13138
13364
  var a_addObject = Ember.EnumerableUtils.addObject;
13139
13365
 
13140
13366
  var childViewsProperty = Ember.computed(function() {
13141
- var childViews = this._childViews;
13142
-
13143
- var ret = Ember.A();
13367
+ var childViews = this._childViews, ret = Ember.A(), view = this;
13144
13368
 
13145
13369
  a_forEach(childViews, function(view) {
13146
13370
  if (view.isVirtual) {
@@ -13150,6 +13374,14 @@ var childViewsProperty = Ember.computed(function() {
13150
13374
  }
13151
13375
  });
13152
13376
 
13377
+ ret.replace = function (idx, removedCount, addedViews) {
13378
+ if (view instanceof Ember.ContainerView) {
13379
+
13380
+ return view.replace(idx, removedCount, addedViews);
13381
+ }
13382
+ throw new Error("childViews is immutable");
13383
+ };
13384
+
13153
13385
  return ret;
13154
13386
  });
13155
13387
 
@@ -13175,7 +13407,10 @@ Ember.CoreView = Ember.Object.extend(Ember.Evented, {
13175
13407
 
13176
13408
  // Register the view for event handling. This hash is used by
13177
13409
  // Ember.EventDispatcher to dispatch incoming events.
13178
- if (!this.isVirtual) Ember.View.views[this.elementId] = this;
13410
+ if (!this.isVirtual) {
13411
+
13412
+ Ember.View.views[this.elementId] = this;
13413
+ }
13179
13414
 
13180
13415
  this.addBeforeObserver('elementId', function() {
13181
13416
  throw new Error("Changing a view's elementId after creation is not allowed");
@@ -13942,6 +14177,7 @@ Ember.View = Ember.CoreView.extend(
13942
14177
  var templateName = get(this, 'templateName'),
13943
14178
  template = this.templateForName(templateName, 'template');
13944
14179
 
14180
+
13945
14181
  return template || get(this, 'defaultTemplate');
13946
14182
  }).property('templateName'),
13947
14183
 
@@ -13983,6 +14219,7 @@ Ember.View = Ember.CoreView.extend(
13983
14219
  var layoutName = get(this, 'layoutName'),
13984
14220
  layout = this.templateForName(layoutName, 'layout');
13985
14221
 
14222
+
13986
14223
  return layout || get(this, 'defaultLayout');
13987
14224
  }).property('layoutName'),
13988
14225
 
@@ -14359,11 +14596,16 @@ Ember.View = Ember.CoreView.extend(
14359
14596
  oldClass = dasherizedClass;
14360
14597
  }
14361
14598
 
14362
- addObserver(this, parsedPath.path, observer);
14363
-
14599
+ this.registerObserver(this, parsedPath.path, observer);
14600
+ // Remove className so when the view is rerendered,
14601
+ // the className is added based on binding reevaluation
14364
14602
  this.one('willClearRender', function() {
14365
- removeObserver(this, parsedPath.path, observer);
14603
+ if (oldClass) {
14604
+ classNames.removeObject(oldClass);
14605
+ oldClass = null;
14606
+ }
14366
14607
  });
14608
+
14367
14609
  }, this);
14368
14610
  },
14369
14611
 
@@ -14395,11 +14637,7 @@ Ember.View = Ember.CoreView.extend(
14395
14637
  Ember.View.applyAttributeBindings(elem, attributeName, attributeValue);
14396
14638
  };
14397
14639
 
14398
- addObserver(this, property, observer);
14399
-
14400
- this.one('willClearRender', function() {
14401
- removeObserver(this, property, observer);
14402
- });
14640
+ this.registerObserver(this, property, observer);
14403
14641
 
14404
14642
  // Determine the current value and add it to the render buffer
14405
14643
  // if necessary.
@@ -14610,7 +14848,7 @@ Ember.View = Ember.CoreView.extend(
14610
14848
  // element.
14611
14849
  // In the interim, we will just re-render if that happens. It is more
14612
14850
  // important than elements get garbage collected.
14613
- this.destroyElement();
14851
+ if (!this.removedFromDOM) { this.destroyElement(); }
14614
14852
  this.invokeRecursively(function(view) {
14615
14853
  if (view.clearRenderedChildren) { view.clearRenderedChildren(); }
14616
14854
  });
@@ -15083,12 +15321,17 @@ Ember.View = Ember.CoreView.extend(
15083
15321
  // so collect any information we need before calling super.
15084
15322
  var childViews = this._childViews,
15085
15323
  parent = this._parentView,
15086
- childLen;
15324
+ childLen, i;
15087
15325
 
15088
15326
  // destroy the element -- this will avoid each child view destroying
15089
15327
  // the element over and over again...
15090
15328
  if (!this.removedFromDOM) { this.destroyElement(); }
15091
15329
 
15330
+ childLen = childViews.length;
15331
+ for (i=childLen-1; i>=0; i--) {
15332
+ childViews[i].removedFromDOM = true;
15333
+ }
15334
+
15092
15335
  // remove from non-virtual parent view if viewName was specified
15093
15336
  if (this.viewName) {
15094
15337
  var nonVirtualParentView = get(this, 'parentView');
@@ -15105,8 +15348,7 @@ Ember.View = Ember.CoreView.extend(
15105
15348
  this.transitionTo('destroyed');
15106
15349
 
15107
15350
  childLen = childViews.length;
15108
- for (var i=childLen-1; i>=0; i--) {
15109
- childViews[i].removedFromDOM = true;
15351
+ for (i=childLen-1; i>=0; i--) {
15110
15352
  childViews[i].destroy();
15111
15353
  }
15112
15354
 
@@ -15251,6 +15493,14 @@ Ember.View = Ember.CoreView.extend(
15251
15493
  */
15252
15494
  handleEvent: function(eventName, evt) {
15253
15495
  return this.currentState.handleEvent(this, eventName, evt);
15496
+ },
15497
+
15498
+ registerObserver: function(root, path, target, observer) {
15499
+ Ember.addObserver(root, path, target, observer);
15500
+
15501
+ this.one('willClearRender', function() {
15502
+ Ember.removeObserver(root, path, target, observer);
15503
+ });
15254
15504
  }
15255
15505
 
15256
15506
  });
@@ -15441,13 +15691,17 @@ Ember.View.childViewsProperty = childViewsProperty;
15441
15691
 
15442
15692
  Ember.View.applyAttributeBindings = function(elem, name, value) {
15443
15693
  var type = Ember.typeOf(value);
15444
- var currentValue = elem.attr(name);
15445
15694
 
15446
15695
  // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js
15447
- if ((type === 'string' || (type === 'number' && !isNaN(value))) && value !== currentValue) {
15448
- elem.attr(name, value);
15449
- } else if (value && type === 'boolean') {
15450
- elem.attr(name, name);
15696
+ if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) {
15697
+ if (value !== elem.attr(name)) {
15698
+ elem.attr(name, value);
15699
+ }
15700
+ } else if (name === 'value' || type === 'boolean') {
15701
+ if (value !== elem.prop(name)) {
15702
+ // value and booleans should always be properties
15703
+ elem.prop(name, value);
15704
+ }
15451
15705
  } else if (!value) {
15452
15706
  elem.removeAttr(name);
15453
15707
  }
@@ -15800,14 +16054,9 @@ var states = Ember.View.cloneStates(Ember.View.states);
15800
16054
  var get = Ember.get, set = Ember.set, meta = Ember.meta;
15801
16055
  var forEach = Ember.EnumerableUtils.forEach;
15802
16056
 
15803
- var childViewsProperty = Ember.computed(function() {
15804
- return get(this, '_childViews');
15805
- }).property('_childViews');
15806
-
15807
16057
  /**
15808
- A `ContainerView` is an `Ember.View` subclass that allows for manual or
15809
- programatic management of a view's `childViews` array that will correctly
15810
- update the `ContainerView` instance's rendered DOM representation.
16058
+ A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray`
16059
+ allowing programatic management of its child views.
15811
16060
 
15812
16061
  ## Setting Initial Child Views
15813
16062
 
@@ -15847,11 +16096,9 @@ var childViewsProperty = Ember.computed(function() {
15847
16096
 
15848
16097
  ## Adding and Removing Child Views
15849
16098
 
15850
- The views in a container's `childViews` array should be added and removed by
15851
- manipulating the `childViews` property directly.
16099
+ The container view implements `Ember.MutableArray` allowing programatic management of its child views.
15852
16100
 
15853
- To remove a view pass that view into a `removeObject` call on the container's
15854
- `childViews` property.
16101
+ To remove a view, pass that view into a `removeObject` call on the container view.
15855
16102
 
15856
16103
  Given an empty `<body>` the following code
15857
16104
 
@@ -15882,9 +16129,9 @@ var childViewsProperty = Ember.computed(function() {
15882
16129
  Removing a view
15883
16130
 
15884
16131
  ```javascript
15885
- aContainer.get('childViews'); // [aContainer.aView, aContainer.bView]
15886
- aContainer.get('childViews').removeObject(aContainer.get('bView'));
15887
- aContainer.get('childViews'); // [aContainer.aView]
16132
+ aContainer.toArray(); // [aContainer.aView, aContainer.bView]
16133
+ aContainer.removeObject(aContainer.get('bView'));
16134
+ aContainer.toArray(); // [aContainer.aView]
15888
16135
  ```
15889
16136
 
15890
16137
  Will result in the following HTML
@@ -15896,7 +16143,7 @@ var childViewsProperty = Ember.computed(function() {
15896
16143
  ```
15897
16144
 
15898
16145
  Similarly, adding a child view is accomplished by adding `Ember.View` instances to the
15899
- container's `childViews` property.
16146
+ container view.
15900
16147
 
15901
16148
  Given an empty `<body>` the following code
15902
16149
 
@@ -15931,9 +16178,9 @@ var childViewsProperty = Ember.computed(function() {
15931
16178
  template: Ember.Handlebars.compile("Another view")
15932
16179
  });
15933
16180
 
15934
- aContainer.get('childViews'); // [aContainer.aView, aContainer.bView]
15935
- aContainer.get('childViews').pushObject(AnotherViewClass.create());
15936
- aContainer.get('childViews'); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>]
16181
+ aContainer.toArray(); // [aContainer.aView, aContainer.bView]
16182
+ aContainer.pushObject(AnotherViewClass.create());
16183
+ aContainer.toArray(); // [aContainer.aView, aContainer.bView, <AnotherViewClass instance>]
15937
16184
  ```
15938
16185
 
15939
16186
  Will result in the following HTML
@@ -15946,71 +16193,20 @@ var childViewsProperty = Ember.computed(function() {
15946
16193
  </div>
15947
16194
  ```
15948
16195
 
15949
- Direct manipulation of `childViews` presence or absence in the DOM via calls
15950
- to `remove` or `removeFromParent` or calls to a container's `removeChild` may
15951
- not behave correctly.
16196
+ ## Templates and Layout
15952
16197
 
15953
- Calling `remove()` on a child view will remove the view's HTML, but it will
15954
- remain as part of its container's `childView`s property.
16198
+ A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or
16199
+ `defaultLayout` property on a container view will not result in the template
16200
+ or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM
16201
+ representation will only be the rendered HTML of its child views.
15955
16202
 
15956
- Calling `removeChild()` on the container will remove the passed view instance
15957
- from the container's `childView`s but keep its HTML within the container's
15958
- rendered view.
16203
+ ## Binding a View to Display
15959
16204
 
15960
- Calling `removeFromParent()` behaves as expected but should be avoided in
15961
- favor of direct manipulation of a container's `childViews` property.
15962
-
15963
- ```javascript
15964
- aContainer = Ember.ContainerView.create({
15965
- classNames: ['the-container'],
15966
- childViews: ['aView', 'bView'],
15967
- aView: Ember.View.create({
15968
- template: Ember.Handlebars.compile("A")
15969
- }),
15970
- bView: Ember.View.create({
15971
- template: Ember.Handlebars.compile("B")
15972
- })
15973
- });
15974
-
15975
- aContainer.appendTo('body');
15976
- ```
15977
-
15978
- Results in the HTML
15979
-
15980
- ```html
15981
- <div class="ember-view the-container">
15982
- <div class="ember-view">A</div>
15983
- <div class="ember-view">B</div>
15984
- </div>
15985
- ```
15986
-
15987
- Calling `aContainer.get('aView').removeFromParent()` will result in the
15988
- following HTML
15989
-
15990
- ```html
15991
- <div class="ember-view the-container">
15992
- <div class="ember-view">B</div>
15993
- </div>
15994
- ```
15995
-
15996
- And the `Ember.View` instance stored in `aContainer.aView` will be removed from `aContainer`'s
15997
- `childViews` array.
15998
-
15999
- ## Templates and Layout
16000
-
16001
- A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or
16002
- `defaultLayout` property on a container view will not result in the template
16003
- or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM
16004
- representation will only be the rendered HTML of its child views.
16005
-
16006
- ## Binding a View to Display
16007
-
16008
- If you would like to display a single view in your ContainerView, you can set
16009
- its `currentView` property. When the `currentView` property is set to a view
16010
- instance, it will be added to the ContainerView's `childViews` array. If the
16011
- `currentView` property is later changed to a different view, the new view
16012
- will replace the old view. If `currentView` is set to `null`, the last
16013
- `currentView` will be removed.
16205
+ If you would like to display a single view in your ContainerView, you can set
16206
+ its `currentView` property. When the `currentView` property is set to a view
16207
+ instance, it will be added to the ContainerView. If the `currentView` property
16208
+ is later changed to a different view, the new view will replace the old view.
16209
+ If `currentView` is set to `null`, the last `currentView` will be removed.
16014
16210
 
16015
16211
  This functionality is useful for cases where you want to bind the display of
16016
16212
  a ContainerView to a controller or state manager. For example, you can bind
@@ -16032,15 +16228,16 @@ var childViewsProperty = Ember.computed(function() {
16032
16228
  @namespace Ember
16033
16229
  @extends Ember.View
16034
16230
  */
16035
-
16036
- Ember.ContainerView = Ember.View.extend({
16231
+ Ember.ContainerView = Ember.View.extend(Ember.MutableArray, {
16037
16232
  states: states,
16038
16233
 
16039
16234
  init: function() {
16040
16235
  this._super();
16041
16236
 
16042
16237
  var childViews = get(this, 'childViews');
16043
- Ember.defineProperty(this, 'childViews', childViewsProperty);
16238
+
16239
+ // redefine view's childViews property that was obliterated
16240
+ Ember.defineProperty(this, 'childViews', Ember.View.childViewsProperty);
16044
16241
 
16045
16242
  var _childViews = this._childViews;
16046
16243
 
@@ -16059,20 +16256,38 @@ Ember.ContainerView = Ember.View.extend({
16059
16256
  }, this);
16060
16257
 
16061
16258
  var currentView = get(this, 'currentView');
16062
- if (currentView) _childViews.push(this.createChildView(currentView));
16259
+ if (currentView) {
16260
+ _childViews.push(this.createChildView(currentView));
16261
+ }
16262
+ },
16063
16263
 
16064
- // Make the _childViews array observable
16065
- Ember.A(_childViews);
16264
+ replace: function(idx, removedCount, addedViews) {
16265
+ var addedCount = addedViews ? get(addedViews, 'length') : 0;
16066
16266
 
16067
- // Sets up an array observer on the child views array. This
16068
- // observer will detect when child views are added or removed
16069
- // and update the DOM to reflect the mutation.
16070
- get(this, 'childViews').addArrayObserver(this, {
16071
- willChange: 'childViewsWillChange',
16072
- didChange: 'childViewsDidChange'
16073
- });
16267
+ this.arrayContentWillChange(idx, removedCount, addedCount);
16268
+ this.childViewsWillChange(this._childViews, idx, removedCount);
16269
+
16270
+ if (addedCount === 0) {
16271
+ this._childViews.splice(idx, removedCount) ;
16272
+ } else {
16273
+ var args = [idx, removedCount].concat(addedViews);
16274
+ this._childViews.splice.apply(this._childViews, args);
16275
+ }
16276
+
16277
+ this.arrayContentDidChange(idx, removedCount, addedCount);
16278
+ this.childViewsDidChange(this._childViews, idx, removedCount, addedCount);
16279
+
16280
+ return this;
16281
+ },
16282
+
16283
+ objectAt: function(idx) {
16284
+ return this._childViews[idx];
16074
16285
  },
16075
16286
 
16287
+ length: Ember.computed(function () {
16288
+ return this._childViews.length;
16289
+ }),
16290
+
16076
16291
  /**
16077
16292
  @private
16078
16293
 
@@ -16089,23 +16304,6 @@ Ember.ContainerView = Ember.View.extend({
16089
16304
 
16090
16305
  instrumentName: 'render.container',
16091
16306
 
16092
- /**
16093
- @private
16094
-
16095
- When the container view is destroyed, tear down the child views
16096
- array observer.
16097
-
16098
- @method willDestroy
16099
- */
16100
- willDestroy: function() {
16101
- get(this, 'childViews').removeArrayObserver(this, {
16102
- willChange: 'childViewsWillChange',
16103
- didChange: 'childViewsDidChange'
16104
- });
16105
-
16106
- this._super();
16107
- },
16108
-
16109
16307
  /**
16110
16308
  @private
16111
16309
 
@@ -16121,12 +16319,19 @@ Ember.ContainerView = Ember.View.extend({
16121
16319
  @param {Number} removed the number of child views removed
16122
16320
  **/
16123
16321
  childViewsWillChange: function(views, start, removed) {
16124
- if (removed === 0) { return; }
16322
+ this.propertyWillChange('childViews');
16125
16323
 
16126
- var changedViews = views.slice(start, start+removed);
16127
- this.initializeViews(changedViews, null, null);
16324
+ if (removed > 0) {
16325
+ var changedViews = views.slice(start, start+removed);
16326
+ // transition to preRender before clearing parentView
16327
+ this.currentState.childViewsWillChange(this, views, start, removed);
16328
+ this.initializeViews(changedViews, null, null);
16329
+ }
16330
+ },
16128
16331
 
16129
- this.currentState.childViewsWillChange(this, views, start, removed);
16332
+ removeChild: function(child) {
16333
+ this.removeObject(child);
16334
+ return this;
16130
16335
  },
16131
16336
 
16132
16337
  /**
@@ -16147,16 +16352,12 @@ Ember.ContainerView = Ember.View.extend({
16147
16352
  @param {Number} the number of child views added
16148
16353
  */
16149
16354
  childViewsDidChange: function(views, start, removed, added) {
16150
- var len = get(views, 'length');
16151
-
16152
- // No new child views were added; bail out.
16153
- if (added === 0) return;
16154
-
16155
- var changedViews = views.slice(start, start+added);
16156
- this.initializeViews(changedViews, this, get(this, 'templateData'));
16157
-
16158
- // Let the current state handle the changes
16159
- this.currentState.childViewsDidChange(this, views, start, added);
16355
+ if (added > 0) {
16356
+ var changedViews = views.slice(start, start+added);
16357
+ this.initializeViews(changedViews, this, get(this, 'templateData'));
16358
+ this.currentState.childViewsDidChange(this, views, start, added);
16359
+ }
16360
+ this.propertyDidChange('childViews');
16160
16361
  },
16161
16362
 
16162
16363
  initializeViews: function(views, parentView, templateData) {
@@ -16172,21 +16373,16 @@ Ember.ContainerView = Ember.View.extend({
16172
16373
  currentView: null,
16173
16374
 
16174
16375
  _currentViewWillChange: Ember.beforeObserver(function() {
16175
- var childViews = get(this, 'childViews'),
16176
- currentView = get(this, 'currentView');
16177
-
16376
+ var currentView = get(this, 'currentView');
16178
16377
  if (currentView) {
16179
16378
  currentView.destroy();
16180
- childViews.removeObject(currentView);
16181
16379
  }
16182
16380
  }, 'currentView'),
16183
16381
 
16184
16382
  _currentViewDidChange: Ember.observer(function() {
16185
- var childViews = get(this, 'childViews'),
16186
- currentView = get(this, 'currentView');
16187
-
16383
+ var currentView = get(this, 'currentView');
16188
16384
  if (currentView) {
16189
- childViews.pushObject(currentView);
16385
+ this.pushObject(currentView);
16190
16386
  }
16191
16387
  }, 'currentView'),
16192
16388
 
@@ -16219,7 +16415,7 @@ Ember.merge(states.hasElement, {
16219
16415
  },
16220
16416
 
16221
16417
  ensureChildrenAreInDOM: function(view) {
16222
- var childViews = view.get('childViews'), i, len, childView, previous, buffer;
16418
+ var childViews = view._childViews, i, len, childView, previous, buffer;
16223
16419
  for (i = 0, len = childViews.length; i < len; i++) {
16224
16420
  childView = childViews[i];
16225
16421
  buffer = childView.renderToBufferIfNeeded();
@@ -16484,6 +16680,10 @@ Ember.CollectionView = Ember.ContainerView.extend(
16484
16680
  if (content) { content.removeArrayObserver(this); }
16485
16681
 
16486
16682
  this._super();
16683
+
16684
+ if (this._createdEmptyView) {
16685
+ this._createdEmptyView.destroy();
16686
+ }
16487
16687
  },
16488
16688
 
16489
16689
  arrayWillChange: function(content, start, removedCount) {
@@ -16497,9 +16697,9 @@ Ember.CollectionView = Ember.ContainerView.extend(
16497
16697
  // Loop through child views that correspond with the removed items.
16498
16698
  // Note that we loop from the end of the array to the beginning because
16499
16699
  // we are mutating it as we go.
16500
- var childViews = get(this, 'childViews'), childView, idx, len;
16700
+ var childViews = this._childViews, childView, idx, len;
16501
16701
 
16502
- len = get(childViews, 'length');
16702
+ len = this._childViews.length;
16503
16703
 
16504
16704
  var removingAll = removedCount === len;
16505
16705
 
@@ -16529,7 +16729,6 @@ Ember.CollectionView = Ember.ContainerView.extend(
16529
16729
  */
16530
16730
  arrayDidChange: function(content, start, removed, added) {
16531
16731
  var itemViewClass = get(this, 'itemViewClass'),
16532
- childViews = get(this, 'childViews'),
16533
16732
  addedViews = [], view, item, idx, len, itemTagName;
16534
16733
 
16535
16734
  if ('string' === typeof itemViewClass) {
@@ -16553,11 +16752,15 @@ Ember.CollectionView = Ember.ContainerView.extend(
16553
16752
  var emptyView = get(this, 'emptyView');
16554
16753
  if (!emptyView) { return; }
16555
16754
 
16755
+ var isClass = Ember.CoreView.detect(emptyView);
16756
+
16556
16757
  emptyView = this.createChildView(emptyView);
16557
16758
  addedViews.push(emptyView);
16558
16759
  set(this, 'emptyView', emptyView);
16760
+
16761
+ if (isClass) { this._createdEmptyView = emptyView; }
16559
16762
  }
16560
- childViews.replace(start, 0, addedViews);
16763
+ this.replace(start, 0, addedViews);
16561
16764
  },
16562
16765
 
16563
16766
  createChildView: function(view, attrs) {
@@ -17169,6 +17372,8 @@ Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string)
17169
17372
  return "data.buffer.push("+string+");";
17170
17373
  };
17171
17374
 
17375
+ var prefix = "ember" + (+new Date()), incr = 1;
17376
+
17172
17377
  /**
17173
17378
  @private
17174
17379
 
@@ -17181,8 +17386,11 @@ Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string)
17181
17386
  @param mustache
17182
17387
  */
17183
17388
  Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
17184
- if (mustache.params.length || mustache.hash) {
17185
- return Handlebars.Compiler.prototype.mustache.call(this, mustache);
17389
+ if (mustache.isHelper && mustache.id.string === 'control') {
17390
+ mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
17391
+ mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]);
17392
+ } else if (mustache.params.length || mustache.hash) {
17393
+ // no changes required
17186
17394
  } else {
17187
17395
  var id = new Handlebars.AST.IdNode(['_triageMustache']);
17188
17396
 
@@ -17194,8 +17402,9 @@ Ember.Handlebars.Compiler.prototype.mustache = function(mustache) {
17194
17402
  mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
17195
17403
  }
17196
17404
  mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
17197
- return Handlebars.Compiler.prototype.mustache.call(this, mustache);
17198
17405
  }
17406
+
17407
+ return Handlebars.Compiler.prototype.mustache.call(this, mustache);
17199
17408
  };
17200
17409
 
17201
17410
  /**
@@ -17254,6 +17463,8 @@ if (Handlebars.compile) {
17254
17463
  })();
17255
17464
 
17256
17465
  (function() {
17466
+ var slice = Array.prototype.slice;
17467
+
17257
17468
  /**
17258
17469
  @private
17259
17470
 
@@ -17308,7 +17519,7 @@ var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data)
17308
17519
  @param {String} path The path to be lookedup
17309
17520
  @param {Object} options The template's option hash
17310
17521
  */
17311
- Ember.Handlebars.get = function(root, path, options) {
17522
+ var handlebarsGet = Ember.Handlebars.get = function(root, path, options) {
17312
17523
  var data = options && options.data,
17313
17524
  normalizedPath = normalizePath(root, path, data),
17314
17525
  value;
@@ -17330,6 +17541,41 @@ Ember.Handlebars.get = function(root, path, options) {
17330
17541
  };
17331
17542
  Ember.Handlebars.getPath = Ember.deprecateFunc('`Ember.Handlebars.getPath` has been changed to `Ember.Handlebars.get` for consistency.', Ember.Handlebars.get);
17332
17543
 
17544
+ Ember.Handlebars.resolveParams = function(context, params, options) {
17545
+ var resolvedParams = [], types = options.types, param, type;
17546
+
17547
+ for (var i=0, l=params.length; i<l; i++) {
17548
+ param = params[i];
17549
+ type = types[i];
17550
+
17551
+ if (type === 'ID') {
17552
+ resolvedParams.push(handlebarsGet(context, param, options));
17553
+ } else {
17554
+ resolvedParams.push(param);
17555
+ }
17556
+ }
17557
+
17558
+ return resolvedParams;
17559
+ };
17560
+
17561
+ Ember.Handlebars.resolveHash = function(context, hash, options) {
17562
+ var resolvedHash = {}, types = options.hashTypes, type;
17563
+
17564
+ for (var key in hash) {
17565
+ if (!hash.hasOwnProperty(key)) { continue; }
17566
+
17567
+ type = types[key];
17568
+
17569
+ if (type === 'ID') {
17570
+ resolvedHash[key] = handlebarsGet(context, hash[key], options);
17571
+ } else {
17572
+ resolvedHash[key] = hash[key];
17573
+ }
17574
+ }
17575
+
17576
+ return resolvedHash;
17577
+ };
17578
+
17333
17579
  /**
17334
17580
  @private
17335
17581
 
@@ -17399,6 +17645,18 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
17399
17645
  {{repeat text count=3}}
17400
17646
  ```
17401
17647
 
17648
+ ## Example with bound options
17649
+
17650
+ Bound hash options are also supported. Example:
17651
+
17652
+ ```handlebars
17653
+ {{repeat text countBinding="numRepeats"}}
17654
+ ```
17655
+
17656
+ In this example, count will be bound to the value of
17657
+ the `numRepeats` property on the context. If that property
17658
+ changes, the helper will be re-rendered.
17659
+
17402
17660
  ## Example with extra dependencies
17403
17661
 
17404
17662
  The `Ember.Handlebars.registerBoundHelper` method takes a variable length
@@ -17411,6 +17669,37 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
17411
17669
  }, 'name');
17412
17670
  ```
17413
17671
 
17672
+ ## Example with multiple bound properties
17673
+
17674
+ `Ember.Handlebars.registerBoundHelper` supports binding to
17675
+ multiple properties, e.g.:
17676
+
17677
+ ```javascript
17678
+ Ember.Handlebars.registerBoundHelper('concatenate', function() {
17679
+ var values = arguments[arguments.length - 1];
17680
+ return values.join('||');
17681
+ });
17682
+ ```
17683
+
17684
+ Which allows for template syntax such as {{concatenate prop1 prop2}} or
17685
+ {{concatenate prop1 prop2 prop3}}. If any of the properties change,
17686
+ the helpr will re-render. Note that dependency keys cannot be
17687
+ using in conjunction with multi-property helpers, since it is ambiguous
17688
+ which property the dependent keys would belong to.
17689
+
17690
+ ## Use with unbound helper
17691
+
17692
+ The {{unbound}} helper can be used with bound helper invocations
17693
+ to render them in their unbound form, e.g.
17694
+
17695
+ ```handlebars
17696
+ {{unbound capitalize name}}
17697
+ ```
17698
+
17699
+ In this example, if the name property changes, the helper
17700
+ will not re-render.
17701
+
17702
+
17414
17703
  @method registerBoundHelper
17415
17704
  @for Ember.Handlebars
17416
17705
  @param {String} name
@@ -17418,15 +17707,49 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
17418
17707
  @param {String} dependentKeys*
17419
17708
  */
17420
17709
  Ember.Handlebars.registerBoundHelper = function(name, fn) {
17421
- var dependentKeys = Array.prototype.slice.call(arguments, 2);
17422
- Ember.Handlebars.registerHelper(name, function(property, options) {
17423
- var data = options.data,
17710
+ var dependentKeys = slice.call(arguments, 2);
17711
+
17712
+ function helper() {
17713
+ var properties = slice.call(arguments, 0, -1),
17714
+ numProperties = properties.length,
17715
+ options = arguments[arguments.length - 1],
17716
+ normalizedProperties = [],
17717
+ data = options.data,
17718
+ hash = options.hash,
17424
17719
  view = data.view,
17425
17720
  currentContext = (options.contexts && options.contexts[0]) || this,
17426
- pathRoot, path, normalized,
17427
- observer, loc;
17721
+ normalized,
17722
+ pathRoot, path,
17723
+ loc, hashOption;
17724
+
17725
+ // Detect bound options (e.g. countBinding="otherCount")
17726
+ hash.boundOptions = {};
17727
+ for (hashOption in hash) {
17728
+ if (!hash.hasOwnProperty(hashOption)) { continue; }
17729
+
17730
+ if (Ember.IS_BINDING.test(hashOption) && typeof hash[hashOption] === 'string') {
17731
+ // Lop off 'Binding' suffix.
17732
+ hash.boundOptions[hashOption.slice(0, -7)] = hash[hashOption];
17733
+ }
17734
+ }
17735
+
17736
+ // Expose property names on data.properties object.
17737
+ data.properties = [];
17738
+ for (loc = 0; loc < numProperties; ++loc) {
17739
+ data.properties.push(properties[loc]);
17740
+ normalizedProperties.push(normalizePath(currentContext, properties[loc], data));
17741
+ }
17742
+
17743
+ if (data.isUnbound) {
17744
+ return evaluateUnboundHelper(this, fn, normalizedProperties, options);
17745
+ }
17746
+
17747
+ if (dependentKeys.length === 0) {
17748
+ return evaluateMultiPropertyBoundHelper(currentContext, fn, normalizedProperties, options);
17749
+ }
17750
+
17428
17751
 
17429
- normalized = Ember.Handlebars.normalizePath(currentContext, property, data);
17752
+ normalized = normalizedProperties[0];
17430
17753
 
17431
17754
  pathRoot = normalized.root;
17432
17755
  path = normalized.path;
@@ -17442,28 +17765,116 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) {
17442
17765
 
17443
17766
  view.appendChild(bindView);
17444
17767
 
17445
- observer = function() {
17446
- Ember.run.scheduleOnce('render', bindView, 'rerender');
17447
- };
17768
+ view.registerObserver(pathRoot, path, bindView, rerenderBoundHelperView);
17448
17769
 
17449
- Ember.addObserver(pathRoot, path, observer);
17450
- loc = 0;
17451
- while(loc < dependentKeys.length) {
17452
- Ember.addObserver(pathRoot, path + '.' + dependentKeys[loc], observer);
17453
- loc += 1;
17770
+ for (var i=0, l=dependentKeys.length; i<l; i++) {
17771
+ view.registerObserver(pathRoot, path + '.' + dependentKeys[i], bindView, rerenderBoundHelperView);
17454
17772
  }
17773
+ }
17455
17774
 
17456
- view.one('willClearRender', function() {
17457
- Ember.removeObserver(pathRoot, path, observer);
17458
- loc = 0;
17459
- while(loc < dependentKeys.length) {
17460
- Ember.removeObserver(pathRoot, path + '.' + dependentKeys[loc], observer);
17461
- loc += 1;
17462
- }
17463
- });
17464
- });
17775
+ helper._rawFunction = fn;
17776
+ Ember.Handlebars.registerHelper(name, helper);
17465
17777
  };
17466
17778
 
17779
+ /**
17780
+ @private
17781
+
17782
+ Renders the unbound form of an otherwise bound helper function.
17783
+
17784
+ @param {Function} fn
17785
+ @param {Object} context
17786
+ @param {Array} normalizedProperties
17787
+ @param {String} options
17788
+ */
17789
+ function evaluateMultiPropertyBoundHelper(context, fn, normalizedProperties, options) {
17790
+ var numProperties = normalizedProperties.length,
17791
+ self = this,
17792
+ data = options.data,
17793
+ view = data.view,
17794
+ hash = options.hash,
17795
+ boundOptions = hash.boundOptions,
17796
+ watchedProperties,
17797
+ boundOption, bindView, loc, property, len;
17798
+
17799
+ bindView = new Ember._SimpleHandlebarsView(null, null, !hash.unescaped, data);
17800
+ bindView.normalizedValue = function() {
17801
+ var args = [], value, boundOption;
17802
+
17803
+ // Copy over bound options.
17804
+ for (boundOption in boundOptions) {
17805
+ if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
17806
+ property = normalizePath(context, boundOptions[boundOption], data);
17807
+ bindView.path = property.path;
17808
+ bindView.pathRoot = property.root;
17809
+ hash[boundOption] = Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView);
17810
+ }
17811
+
17812
+ for (loc = 0; loc < numProperties; ++loc) {
17813
+ property = normalizedProperties[loc];
17814
+ bindView.path = property.path;
17815
+ bindView.pathRoot = property.root;
17816
+ args.push(Ember._SimpleHandlebarsView.prototype.normalizedValue.call(bindView));
17817
+ }
17818
+ args.push(options);
17819
+ return fn.apply(context, args);
17820
+ };
17821
+
17822
+ view.appendChild(bindView);
17823
+
17824
+ // Assemble liast of watched properties that'll re-render this helper.
17825
+ watchedProperties = [];
17826
+ for (boundOption in boundOptions) {
17827
+ if (boundOptions.hasOwnProperty(boundOption)) {
17828
+ watchedProperties.push(normalizePath(context, boundOptions[boundOption], data));
17829
+ }
17830
+ }
17831
+ watchedProperties = watchedProperties.concat(normalizedProperties);
17832
+
17833
+ // Observe each property.
17834
+ for (loc = 0, len = watchedProperties.length; loc < len; ++loc) {
17835
+ property = watchedProperties[loc];
17836
+ view.registerObserver(property.root, property.path, bindView, rerenderBoundHelperView);
17837
+ }
17838
+
17839
+ }
17840
+
17841
+ /**
17842
+ @private
17843
+
17844
+ An observer function used with bound helpers which
17845
+ will schedule a re-render of the _SimpleHandlebarsView
17846
+ connected with the helper.
17847
+ */
17848
+ function rerenderBoundHelperView() {
17849
+ Ember.run.scheduleOnce('render', this, 'rerender');
17850
+ }
17851
+
17852
+ /**
17853
+ @private
17854
+
17855
+ Renders the unbound form of an otherwise bound helper function.
17856
+
17857
+ @param {Function} fn
17858
+ @param {Object} context
17859
+ @param {Array} normalizedProperties
17860
+ @param {String} options
17861
+ */
17862
+ function evaluateUnboundHelper(context, fn, normalizedProperties, options) {
17863
+ var args = [], hash = options.hash, boundOptions = hash.boundOptions, loc, len, property, boundOption;
17864
+
17865
+ for (boundOption in boundOptions) {
17866
+ if (!boundOptions.hasOwnProperty(boundOption)) { continue; }
17867
+ hash[boundOption] = Ember.Handlebars.get(context, boundOptions[boundOption], options);
17868
+ }
17869
+
17870
+ for(loc = 0, len = normalizedProperties.length; loc < len; ++loc) {
17871
+ property = normalizedProperties[loc];
17872
+ args.push(Ember.Handlebars.get(context, property.path, options));
17873
+ }
17874
+ args.push(options);
17875
+ return fn.apply(context, args);
17876
+ }
17877
+
17467
17878
  /**
17468
17879
  @private
17469
17880
 
@@ -17567,7 +17978,7 @@ var DOMManager = {
17567
17978
  view.transitionTo('preRender');
17568
17979
 
17569
17980
  Ember.run.schedule('render', this, function() {
17570
- if (get(view, 'isDestroyed')) { return; }
17981
+ if (view.isDestroying) { return; }
17571
17982
 
17572
17983
  view.clearRenderedChildren();
17573
17984
  var buffer = view.renderToBuffer();
@@ -17988,20 +18399,16 @@ var EmberHandlebars = Ember.Handlebars, helpers = EmberHandlebars.helpers;
17988
18399
 
17989
18400
  // Binds a property into the DOM. This will create a hook in DOM that the
17990
18401
  // KVO system will look for and update if the property changes.
17991
- function bind(property, options, preserveContext, shouldDisplay, valueNormalizer) {
18402
+ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties) {
17992
18403
  var data = options.data,
17993
18404
  fn = options.fn,
17994
18405
  inverse = options.inverse,
17995
18406
  view = data.view,
17996
18407
  currentContext = this,
17997
- pathRoot, path, normalized,
17998
- observer;
18408
+ normalized, observer, i;
17999
18409
 
18000
18410
  normalized = normalizePath(currentContext, property, data);
18001
18411
 
18002
- pathRoot = normalized.root;
18003
- path = normalized.path;
18004
-
18005
18412
  // Set up observers for observable objects
18006
18413
  if ('object' === typeof this) {
18007
18414
  if (data.insideGroup) {
@@ -18009,7 +18416,7 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
18009
18416
  Ember.run.once(view, 'rerender');
18010
18417
  };
18011
18418
 
18012
- var template, context, result = handlebarsGet(pathRoot, path, options);
18419
+ var template, context, result = handlebarsGet(currentContext, property, options);
18013
18420
 
18014
18421
  result = valueNormalizer(result);
18015
18422
 
@@ -18031,8 +18438,8 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
18031
18438
  valueNormalizerFunc: valueNormalizer,
18032
18439
  displayTemplate: fn,
18033
18440
  inverseTemplate: inverse,
18034
- path: path,
18035
- pathRoot: pathRoot,
18441
+ path: property,
18442
+ pathRoot: currentContext,
18036
18443
  previousContext: currentContext,
18037
18444
  isEscaped: !options.hash.unescaped,
18038
18445
  templateData: options.data
@@ -18049,17 +18456,18 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer
18049
18456
  // tells the Ember._HandlebarsBoundView to re-render. If property
18050
18457
  // is an empty string, we are printing the current context
18051
18458
  // object ({{this}}) so updating it is not our responsibility.
18052
- if (path !== '') {
18053
- Ember.addObserver(pathRoot, path, observer);
18054
-
18055
- view.one('willClearRender', function() {
18056
- Ember.removeObserver(pathRoot, path, observer);
18057
- });
18459
+ if (normalized.path !== '') {
18460
+ view.registerObserver(normalized.root, normalized.path, observer);
18461
+ if (childProperties) {
18462
+ for (i=0; i<childProperties.length; i++) {
18463
+ view.registerObserver(normalized.root, normalized.path+'.'+childProperties[i], observer);
18464
+ }
18465
+ }
18058
18466
  }
18059
18467
  } else {
18060
18468
  // The object is not observable, so just render it out and
18061
18469
  // be done with it.
18062
- data.buffer.push(handlebarsGet(pathRoot, path, options));
18470
+ data.buffer.push(handlebarsGet(currentContext, property, options));
18063
18471
  }
18064
18472
  }
18065
18473
 
@@ -18067,14 +18475,10 @@ function simpleBind(property, options) {
18067
18475
  var data = options.data,
18068
18476
  view = data.view,
18069
18477
  currentContext = this,
18070
- pathRoot, path, normalized,
18071
- observer;
18478
+ normalized, observer;
18072
18479
 
18073
18480
  normalized = normalizePath(currentContext, property, data);
18074
18481
 
18075
- pathRoot = normalized.root;
18076
- path = normalized.path;
18077
-
18078
18482
  // Set up observers for observable objects
18079
18483
  if ('object' === typeof this) {
18080
18484
  if (data.insideGroup) {
@@ -18082,12 +18486,12 @@ function simpleBind(property, options) {
18082
18486
  Ember.run.once(view, 'rerender');
18083
18487
  };
18084
18488
 
18085
- var result = handlebarsGet(pathRoot, path, options);
18489
+ var result = handlebarsGet(currentContext, property, options);
18086
18490
  if (result === null || result === undefined) { result = ""; }
18087
18491
  data.buffer.push(result);
18088
18492
  } else {
18089
18493
  var bindView = new Ember._SimpleHandlebarsView(
18090
- path, pathRoot, !options.hash.unescaped, options.data
18494
+ property, currentContext, !options.hash.unescaped, options.data
18091
18495
  );
18092
18496
 
18093
18497
  bindView._parentView = view;
@@ -18102,17 +18506,13 @@ function simpleBind(property, options) {
18102
18506
  // tells the Ember._HandlebarsBoundView to re-render. If property
18103
18507
  // is an empty string, we are printing the current context
18104
18508
  // object ({{this}}) so updating it is not our responsibility.
18105
- if (path !== '') {
18106
- Ember.addObserver(pathRoot, path, observer);
18107
-
18108
- view.one('willClearRender', function() {
18109
- Ember.removeObserver(pathRoot, path, observer);
18110
- });
18509
+ if (normalized.path !== '') {
18510
+ view.registerObserver(normalized.root, normalized.path, observer);
18111
18511
  }
18112
18512
  } else {
18113
18513
  // The object is not observable, so just render it out and
18114
18514
  // be done with it.
18115
- data.buffer.push(handlebarsGet(pathRoot, path, options));
18515
+ data.buffer.push(handlebarsGet(currentContext, property, options));
18116
18516
  }
18117
18517
  }
18118
18518
 
@@ -18201,14 +18601,17 @@ EmberHandlebars.registerHelper('bind', function(property, options) {
18201
18601
  EmberHandlebars.registerHelper('boundIf', function(property, fn) {
18202
18602
  var context = (fn.contexts && fn.contexts[0]) || this;
18203
18603
  var func = function(result) {
18204
- if (Ember.typeOf(result) === 'array') {
18604
+ var truthy = result && get(result, 'isTruthy');
18605
+ if (typeof truthy === 'boolean') { return truthy; }
18606
+
18607
+ if (Ember.isArray(result)) {
18205
18608
  return get(result, 'length') !== 0;
18206
18609
  } else {
18207
18610
  return !!result;
18208
18611
  }
18209
18612
  };
18210
18613
 
18211
- return bind.call(context, property, fn, true, func, func);
18614
+ return bind.call(context, property, fn, true, func, func, ['isTruthy', 'length']);
18212
18615
  });
18213
18616
 
18214
18617
  /**
@@ -18442,22 +18845,19 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18442
18845
  // current value of the property as an attribute.
18443
18846
  forEach.call(attrKeys, function(attr) {
18444
18847
  var path = attrs[attr],
18445
- pathRoot, normalized;
18848
+ normalized;
18446
18849
 
18447
18850
 
18448
18851
  normalized = normalizePath(ctx, path, options.data);
18449
18852
 
18450
- pathRoot = normalized.root;
18451
- path = normalized.path;
18452
-
18453
- var value = (path === 'this') ? pathRoot : handlebarsGet(pathRoot, path, options),
18853
+ var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options),
18454
18854
  type = Ember.typeOf(value);
18455
18855
 
18456
18856
 
18457
18857
  var observer, invoker;
18458
18858
 
18459
18859
  observer = function observer() {
18460
- var result = handlebarsGet(pathRoot, path, options);
18860
+ var result = handlebarsGet(ctx, path, options);
18461
18861
 
18462
18862
 
18463
18863
  var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']");
@@ -18467,7 +18867,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18467
18867
  // In that case, we can assume the template has been re-rendered
18468
18868
  // and we need to clean up the observer.
18469
18869
  if (!elem || elem.length === 0) {
18470
- Ember.removeObserver(pathRoot, path, invoker);
18870
+ Ember.removeObserver(normalized.root, normalized.path, invoker);
18471
18871
  return;
18472
18872
  }
18473
18873
 
@@ -18482,11 +18882,7 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
18482
18882
  // When the observer fires, find the element using the
18483
18883
  // unique data id and update the attribute to the new value.
18484
18884
  if (path !== 'this') {
18485
- Ember.addObserver(pathRoot, path, invoker);
18486
-
18487
- view.one('willClearRender', function() {
18488
- Ember.removeObserver(pathRoot, path, invoker);
18489
- });
18885
+ view.registerObserver(normalized.root, normalized.path, invoker);
18490
18886
  }
18491
18887
 
18492
18888
  // if this changes, also change the logic in ember-views/lib/views/view.js
@@ -18576,7 +18972,7 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId,
18576
18972
  // class name.
18577
18973
  observer = function() {
18578
18974
  // Get the current value of the property
18579
- newClass = classStringForPath(pathRoot, parsedPath, options);
18975
+ newClass = classStringForPath(context, parsedPath, options);
18580
18976
  elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$();
18581
18977
 
18582
18978
  // If we can't find the element anymore, a parent template has been
@@ -18605,16 +19001,12 @@ EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId,
18605
19001
  };
18606
19002
 
18607
19003
  if (path !== '' && path !== 'this') {
18608
- Ember.addObserver(pathRoot, path, invoker);
18609
-
18610
- view.one('willClearRender', function() {
18611
- Ember.removeObserver(pathRoot, path, invoker);
18612
- });
19004
+ view.registerObserver(pathRoot, path, invoker);
18613
19005
  }
18614
19006
 
18615
19007
  // We've already setup the observer; now we just need to figure out the
18616
19008
  // correct behavior right now on the first pass through.
18617
- value = classStringForPath(pathRoot, parsedPath, options);
19009
+ value = classStringForPath(context, parsedPath, options);
18618
19010
 
18619
19011
  if (value) {
18620
19012
  ret.push(value);
@@ -19134,7 +19526,7 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
19134
19526
  if (hash.hasOwnProperty(prop)) {
19135
19527
  match = prop.match(/^item(.)(.*)$/);
19136
19528
 
19137
- if(match) {
19529
+ if(match && prop !== 'itemController') {
19138
19530
  // Convert itemShouldFoo -> shouldFoo
19139
19531
  itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
19140
19532
  // Delete from hash as this will end up getting passed to the
@@ -19161,13 +19553,10 @@ Ember.Handlebars.registerHelper('collection', function(path, options) {
19161
19553
  } else if (hash.emptyViewClass) {
19162
19554
  emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
19163
19555
  }
19164
- hash.emptyView = emptyViewClass;
19556
+ if (emptyViewClass) { hash.emptyView = emptyViewClass; }
19165
19557
 
19166
- if (hash.eachHelper === 'each') {
19167
- itemHash._context = Ember.computed(function() {
19168
- return get(this, 'content');
19169
- }).property('content');
19170
- delete hash.eachHelper;
19558
+ if(!hash.keyword){
19559
+ itemHash._context = Ember.computed.alias('content');
19171
19560
  }
19172
19561
 
19173
19562
  var viewString = view.toString();
@@ -19200,13 +19589,31 @@ var handlebarsGet = Ember.Handlebars.get;
19200
19589
  <div>{{unbound somePropertyThatDoesntChange}}</div>
19201
19590
  ```
19202
19591
 
19592
+ `unbound` can also be used in conjunction with a bound helper to
19593
+ render it in its unbound form:
19594
+
19595
+ ```handlebars
19596
+ <div>{{unbound helperName somePropertyThatDoesntChange}}</div>
19597
+ ```
19598
+
19203
19599
  @method unbound
19204
19600
  @for Ember.Handlebars.helpers
19205
19601
  @param {String} property
19206
19602
  @return {String} HTML string
19207
19603
  */
19208
19604
  Ember.Handlebars.registerHelper('unbound', function(property, fn) {
19209
- var context = (fn.contexts && fn.contexts[0]) || this;
19605
+ var options = arguments[arguments.length - 1], helper, context, out;
19606
+
19607
+ if(arguments.length > 2) {
19608
+ // Unbound helper call.
19609
+ options.data.isUnbound = true;
19610
+ helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing;
19611
+ out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
19612
+ delete options.data.isUnbound;
19613
+ return out;
19614
+ }
19615
+
19616
+ context = (fn.contexts && fn.contexts[0]) || this;
19210
19617
  return handlebarsGet(context, property, fn);
19211
19618
  });
19212
19619
 
@@ -19272,6 +19679,44 @@ Ember.Handlebars.registerHelper('debugger', function() {
19272
19679
  var get = Ember.get, set = Ember.set;
19273
19680
 
19274
19681
  Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
19682
+ init: function() {
19683
+ var itemController = get(this, 'itemController');
19684
+ var binding;
19685
+
19686
+ if (itemController) {
19687
+ var controller = Ember.ArrayController.create();
19688
+ set(controller, 'itemController', itemController);
19689
+ set(controller, 'container', get(this, 'controller.container'));
19690
+ set(controller, '_eachView', this);
19691
+ set(controller, 'target', get(this, 'controller'));
19692
+
19693
+ this.disableContentObservers(function() {
19694
+ set(this, 'content', controller);
19695
+ binding = new Ember.Binding('content', '_eachView.dataSource').oneWay();
19696
+ binding.connect(controller);
19697
+ });
19698
+
19699
+ set(this, '_arrayController', controller);
19700
+ } else {
19701
+ this.disableContentObservers(function() {
19702
+ binding = new Ember.Binding('content', 'dataSource').oneWay();
19703
+ binding.connect(this);
19704
+ });
19705
+ }
19706
+
19707
+ return this._super();
19708
+ },
19709
+
19710
+ disableContentObservers: function(callback) {
19711
+ Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange');
19712
+ Ember.removeObserver(this, 'content', null, '_contentDidChange');
19713
+
19714
+ callback.apply(this);
19715
+
19716
+ Ember.addBeforeObserver(this, 'content', null, '_contentWillChange');
19717
+ Ember.addObserver(this, 'content', null, '_contentDidChange');
19718
+ },
19719
+
19275
19720
  itemViewClass: Ember._MetamorphView,
19276
19721
  emptyViewClass: Ember._MetamorphView,
19277
19722
 
@@ -19282,6 +19727,7 @@ Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
19282
19727
  // to insert keywords, it is responsible for cloning
19283
19728
  // the keywords hash. This will be fixed momentarily.
19284
19729
  var keyword = get(this, 'keyword');
19730
+ var content = get(view, 'content');
19285
19731
 
19286
19732
  if (keyword) {
19287
19733
  var data = get(view, 'templateData');
@@ -19290,14 +19736,28 @@ Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, {
19290
19736
  data.keywords = view.cloneKeywords();
19291
19737
  set(view, 'templateData', data);
19292
19738
 
19293
- var content = get(view, 'content');
19294
-
19295
19739
  // In this case, we do not bind, because the `content` of
19296
19740
  // a #each item cannot change.
19297
19741
  data.keywords[keyword] = content;
19298
19742
  }
19299
19743
 
19744
+ // If {{#each}} is looping over an array of controllers,
19745
+ // point each child view at their respective controller.
19746
+ if (content && get(content, 'isController')) {
19747
+ set(view, 'controller', content);
19748
+ }
19749
+
19300
19750
  return view;
19751
+ },
19752
+
19753
+ willDestroy: function() {
19754
+ var arrayController = get(this, '_arrayController');
19755
+
19756
+ if (arrayController) {
19757
+ arrayController.destroy();
19758
+ }
19759
+
19760
+ return this._super();
19301
19761
  }
19302
19762
  });
19303
19763
 
@@ -19391,7 +19851,8 @@ GroupedEach.prototype = {
19391
19851
 
19392
19852
  /**
19393
19853
  The `{{#each}}` helper loops over elements in a collection, rendering its
19394
- block once for each item:
19854
+ block once for each item. It is an extension of the base Handlebars `{{#each}}`
19855
+ helper:
19395
19856
 
19396
19857
  ```javascript
19397
19858
  Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
@@ -19423,12 +19884,20 @@ GroupedEach.prototype = {
19423
19884
  {{this}}
19424
19885
  {{/each}}
19425
19886
  ```
19887
+ ### {{else}} condition
19888
+ `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
19889
+ if the collection is empty.
19426
19890
 
19427
- ### Blockless Use
19428
-
19429
- If you provide an `itemViewClass` option that has its own `template` you can
19430
- omit the block in a similar way to how it can be done with the collection
19431
- helper.
19891
+ ```
19892
+ {{#each person in Developers}}
19893
+ {{person.name}}
19894
+ {{else}}
19895
+ <p>Sorry, nobody is available for this task.</p>
19896
+ {{/each}}
19897
+ ```
19898
+ ### Specifying a View class for items
19899
+ If you provide an `itemViewClass` option that references a view class
19900
+ with its own `template` you can omit the block.
19432
19901
 
19433
19902
  The following template:
19434
19903
 
@@ -19454,8 +19923,6 @@ GroupedEach.prototype = {
19454
19923
  App.AnItemView = Ember.View.extend({
19455
19924
  template: Ember.Handlebars.compile("Greetings {{name}}")
19456
19925
  });
19457
-
19458
- App.initialize();
19459
19926
  ```
19460
19927
 
19461
19928
  Will result in the HTML structure below
@@ -19467,11 +19934,39 @@ GroupedEach.prototype = {
19467
19934
  <div class="ember-view">Greetings Sara</div>
19468
19935
  </div>
19469
19936
  ```
19470
-
19937
+
19938
+ ### Representing each item with a Controller.
19939
+ By default the controller lookup within an `{{#each}}` block will be
19940
+ the controller of the template where the `{{#each}}` was used. If each
19941
+ item needs to be presented by a custom controller you can provide a
19942
+ `itemController` option which references a controller by lookup name.
19943
+ Each item in the loop will be wrapped in an instance of this controller
19944
+ and the item itself will be set to the `content` property of that controller.
19945
+
19946
+ This is useful in cases where properties of model objects need transformation
19947
+ or synthesis for display:
19948
+
19949
+ ```javascript
19950
+ App.DeveloperController = Ember.ObjectController.extend({
19951
+ isAvailableForHire: function(){
19952
+ return !this.get('content.isEmployed') && this.get('content.isSeekingWork');
19953
+ }.property('isEmployed', 'isSeekingWork')
19954
+ })
19955
+ ```
19956
+
19957
+ ```handlebars
19958
+ {{#each person in Developers itemController="developer"}}
19959
+ {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
19960
+ {{/each}}
19961
+ ```
19962
+
19471
19963
  @method each
19472
19964
  @for Ember.Handlebars.helpers
19473
19965
  @param [name] {String} name for item (used with `in`)
19474
19966
  @param path {String} path
19967
+ @param [options] {Object} Handlebars key/value pairs of options
19968
+ @param [options.itemViewClass] {String} a path to a view class used for each item
19969
+ @param [options.itemController] {String} name of a controller to be created for each item
19475
19970
  */
19476
19971
  Ember.Handlebars.registerHelper('each', function(path, options) {
19477
19972
  if (arguments.length === 4) {
@@ -19484,11 +19979,9 @@ Ember.Handlebars.registerHelper('each', function(path, options) {
19484
19979
  if (path === '') { path = "this"; }
19485
19980
 
19486
19981
  options.hash.keyword = keywordName;
19487
- } else {
19488
- options.hash.eachHelper = 'each';
19489
19982
  }
19490
19983
 
19491
- options.hash.contentBinding = path;
19984
+ options.hash.dataSourceBinding = path;
19492
19985
  // Set up emptyView as a metamorph with no tag
19493
19986
  //options.hash.emptyViewClass = Ember._MetamorphView;
19494
19987
 
@@ -19844,7 +20337,7 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
19844
20337
 
19845
20338
  classNames: ['ember-text-field'],
19846
20339
  tagName: "input",
19847
- attributeBindings: ['type', 'value', 'size'],
20340
+ attributeBindings: ['type', 'value', 'size', 'pattern'],
19848
20341
 
19849
20342
  /**
19850
20343
  The `value` attribute of the input element. As the user inputs text, this
@@ -19874,6 +20367,15 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
19874
20367
  */
19875
20368
  size: null,
19876
20369
 
20370
+ /**
20371
+ The `pattern` the pattern attribute of input element.
20372
+
20373
+ @property pattern
20374
+ @type String
20375
+ @default null
20376
+ */
20377
+ pattern: null,
20378
+
19877
20379
  /**
19878
20380
  The action to be sent when the user presses the return key.
19879
20381
 
@@ -19887,15 +20389,34 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
19887
20389
  */
19888
20390
  action: null,
19889
20391
 
19890
- insertNewline: function() {
19891
- var controller = get(this, 'controller'),
20392
+ /**
20393
+ Whether they `keyUp` event that triggers an `action` to be sent continues
20394
+ propagating to other views.
20395
+
20396
+ By default, when the user presses the return key on their keyboard and
20397
+ the text field has an `action` set, the action will be sent to the view's
20398
+ controller and the key event will stop propagating.
20399
+
20400
+ If you would like parent views to receive the `keyUp` event even after an
20401
+ action has been dispatched, set `bubbles` to true.
20402
+
20403
+ @property bubbles
20404
+ @type Boolean
20405
+ @default false
20406
+ */
20407
+ bubbles: false,
20408
+
20409
+ insertNewline: function(event) {
20410
+ var controller = get(this, 'controller'),
19892
20411
  action = get(this, 'action');
19893
20412
 
19894
20413
  if (action) {
19895
- controller.send(action, get(this, 'value'));
19896
- }
20414
+ controller.send(action, get(this, 'value'), this);
19897
20415
 
19898
- return false;
20416
+ if (!get(this, 'bubbles')) {
20417
+ event.stopPropagation();
20418
+ }
20419
+ }
19899
20420
  }
19900
20421
  });
19901
20422
 
@@ -20369,30 +20890,37 @@ Ember.Select = Ember.View.extend(
20369
20890
  tagName: 'select',
20370
20891
  classNames: ['ember-select'],
20371
20892
  defaultTemplate: Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) {
20893
+ this.compilerInfo = [2,'>= 1.0.0-rc.3'];
20372
20894
  helpers = helpers || Ember.Handlebars.helpers; data = data || {};
20373
- var buffer = '', stack1, escapeExpression=this.escapeExpression, self=this;
20895
+ var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this;
20374
20896
 
20375
20897
  function program1(depth0,data) {
20376
20898
 
20377
- var buffer = '', stack1;
20899
+ var buffer = '', hashTypes;
20378
20900
  data.buffer.push("<option value=\"\">");
20379
- stack1 = helpers._triageMustache.call(depth0, "view.prompt", {hash:{},contexts:[depth0],data:data});
20380
- data.buffer.push(escapeExpression(stack1) + "</option>");
20381
- return buffer;}
20901
+ hashTypes = {};
20902
+ data.buffer.push(escapeExpression(helpers._triageMustache.call(depth0, "view.prompt", {hash:{},contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data})));
20903
+ data.buffer.push("</option>");
20904
+ return buffer;
20905
+ }
20382
20906
 
20383
20907
  function program3(depth0,data) {
20384
20908
 
20385
- var stack1;
20386
- stack1 = {};
20387
- stack1['contentBinding'] = "this";
20388
- stack1 = helpers.view.call(depth0, "Ember.SelectOption", {hash:stack1,contexts:[depth0],data:data});
20389
- data.buffer.push(escapeExpression(stack1));}
20909
+ var hashTypes;
20910
+ hashTypes = {'contentBinding': "STRING"};
20911
+ data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{
20912
+ 'contentBinding': ("this")
20913
+ },contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data})));
20914
+ }
20390
20915
 
20391
- stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],data:data});
20916
+ hashTypes = {};
20917
+ 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});
20392
20918
  if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
20393
- stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],data:data});
20919
+ hashTypes = {};
20920
+ 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});
20394
20921
  if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
20395
20922
  return buffer;
20923
+
20396
20924
  }),
20397
20925
  attributeBindings: ['multiple', 'disabled', 'tabindex'],
20398
20926
 
@@ -21728,10 +22256,16 @@ define("router",
21728
22256
  if (handler.setup) { handler.setup(context); }
21729
22257
  });
21730
22258
 
22259
+ var aborted = false;
21731
22260
  eachHandler(partition.entered, function(handler, context) {
22261
+ if (aborted) { return; }
21732
22262
  if (handler.enter) { handler.enter(); }
21733
22263
  setContext(handler, context);
21734
- if (handler.setup) { handler.setup(context); }
22264
+ if (handler.setup) {
22265
+ if (false === handler.setup(context)) {
22266
+ aborted = true;
22267
+ }
22268
+ }
21735
22269
  });
21736
22270
 
21737
22271
  if (router.didTransition) {
@@ -21855,21 +22389,23 @@ define("router",
21855
22389
  function trigger(router, args) {
21856
22390
  var currentHandlerInfos = router.currentHandlerInfos;
21857
22391
 
22392
+ var name = args.shift();
22393
+
21858
22394
  if (!currentHandlerInfos) {
21859
- throw new Error("Could not trigger event. There are no active handlers");
22395
+ throw new Error("Could not trigger event '" + name + "'. There are no active handlers");
21860
22396
  }
21861
22397
 
21862
- var name = args.shift();
21863
-
21864
22398
  for (var i=currentHandlerInfos.length-1; i>=0; i--) {
21865
22399
  var handlerInfo = currentHandlerInfos[i],
21866
22400
  handler = handlerInfo.handler;
21867
22401
 
21868
22402
  if (handler.events && handler.events[name]) {
21869
22403
  handler.events[name].apply(handler, args);
21870
- break;
22404
+ return;
21871
22405
  }
21872
22406
  }
22407
+
22408
+ throw new Error("Nothing handled the event '" + name + "'.");
21873
22409
  }
21874
22410
 
21875
22411
  function setContext(handler, context) {
@@ -22015,7 +22551,7 @@ Ember.generateController = function(container, controllerName, context) {
22015
22551
  var Router = requireModule("router");
22016
22552
  var get = Ember.get, set = Ember.set, classify = Ember.String.classify;
22017
22553
 
22018
- var DefaultView = Ember.View.extend(Ember._Metamorph);
22554
+ var DefaultView = Ember._MetamorphView;
22019
22555
  function setupLocation(router) {
22020
22556
  var location = get(router, 'location'),
22021
22557
  rootURL = get(router, 'rootURL');
@@ -22031,6 +22567,14 @@ function setupLocation(router) {
22031
22567
  }
22032
22568
  }
22033
22569
 
22570
+ /**
22571
+ The `Ember.Router` class manages the application state and URLs. Refer to
22572
+ the [routing guide](http://emberjs.com/guides/routing/) for documentation.
22573
+
22574
+ @class Router
22575
+ @namespace Ember
22576
+ @extends Ember.Object
22577
+ */
22034
22578
  Ember.Router = Ember.Object.extend({
22035
22579
  location: 'hash',
22036
22580
 
@@ -22040,6 +22584,10 @@ Ember.Router = Ember.Object.extend({
22040
22584
  setupLocation(this);
22041
22585
  },
22042
22586
 
22587
+ url: Ember.computed(function() {
22588
+ return get(this, 'location').getURL();
22589
+ }),
22590
+
22043
22591
  startRouting: function() {
22044
22592
  this.router = this.router || this.constructor.map(Ember.K);
22045
22593
 
@@ -22053,15 +22601,18 @@ Ember.Router = Ember.Object.extend({
22053
22601
  container.register('view', 'default', DefaultView);
22054
22602
  container.register('view', 'toplevel', Ember.View.extend());
22055
22603
 
22056
- router.handleURL(location.getURL());
22057
22604
  location.onUpdateURL(function(url) {
22058
- router.handleURL(url);
22605
+ self.handleURL(url);
22059
22606
  });
22607
+
22608
+ this.handleURL(location.getURL());
22060
22609
  },
22061
22610
 
22062
22611
  didTransition: function(infos) {
22063
22612
  // Don't do any further action here if we redirected
22064
- if (infos[infos.length-1].handler.transitioned) { return; }
22613
+ for (var i=0, l=infos.length; i<l; i++) {
22614
+ if (infos[i].handler.redirected) { return; }
22615
+ }
22065
22616
 
22066
22617
  var appController = this.container.lookup('controller:application'),
22067
22618
  path = routePath(infos);
@@ -22079,23 +22630,14 @@ Ember.Router = Ember.Object.extend({
22079
22630
  this.notifyPropertyChange('url');
22080
22631
  },
22081
22632
 
22082
- transitionTo: function(passedName) {
22083
- var args = [].slice.call(arguments), name;
22084
-
22085
- if (!this.router.hasRoute(passedName)) {
22086
- name = args[0] = passedName + '.index';
22087
- } else {
22088
- name = passedName;
22089
- }
22090
-
22091
-
22092
- this.router.transitionTo.apply(this.router, args);
22093
- this.notifyPropertyChange('url');
22633
+ transitionTo: function(name) {
22634
+ var args = [].slice.call(arguments);
22635
+ doTransition(this, 'transitionTo', args);
22094
22636
  },
22095
22637
 
22096
22638
  replaceWith: function() {
22097
- this.router.replaceWith.apply(this.router, arguments);
22098
- this.notifyPropertyChange('url');
22639
+ var args = [].slice.call(arguments);
22640
+ doTransition(this, 'replaceWith', args);
22099
22641
  },
22100
22642
 
22101
22643
  generate: function() {
@@ -22109,11 +22651,7 @@ Ember.Router = Ember.Object.extend({
22109
22651
  },
22110
22652
 
22111
22653
  send: function(name, context) {
22112
- if (Ember.$ && context instanceof Ember.$.Event) {
22113
- context = context.context;
22114
- }
22115
-
22116
- this.router.trigger(name, context);
22654
+ this.router.trigger.apply(this.router, arguments);
22117
22655
  },
22118
22656
 
22119
22657
  hasRoute: function(route) {
@@ -22230,6 +22768,20 @@ function setupRouter(emberRouter, router, location) {
22230
22768
  };
22231
22769
  }
22232
22770
 
22771
+ function doTransition(router, method, args) {
22772
+ var passedName = args[0], name;
22773
+
22774
+ if (!router.router.hasRoute(args[0])) {
22775
+ name = args[0] = passedName + '.index';
22776
+ } else {
22777
+ name = passedName;
22778
+ }
22779
+
22780
+
22781
+ router.router[method].apply(router.router, args);
22782
+ router.notifyPropertyChange('url');
22783
+ }
22784
+
22233
22785
  Ember.Router.reopenClass({
22234
22786
  map: function(callback) {
22235
22787
  var router = this.router = new Router();
@@ -22259,12 +22811,70 @@ var get = Ember.get, set = Ember.set,
22259
22811
  classify = Ember.String.classify,
22260
22812
  decamelize = Ember.String.decamelize;
22261
22813
 
22814
+ /**
22815
+ The `Ember.Route` class is used to define individual routes. Refer to
22816
+ the [routing guide](http://emberjs.com/guides/routing/) for documentation.
22262
22817
 
22818
+ @class Route
22819
+ @namespace Ember
22820
+ @extends Ember.Object
22821
+ */
22263
22822
  Ember.Route = Ember.Object.extend({
22823
+ /**
22824
+ @private
22825
+
22826
+ @method exit
22827
+ */
22264
22828
  exit: function() {
22829
+ this.deactivate();
22265
22830
  teardownView(this);
22266
22831
  },
22267
22832
 
22833
+ /**
22834
+ @private
22835
+
22836
+ @method enter
22837
+ */
22838
+ enter: function() {
22839
+ this.activate();
22840
+ },
22841
+
22842
+ /**
22843
+ The collection of functions keyed by name available on this route as
22844
+ action targets.
22845
+
22846
+ These functions will be invoked when a matching `{{action}}` is triggered
22847
+ from within a template and the application's current route is this route.
22848
+
22849
+ Events can also be invoked from other parts of your application via `Route#send`.
22850
+
22851
+ The context of event will be the this route.
22852
+
22853
+ @see {Ember.Route#send}
22854
+ @see {Handlebars.helpers.action}
22855
+
22856
+ @property events
22857
+ @type Hash
22858
+ @default null
22859
+ */
22860
+ events: null,
22861
+
22862
+ /**
22863
+ This hook is executed when the router completely exits this route. It is
22864
+ not executed when the model for the route changes.
22865
+
22866
+ @method deactivate
22867
+ */
22868
+ deactivate: Ember.K,
22869
+
22870
+ /**
22871
+ This hook is executed when the router enters the route for the first time.
22872
+ It is not executed when the model for the route changes.
22873
+
22874
+ @method activate
22875
+ */
22876
+ activate: Ember.K,
22877
+
22268
22878
  /**
22269
22879
  Transition into another route. Optionally supply a model for the
22270
22880
  route in question. The model will be serialized into the URL
@@ -22275,7 +22885,7 @@ Ember.Route = Ember.Object.extend({
22275
22885
  @param {...Object} models the
22276
22886
  */
22277
22887
  transitionTo: function() {
22278
- this.transitioned = true;
22888
+ if (this._checkingRedirect) { this.redirected = true; }
22279
22889
  return this.router.transitionTo.apply(this.router, arguments);
22280
22890
  },
22281
22891
 
@@ -22288,7 +22898,7 @@ Ember.Route = Ember.Object.extend({
22288
22898
  @param {...Object} models the
22289
22899
  */
22290
22900
  replaceWith: function() {
22291
- this.transitioned = true;
22901
+ if (this._checkingRedirect) { this.redirected = true; }
22292
22902
  return this.router.replaceWith.apply(this.router, arguments);
22293
22903
  },
22294
22904
 
@@ -22304,14 +22914,18 @@ Ember.Route = Ember.Object.extend({
22304
22914
  @method setup
22305
22915
  */
22306
22916
  setup: function(context) {
22307
- this.transitioned = false;
22917
+ this.redirected = false;
22918
+ this._checkingRedirect = true;
22919
+
22308
22920
  this.redirect(context);
22309
22921
 
22310
- if (this.transitioned) { return; }
22922
+ this._checkingRedirect = false;
22923
+ if (this.redirected) { return false; }
22311
22924
 
22312
22925
  var controller = this.controllerFor(this.routeName, context);
22313
22926
 
22314
22927
  if (controller) {
22928
+ this.controller = controller;
22315
22929
  set(controller, 'model', context);
22316
22930
  }
22317
22931
 
@@ -22386,16 +23000,18 @@ Ember.Route = Ember.Object.extend({
22386
23000
  @param {Object} params the parameters extracted from the URL
22387
23001
  */
22388
23002
  model: function(params) {
22389
- var match, name, value;
23003
+ var match, name, sawParams, value;
22390
23004
 
22391
23005
  for (var prop in params) {
22392
23006
  if (match = prop.match(/^(.*)_id$/)) {
22393
23007
  name = match[1];
22394
23008
  value = params[prop];
22395
23009
  }
23010
+ sawParams = true;
22396
23011
  }
22397
23012
 
22398
- if (!name) { return; }
23013
+ if (!name && sawParams) { return params; }
23014
+ else if (!name) { return; }
22399
23015
 
22400
23016
  var className = classify(name),
22401
23017
  namespace = this.router.namespace,
@@ -22442,7 +23058,12 @@ Ember.Route = Ember.Object.extend({
22442
23058
  if (params.length !== 1) { return; }
22443
23059
 
22444
23060
  var name = params[0], object = {};
22445
- object[name] = get(model, 'id');
23061
+
23062
+ if (/_id$/.test(name)) {
23063
+ object[name] = get(model, 'id');
23064
+ } else {
23065
+ object[name] = model;
23066
+ }
22446
23067
 
22447
23068
  return object;
22448
23069
  },
@@ -22610,12 +23231,16 @@ Ember.Route = Ember.Object.extend({
22610
23231
 
22611
23232
  if (!view && !template) { return; }
22612
23233
 
22613
- this.lastRenderedTemplate = name;
22614
-
22615
23234
  options = normalizeOptions(this, name, template, options);
22616
23235
  view = setupView(view, container, options);
22617
23236
 
23237
+ if (options.outlet === 'main') { this.lastRenderedTemplate = name; }
23238
+
22618
23239
  appendView(this, view, options);
23240
+ },
23241
+
23242
+ willDestroy: function() {
23243
+ teardownView(this);
22619
23244
  }
22620
23245
  });
22621
23246
 
@@ -22631,15 +23256,16 @@ function parentRoute(route) {
22631
23256
  }
22632
23257
  }
22633
23258
 
22634
- function parentTemplate(route) {
23259
+ function parentTemplate(route, isRecursive) {
22635
23260
  var parent = parentRoute(route), template;
22636
23261
 
22637
23262
  if (!parent) { return; }
22638
23263
 
23264
+
22639
23265
  if (template = parent.lastRenderedTemplate) {
22640
23266
  return template;
22641
23267
  } else {
22642
- return parentTemplate(parent);
23268
+ return parentTemplate(parent, true);
22643
23269
  }
22644
23270
  }
22645
23271
 
@@ -22650,6 +23276,7 @@ function normalizeOptions(route, name, template, options) {
22650
23276
  options.name = name;
22651
23277
  options.template = template;
22652
23278
 
23279
+
22653
23280
  var controller = options.controller, namedController;
22654
23281
 
22655
23282
  if (options.controller) {
@@ -22676,6 +23303,8 @@ function setupView(view, container, options) {
22676
23303
 
22677
23304
  if (!get(view, 'templateName')) {
22678
23305
  set(view, 'template', options.template);
23306
+
23307
+ set(view, '_debugTemplateName', options.name);
22679
23308
  }
22680
23309
 
22681
23310
  set(view, 'renderedName', options.name);
@@ -22698,7 +23327,7 @@ function appendView(route, view, options) {
22698
23327
  }
22699
23328
 
22700
23329
  function teardownTopLevel(view) {
22701
- return function() { view.remove(); };
23330
+ return function() { view.destroy(); };
22702
23331
  }
22703
23332
 
22704
23333
  function teardownOutlet(parentView, outlet) {
@@ -22723,10 +23352,15 @@ function teardownView(route) {
22723
23352
 
22724
23353
 
22725
23354
  (function() {
23355
+ /**
23356
+ @module ember
23357
+ @submodule ember-routing
23358
+ */
23359
+
22726
23360
  var get = Ember.get, set = Ember.set;
22727
23361
  Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22728
23362
 
22729
- var resolvePaths = Ember.Handlebars.resolvePaths,
23363
+ var resolveParams = Ember.Handlebars.resolveParams,
22730
23364
  isSimpleClick = Ember.ViewUtils.isSimpleClick;
22731
23365
 
22732
23366
  function fullRouteName(router, name) {
@@ -22737,8 +23371,11 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22737
23371
  return name;
22738
23372
  }
22739
23373
 
22740
- function resolvedPaths(linkView) {
22741
- return resolvePaths(linkView.parameters);
23374
+ function resolvedPaths(options) {
23375
+ var types = options.options.types.slice(1),
23376
+ data = options.options.data;
23377
+
23378
+ return resolveParams(options.context, options.params, { types: types, data: data });
22742
23379
  }
22743
23380
 
22744
23381
  function args(linkView, router, route) {
@@ -22748,7 +23385,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22748
23385
 
22749
23386
 
22750
23387
  var ret = [ routeName ];
22751
- return ret.concat(resolvePaths(linkView.parameters));
23388
+ return ret.concat(resolvedPaths(linkView.parameters));
22752
23389
  }
22753
23390
 
22754
23391
  var LinkView = Ember.View.extend({
@@ -22761,9 +23398,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22761
23398
  attributeBindings: ['href', 'title'],
22762
23399
  classNameBindings: 'active',
22763
23400
 
23401
+ // Even though this isn't a virtual view, we want to treat it as if it is
23402
+ // so that you can access the parent with {{view.prop}}
23403
+ concreteView: Ember.computed(function() {
23404
+ return get(this, 'parentView');
23405
+ }).property('parentView').volatile(),
23406
+
22764
23407
  active: Ember.computed(function() {
22765
23408
  var router = this.get('router'),
22766
- params = resolvedPaths(this),
23409
+ params = resolvedPaths(this.parameters),
22767
23410
  currentWithIndex = this.currentWhen + '.index',
22768
23411
  isActive = router.isActive.apply(router, [this.currentWhen].concat(params)) ||
22769
23412
  router.isActive.apply(router, [currentWithIndex].concat(params));
@@ -22798,9 +23441,16 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22798
23441
 
22799
23442
  LinkView.toString = function() { return "LinkView"; };
22800
23443
 
23444
+ /**
23445
+ @method linkTo
23446
+ @for Ember.Handlebars.helpers
23447
+ @param {String} routeName
23448
+ @param {Object} [context]*
23449
+ @return {String} HTML string
23450
+ */
22801
23451
  Ember.Handlebars.registerHelper('linkTo', function(name) {
22802
23452
  var options = [].slice.call(arguments, -1)[0];
22803
- var contexts = [].slice.call(arguments, 1, -1);
23453
+ var params = [].slice.call(arguments, 1, -1);
22804
23454
 
22805
23455
  var hash = options.hash;
22806
23456
 
@@ -22808,9 +23458,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22808
23458
  hash.currentWhen = hash.currentWhen || name;
22809
23459
 
22810
23460
  hash.parameters = {
22811
- data: options.data,
22812
- contexts: contexts,
22813
- roots: options.contexts
23461
+ context: this,
23462
+ options: options,
23463
+ params: params
22814
23464
  };
22815
23465
 
22816
23466
  return Ember.Handlebars.helpers.view.call(this, LinkView, options);
@@ -22894,45 +23544,6 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22894
23544
 
22895
23545
  return Handlebars.helpers.view.call(this, Handlebars.OutletView, options);
22896
23546
  });
22897
-
22898
- Ember.View.reopen({
22899
- init: function() {
22900
- set(this, '_outlets', {});
22901
- this._super();
22902
- },
22903
-
22904
- connectOutlet: function(outletName, view) {
22905
- var outlets = get(this, '_outlets'),
22906
- container = get(this, 'container'),
22907
- router = container && container.lookup('router:main'),
22908
- oldView = get(outlets, outletName),
22909
- renderedName = get(view, 'renderedName');
22910
-
22911
- set(outlets, outletName, view);
22912
-
22913
- if (router) {
22914
- if (oldView) {
22915
- router._disconnectActiveView(oldView);
22916
- }
22917
- if (renderedName) {
22918
- router._connectActiveView(renderedName, view);
22919
- }
22920
- }
22921
- },
22922
-
22923
- disconnectOutlet: function(outletName) {
22924
- var outlets = get(this, '_outlets'),
22925
- container = get(this, 'container'),
22926
- router = container && container.lookup('router:main'),
22927
- view = get(outlets, outletName);
22928
-
22929
- set(outlets, outletName, null);
22930
-
22931
- if (router && view) {
22932
- router._disconnectActiveView(view);
22933
- }
22934
- }
22935
- });
22936
23547
  });
22937
23548
 
22938
23549
  })();
@@ -22948,17 +23559,34 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22948
23559
  var get = Ember.get, set = Ember.set;
22949
23560
  Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22950
23561
 
22951
- Ember.Handlebars.registerHelper('render', function(name, context, options) {
23562
+ /**
23563
+ Renders the named template in the current context using the singleton
23564
+ instance of the same-named controller.
23565
+
23566
+ If a view class with the same name exists, uses the view class.
23567
+
23568
+ If a `model` is specified, it becomes the model for that controller.
22952
23569
 
22953
- var container, router, controller, view;
23570
+ The default target for `{{action}}`s in the rendered template is the
23571
+ named controller.
23572
+
23573
+ @method action
23574
+ @for Ember.Handlebars.helpers
23575
+ @param {String} actionName
23576
+ @param {Object?} model
23577
+ @param {Hash} options
23578
+ */
23579
+ Ember.Handlebars.registerHelper('render', function(name, contextString, options) {
23580
+
23581
+ var container, router, controller, view, context;
22954
23582
 
22955
23583
  if (arguments.length === 2) {
22956
- options = context;
22957
- context = undefined;
23584
+ options = contextString;
23585
+ contextString = undefined;
22958
23586
  }
22959
23587
 
22960
- if (typeof context === 'string') {
22961
- context = Ember.Handlebars.get(options.contexts[1], context, options);
23588
+ if (typeof contextString === 'string') {
23589
+ context = Ember.Handlebars.get(options.contexts[1], contextString, options);
22962
23590
  }
22963
23591
 
22964
23592
  name = name.replace(/\//g, '.');
@@ -22978,6 +23606,14 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
22978
23606
  controller.set('model', context);
22979
23607
  }
22980
23608
 
23609
+ var root = options.contexts[1];
23610
+
23611
+ if (root) {
23612
+ view.registerObserver(root, contextString, function() {
23613
+ controller.set('model', Ember.Handlebars.get(root, contextString, options));
23614
+ });
23615
+ }
23616
+
22981
23617
  controller.set('target', options.data.keywords.controller);
22982
23618
 
22983
23619
  options.hash.viewName = Ember.String.camelize(name);
@@ -23004,7 +23640,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23004
23640
  */
23005
23641
  Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23006
23642
 
23007
- var resolvePaths = Ember.Handlebars.resolvePaths,
23643
+ var resolveParams = Ember.Handlebars.resolveParams,
23008
23644
  isSimpleClick = Ember.ViewUtils.isSimpleClick;
23009
23645
 
23010
23646
  var EmberHandlebars = Ember.Handlebars,
@@ -23016,7 +23652,11 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23016
23652
  function args(options, actionName) {
23017
23653
  var ret = [];
23018
23654
  if (actionName) { ret.push(actionName); }
23019
- return ret.concat(resolvePaths(options.parameters));
23655
+
23656
+ var types = options.options.types.slice(1),
23657
+ data = options.options.data;
23658
+
23659
+ return ret.concat(resolveParams(options.context, options.params, { types: types, data: data }));
23020
23660
  }
23021
23661
 
23022
23662
  var ActionHelper = EmberHandlebars.ActionHelper = {
@@ -23040,12 +23680,20 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23040
23680
  contexts = options.contexts,
23041
23681
  target = options.target;
23042
23682
 
23043
- if (target.send) {
23044
- return target.send.apply(target, args(options, actionName));
23683
+ if (target.target) {
23684
+ target = handlebarsGet(target.root, target.target, target.options);
23045
23685
  } else {
23046
-
23047
- return target[actionName].apply(target, args(options));
23686
+ target = target.root;
23048
23687
  }
23688
+
23689
+ Ember.run(function() {
23690
+ if (target.send) {
23691
+ target.send.apply(target, args(options.parameters, actionName));
23692
+ } else {
23693
+
23694
+ target[actionName].apply(target, args(options.parameters));
23695
+ }
23696
+ });
23049
23697
  }
23050
23698
  };
23051
23699
 
@@ -23225,7 +23873,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23225
23873
  @method action
23226
23874
  @for Ember.Handlebars.helpers
23227
23875
  @param {String} actionName
23228
- @param {Object...} contexts
23876
+ @param {Object} [context]*
23229
23877
  @param {Hash} options
23230
23878
  */
23231
23879
  EmberHandlebars.registerHelper('action', function(actionName) {
@@ -23234,7 +23882,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23234
23882
 
23235
23883
  var hash = options.hash,
23236
23884
  view = options.data.view,
23237
- target, controller, link;
23885
+ controller, link;
23238
23886
 
23239
23887
  // create a hash to pass along to registerAction
23240
23888
  var action = {
@@ -23242,20 +23890,23 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23242
23890
  };
23243
23891
 
23244
23892
  action.parameters = {
23245
- data: options.data,
23246
- contexts: contexts,
23247
- roots: options.contexts
23893
+ context: this,
23894
+ options: options,
23895
+ params: contexts
23248
23896
  };
23249
23897
 
23250
23898
  action.view = view = get(view, 'concreteView');
23251
23899
 
23900
+ var root, target;
23901
+
23252
23902
  if (hash.target) {
23253
- target = handlebarsGet(this, hash.target, options);
23903
+ root = this;
23904
+ target = hash.target;
23254
23905
  } else if (controller = options.data.keywords.controller) {
23255
- target = controller;
23906
+ root = controller;
23256
23907
  }
23257
23908
 
23258
- action.target = target;
23909
+ action.target = { root: root, target: target, options: options };
23259
23910
  action.bubbles = hash.bubbles;
23260
23911
 
23261
23912
  var actionId = ActionHelper.registerAction(actionName, action);
@@ -23268,108 +23919,124 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
23268
23919
 
23269
23920
 
23270
23921
 
23271
- (function() {
23272
-
23273
- })();
23274
-
23275
-
23276
-
23277
23922
  (function() {
23278
23923
  /**
23279
23924
  @module ember
23280
23925
  @submodule ember-routing
23281
23926
  */
23282
23927
 
23283
- var get = Ember.get, set = Ember.set;
23284
- var ControllersProxy = Ember.Object.extend({
23285
- controller: null,
23928
+ if (Ember.ENV.EXPERIMENTAL_CONTROL_HELPER) {
23929
+ var get = Ember.get, set = Ember.set;
23286
23930
 
23287
- unknownProperty: function(controllerName) {
23288
- var controller = get(this, 'controller'),
23289
- needs = get(controller, 'needs'),
23290
- dependency;
23931
+ /**
23932
+ The control helper is currently under development and is considered experimental.
23933
+ To enable it, set `ENV.EXPERIMENTAL_CONTROL_HELPER = true` before requiring Ember.
23291
23934
 
23292
- for (var i=0, l=needs.length; i<l; i++) {
23293
- dependency = needs[i];
23294
- if (dependency === controllerName) {
23295
- return controller.controllerFor(controllerName);
23296
- }
23935
+ @method control
23936
+ @for Ember.Handlebars.helpers
23937
+ @param {String} path
23938
+ @param {String} modelPath
23939
+ @param {Hash} options
23940
+ @return {String} HTML string
23941
+ */
23942
+ Ember.Handlebars.registerHelper('control', function(path, modelPath, options) {
23943
+ if (arguments.length === 2) {
23944
+ options = modelPath;
23945
+ modelPath = undefined;
23297
23946
  }
23298
- }
23299
- });
23300
23947
 
23301
- Ember.ControllerMixin.reopen({
23302
- concatenatedProperties: ['needs'],
23303
- needs: [],
23948
+ var model;
23304
23949
 
23305
- init: function() {
23306
- this._super.apply(this, arguments);
23950
+ if (modelPath) {
23951
+ model = Ember.Handlebars.get(this, modelPath, options);
23952
+ }
23307
23953
 
23308
- // Structure asserts to still do verification but not string concat in production
23309
- if(!verifyDependencies(this)) {
23954
+ var controller = options.data.keywords.controller,
23955
+ view = options.data.keywords.view,
23956
+ children = get(controller, '_childContainers'),
23957
+ controlID = options.hash.controlID,
23958
+ container, subContainer;
23310
23959
 
23960
+ if (children.hasOwnProperty(controlID)) {
23961
+ subContainer = children[controlID];
23962
+ } else {
23963
+ container = get(controller, 'container'),
23964
+ subContainer = container.child();
23965
+ children[controlID] = subContainer;
23311
23966
  }
23312
- },
23313
23967
 
23314
- transitionToRoute: function() {
23315
- var target = get(this, 'target');
23968
+ var normalizedPath = path.replace(/\//g, '.');
23316
23969
 
23317
- return target.transitionTo.apply(target, arguments);
23318
- },
23970
+ var childView = subContainer.lookup('view:' + normalizedPath) || subContainer.lookup('view:default'),
23971
+ childController = subContainer.lookup('controller:' + normalizedPath),
23972
+ childTemplate = subContainer.lookup('template:' + path);
23319
23973
 
23320
- // TODO: Deprecate this, see https://github.com/emberjs/ember.js/issues/1785
23321
- transitionTo: function() {
23322
- return this.transitionToRoute.apply(this, arguments);
23323
- },
23324
23974
 
23325
- replaceRoute: function() {
23326
- var target = get(this, 'target');
23327
23975
 
23328
- return target.replaceWith.apply(target, arguments);
23329
- },
23330
-
23331
- // TODO: Deprecate this, see https://github.com/emberjs/ember.js/issues/1785
23332
- replaceWith: function() {
23333
- return this.replaceRoute.apply(this, arguments);
23334
- },
23976
+ set(childController, 'target', controller);
23977
+ set(childController, 'model', model);
23335
23978
 
23336
- controllerFor: function(controllerName) {
23337
- var container = get(this, 'container');
23338
- return container.lookup('controller:' + controllerName);
23339
- },
23979
+ options.hash.template = childTemplate;
23980
+ options.hash.controller = childController;
23340
23981
 
23341
- model: Ember.computed(function(key, value) {
23342
- if (arguments.length > 1) {
23343
- return set(this, 'content', value);
23344
- } else {
23345
- return get(this, 'content');
23982
+ function observer() {
23983
+ var model = Ember.Handlebars.get(this, modelPath, options);
23984
+ set(childController, 'model', model);
23985
+ childView.rerender();
23346
23986
  }
23347
- }).property('content'),
23348
23987
 
23349
- controllers: Ember.computed(function() {
23350
- return ControllersProxy.create({ controller: this });
23351
- })
23352
- });
23988
+ Ember.addObserver(this, modelPath, observer);
23989
+ childView.one('willDestroyElement', this, function() {
23990
+ Ember.removeObserver(this, modelPath, observer);
23991
+ });
23353
23992
 
23354
- function verifyDependencies(controller) {
23355
- var needs = get(controller, 'needs'),
23356
- container = get(controller, 'container'),
23357
- dependency, satisfied = true;
23993
+ Ember.Handlebars.helpers.view.call(this, childView, options);
23994
+ });
23995
+ }
23358
23996
 
23359
- for (var i=0, l=needs.length; i<l; i++) {
23360
- dependency = needs[i];
23361
- if (dependency.indexOf(':') === -1) {
23362
- dependency = "controller:" + dependency;
23363
- }
23997
+ })();
23364
23998
 
23365
- if (!container.has(dependency)) {
23366
- satisfied = false;
23367
23999
 
23368
- }
23369
- }
23370
24000
 
23371
- return satisfied;
23372
- }
24001
+ (function() {
24002
+
24003
+ })();
24004
+
24005
+
24006
+
24007
+ (function() {
24008
+ /**
24009
+ @module ember
24010
+ @submodule ember-routing
24011
+ */
24012
+
24013
+ var get = Ember.get, set = Ember.set;
24014
+
24015
+ Ember.ControllerMixin.reopen({
24016
+ transitionToRoute: function() {
24017
+ // target may be either another controller or a router
24018
+ var target = get(this, 'target'),
24019
+ method = target.transitionToRoute || target.transitionTo;
24020
+ return method.apply(target, arguments);
24021
+ },
24022
+
24023
+ transitionTo: function() {
24024
+
24025
+ return this.transitionToRoute.apply(this, arguments);
24026
+ },
24027
+
24028
+ replaceRoute: function() {
24029
+ // target may be either another controller or a router
24030
+ var target = get(this, 'target'),
24031
+ method = target.replaceRoute || target.replaceWith;
24032
+ return method.apply(target, arguments);
24033
+ },
24034
+
24035
+ replaceWith: function() {
24036
+
24037
+ return this.replaceRoute.apply(this, arguments);
24038
+ }
24039
+ });
23373
24040
 
23374
24041
  })();
23375
24042
 
@@ -23506,7 +24173,12 @@ Ember.NoneLocation = Ember.Object.extend({
23506
24173
  },
23507
24174
 
23508
24175
  onUpdateURL: function(callback) {
23509
- // We are not wired up to the browser, so we'll never trigger the callback.
24176
+ this.updateCallback = callback;
24177
+ },
24178
+
24179
+ handleURL: function(url) {
24180
+ set(this, 'path', url);
24181
+ this.updateCallback(url);
23510
24182
  },
23511
24183
 
23512
24184
  formatURL: function(url) {
@@ -23587,12 +24259,14 @@ Ember.HashLocation = Ember.Object.extend({
23587
24259
  var guid = Ember.guidFor(this);
23588
24260
 
23589
24261
  Ember.$(window).bind('hashchange.ember-location-'+guid, function() {
23590
- var path = location.hash.substr(1);
23591
- if (get(self, 'lastSetURL') === path) { return; }
24262
+ Ember.run(function() {
24263
+ var path = location.hash.substr(1);
24264
+ if (get(self, 'lastSetURL') === path) { return; }
23592
24265
 
23593
- set(self, 'lastSetURL', null);
24266
+ set(self, 'lastSetURL', null);
23594
24267
 
23595
- callback(location.hash.substr(1));
24268
+ callback(location.hash.substr(1));
24269
+ });
23596
24270
  });
23597
24271
  },
23598
24272
 
@@ -23657,7 +24331,7 @@ Ember.HistoryLocation = Ember.Object.extend({
23657
24331
  @method initState
23658
24332
  */
23659
24333
  initState: function() {
23660
- this.replaceState(get(this, 'location').pathname);
24334
+ this.replaceState(this.formatURL(this.getURL()));
23661
24335
  set(this, 'history', window.history);
23662
24336
  },
23663
24337
 
@@ -23672,12 +24346,18 @@ Ember.HistoryLocation = Ember.Object.extend({
23672
24346
  /**
23673
24347
  @private
23674
24348
 
23675
- Returns the current `location.pathname`.
24349
+ Returns the current `location.pathname` without rootURL
23676
24350
 
23677
24351
  @method getURL
23678
24352
  */
23679
24353
  getURL: function() {
23680
- return get(this, 'location').pathname;
24354
+ var rootURL = get(this, 'rootURL'),
24355
+ url = get(this, 'location').pathname;
24356
+
24357
+ rootURL = rootURL.replace(/\/$/, '');
24358
+ url = url.replace(rootURL, '');
24359
+
24360
+ return url;
23681
24361
  },
23682
24362
 
23683
24363
  /**
@@ -23760,13 +24440,14 @@ Ember.HistoryLocation = Ember.Object.extend({
23760
24440
  @param callback {Function}
23761
24441
  */
23762
24442
  onUpdateURL: function(callback) {
23763
- var guid = Ember.guidFor(this);
24443
+ var guid = Ember.guidFor(this),
24444
+ self = this;
23764
24445
 
23765
24446
  Ember.$(window).bind('popstate.ember-location-'+guid, function(e) {
23766
24447
  if(!popstateReady) {
23767
24448
  return;
23768
24449
  }
23769
- callback(location.pathname);
24450
+ callback(self.getURL());
23770
24451
  });
23771
24452
  },
23772
24453
 
@@ -24028,68 +24709,32 @@ var get = Ember.get, set = Ember.set,
24028
24709
  layer, and a list of the event listeners that are setup by default, visit the
24029
24710
  [Ember View Layer guide](http://emberjs.com/guides/view_layer#toc_event-delegation).
24030
24711
 
24031
- ### Dependency Injection
24712
+ ### Initializers
24032
24713
 
24033
- One thing you may have noticed while using Ember is that you define
24034
- *classes*, not *instances*. When your application loads, all of the instances
24035
- are created for you. Creating these instances is the responsibility of
24036
- `Ember.Application`.
24037
-
24038
- When the `Ember.Application` initializes, it will look for an `Ember.Router`
24039
- class defined on the applications's `Router` property, like this:
24714
+ Libraries on top of Ember can register additional initializers, like so:
24040
24715
 
24041
24716
  ```javascript
24042
- App.Router = Ember.Router.extend({
24043
- // ...
24044
- });
24045
- ```
24046
-
24047
- If found, the router is instantiated and saved on the application's `router`
24048
- property (note the lowercase 'r'). While you should *not* reference this
24049
- router instance directly from your application code, having access to
24050
- `App.router` from the console can be useful during debugging.
24051
-
24052
- After the router is created, the application loops through all of the
24053
- registered _injections_ and invokes them once for each property on the
24054
- `Ember.Application` object.
24055
-
24056
- An injection is a function that is responsible for instantiating objects from
24057
- classes defined on the application. By default, the only injection registered
24058
- instantiates controllers and makes them available on the router.
24717
+ Ember.Application.initializer({
24718
+ name: "store",
24059
24719
 
24060
- For example, if you define a controller class:
24061
-
24062
- ```javascript
24063
- App.MyController = Ember.Controller.extend({
24064
- // ...
24720
+ initialize: function(container, application) {
24721
+ container.register('store', 'main', application.Store);
24722
+ }
24065
24723
  });
24066
24724
  ```
24067
24725
 
24068
- Your router will receive an instance of `App.MyController` saved on its
24069
- `myController` property.
24726
+ ### Routing
24070
24727
 
24071
- Libraries on top of Ember can register additional injections. For example,
24072
- if your application is using Ember Data, it registers an injection that
24073
- instantiates `DS.Store`:
24728
+ In addition to creating your application's router, `Ember.Application` is
24729
+ also responsible for telling the router when to start routing. Transitions
24730
+ between routes can be logged with the LOG_TRANSITIONS flag:
24074
24731
 
24075
24732
  ```javascript
24076
- Ember.Application.registerInjection({
24077
- name: 'store',
24078
- before: 'controllers',
24079
-
24080
- injection: function(app, router, property) {
24081
- if (property === 'Store') {
24082
- set(router, 'store', app[property].create());
24083
- }
24084
- }
24733
+ window.App = Ember.Application.create({
24734
+ LOG_TRANSITIONS: true
24085
24735
  });
24086
24736
  ```
24087
24737
 
24088
- ### Routing
24089
-
24090
- In addition to creating your application's router, `Ember.Application` is
24091
- also responsible for telling the router when to start routing.
24092
-
24093
24738
  By default, the router will begin trying to translate the current URL into
24094
24739
  application state once the browser emits the `DOMContentReady` event. If you
24095
24740
  need to defer routing, you can call the application's `deferReadiness()`
@@ -24097,14 +24742,7 @@ var get = Ember.get, set = Ember.set,
24097
24742
 
24098
24743
  If there is any setup required before routing begins, you can implement a
24099
24744
  `ready()` method on your app that will be invoked immediately before routing
24100
- begins:
24101
-
24102
- ```javascript
24103
- window.App = Ember.Application.create({
24104
- ready: function() {
24105
- this.set('router.enableLogging', true);
24106
- }
24107
- });
24745
+ begins.
24108
24746
 
24109
24747
  To begin routing, you must have at a minimum a top-level controller and view.
24110
24748
  You define these as `App.ApplicationController` and `App.ApplicationView`,
@@ -24122,8 +24760,7 @@ var get = Ember.get, set = Ember.set,
24122
24760
  @namespace Ember
24123
24761
  @extends Ember.Namespace
24124
24762
  */
24125
- var Application = Ember.Application = Ember.Namespace.extend(
24126
- /** @scope Ember.Application.prototype */{
24763
+ var Application = Ember.Application = Ember.Namespace.extend({
24127
24764
 
24128
24765
  /**
24129
24766
  The root DOM element of the Application. This can be specified as an
@@ -24202,6 +24839,11 @@ var Application = Ember.Application = Ember.Namespace.extend(
24202
24839
 
24203
24840
  this.deferUntilDOMReady();
24204
24841
  this.scheduleInitialize();
24842
+
24843
+
24844
+
24845
+
24846
+
24205
24847
  },
24206
24848
 
24207
24849
  /**
@@ -24333,9 +24975,52 @@ var Application = Ember.Application = Ember.Namespace.extend(
24333
24975
  }
24334
24976
  },
24335
24977
 
24978
+ /**
24979
+ registers a factory for later injection
24980
+
24981
+ Example:
24982
+
24983
+ ```javascript
24984
+ App = Ember.Application.create();
24985
+
24986
+ App.Person = Ember.Object.extend({});
24987
+ App.Orange = Ember.Object.extend({});
24988
+ App.Email = Ember.Object.extend({});
24989
+
24990
+ App.register('model:user', App.Person, {singleton: false });
24991
+ App.register('fruit:favorite', App.Orange);
24992
+ App.register('communication:main', App.Email, {singleton: false});
24993
+ ```
24994
+
24995
+ @method register
24996
+ @param type {String}
24997
+ @param name {String}
24998
+ @param factory {String}
24999
+ @param options {String} (optional)
25000
+ **/
24336
25001
  register: function() {
24337
25002
  var container = this.__container__;
24338
- return container.register.apply(container, arguments);
25003
+ container.register.apply(container, arguments);
25004
+ },
25005
+ /**
25006
+ defines an injection or typeInjection
25007
+
25008
+ Example:
25009
+
25010
+ ```javascript
25011
+ App.inject(<full_name or type>, <property name>, <full_name>)
25012
+ App.inject('model:user', 'email', 'model:email')
25013
+ App.inject('model', 'source', 'source:main')
25014
+ ```
25015
+
25016
+ @method inject
25017
+ @param factoryNameOrType {String}
25018
+ @param property {String}
25019
+ @param injectionName {String}
25020
+ **/
25021
+ inject: function(){
25022
+ var container = this.__container__;
25023
+ container.injection.apply(container, arguments);
24339
25024
  },
24340
25025
 
24341
25026
  /**
@@ -24343,7 +25028,7 @@ var Application = Ember.Application = Ember.Namespace.extend(
24343
25028
 
24344
25029
  Initialize the application. This happens automatically.
24345
25030
 
24346
- Run any injections and run the application load hook. These hooks may
25031
+ Run any initializers and run the application load hook. These hooks may
24347
25032
  choose to defer readiness. For example, an authentication hook might want
24348
25033
  to defer readiness until the auth token has been retrieved.
24349
25034
 
@@ -24357,13 +25042,10 @@ var Application = Ember.Application = Ember.Namespace.extend(
24357
25042
  // At this point, the App.Router must already be assigned
24358
25043
  this.__container__.register('router', 'main', this.Router);
24359
25044
 
24360
- // Run any injections and run the application load hook. These hooks may
24361
- // choose to defer readiness. For example, an authentication hook might want
24362
- // to defer readiness until the auth token has been retrieved.
24363
25045
  this.runInitializers();
24364
25046
  Ember.runLoadHooks('application', this);
24365
25047
 
24366
- // At this point, any injections or load hooks that would have wanted
25048
+ // At this point, any initializers or load hooks that would have wanted
24367
25049
  // to defer readiness have fired. In general, advancing readiness here
24368
25050
  // will proceed to didBecomeReady.
24369
25051
  this.advanceReadiness();
@@ -24371,6 +25053,15 @@ var Application = Ember.Application = Ember.Namespace.extend(
24371
25053
  return this;
24372
25054
  },
24373
25055
 
25056
+ reset: function() {
25057
+ get(this, '__container__').destroy();
25058
+ this.buildContainer();
25059
+
25060
+ this.isInitialized = false;
25061
+ this.initialize();
25062
+ this.startRouting();
25063
+ },
25064
+
24374
25065
  /**
24375
25066
  @private
24376
25067
  @method runInitializers
@@ -24458,6 +25149,12 @@ var Application = Ember.Application = Ember.Namespace.extend(
24458
25149
  router.startRouting();
24459
25150
  },
24460
25151
 
25152
+ handleURL: function(url) {
25153
+ var router = this.__container__.lookup('router:main');
25154
+
25155
+ router.handleURL(url);
25156
+ },
25157
+
24461
25158
  /**
24462
25159
  Called when the Application has become ready.
24463
25160
  The call will be delayed until the DOM has become ready.
@@ -24472,7 +25169,7 @@ var Application = Ember.Application = Ember.Namespace.extend(
24472
25169
  var eventDispatcher = get(this, 'eventDispatcher');
24473
25170
  if (eventDispatcher) { eventDispatcher.destroy(); }
24474
25171
 
24475
- this.__container__.destroy();
25172
+ get(this, '__container__').destroy();
24476
25173
  },
24477
25174
 
24478
25175
  initializer: function(options) {
@@ -24520,7 +25217,7 @@ Ember.Application.reopenClass({
24520
25217
  */
24521
25218
  buildContainer: function(namespace) {
24522
25219
  var container = new Ember.Container();
24523
- Ember.Container.defaultContainer = container;
25220
+ Ember.Container.defaultContainer = Ember.Container.defaultContainer || container;
24524
25221
 
24525
25222
  container.set = Ember.set;
24526
25223
  container.resolver = resolverFor(namespace);
@@ -24595,6 +25292,85 @@ Ember.runLoadHooks('Ember.Application', Ember.Application);
24595
25292
 
24596
25293
 
24597
25294
 
25295
+ (function() {
25296
+ /**
25297
+ @module ember
25298
+ @submodule ember-routing
25299
+ */
25300
+
25301
+ var get = Ember.get, set = Ember.set;
25302
+ var ControllersProxy = Ember.Object.extend({
25303
+ controller: null,
25304
+
25305
+ unknownProperty: function(controllerName) {
25306
+ var controller = get(this, 'controller'),
25307
+ needs = get(controller, 'needs'),
25308
+ container = controller.get('container'),
25309
+ dependency;
25310
+
25311
+ for (var i=0, l=needs.length; i<l; i++) {
25312
+ dependency = needs[i];
25313
+ if (dependency === controllerName) {
25314
+ return container.lookup('controller:' + controllerName);
25315
+ }
25316
+ }
25317
+ }
25318
+ });
25319
+
25320
+ function verifyDependencies(controller) {
25321
+ var needs = get(controller, 'needs'),
25322
+ container = get(controller, 'container'),
25323
+ dependency, satisfied = true;
25324
+
25325
+ for (var i=0, l=needs.length; i<l; i++) {
25326
+ dependency = needs[i];
25327
+ if (dependency.indexOf(':') === -1) {
25328
+ dependency = "controller:" + dependency;
25329
+ }
25330
+
25331
+ if (!container.has(dependency)) {
25332
+ satisfied = false;
25333
+
25334
+ }
25335
+ }
25336
+
25337
+ return satisfied;
25338
+ }
25339
+
25340
+ Ember.ControllerMixin.reopen({
25341
+ concatenatedProperties: ['needs'],
25342
+ needs: [],
25343
+
25344
+ init: function() {
25345
+ this._super.apply(this, arguments);
25346
+
25347
+ // Structure asserts to still do verification but not string concat in production
25348
+ if(!verifyDependencies(this)) {
25349
+
25350
+ }
25351
+ },
25352
+
25353
+ controllerFor: function(controllerName) {
25354
+
25355
+ var container = get(this, 'container');
25356
+ return container.lookup('controller:' + controllerName);
25357
+ },
25358
+
25359
+ controllers: Ember.computed(function() {
25360
+ return ControllersProxy.create({ controller: this });
25361
+ })
25362
+ });
25363
+
25364
+ })();
25365
+
25366
+
25367
+
25368
+ (function() {
25369
+
25370
+ })();
25371
+
25372
+
25373
+
24598
25374
  (function() {
24599
25375
  /**
24600
25376
  Ember Application
@@ -25563,9 +26339,7 @@ Ember.StateManager = Ember.State.extend({
25563
26339
  @property currentPath
25564
26340
  @type String
25565
26341
  */
25566
- currentPath: Ember.computed('currentState', function() {
25567
- return get(this, 'currentState.path');
25568
- }),
26342
+ currentPath: Ember.computed.alias('currentState.path'),
25569
26343
 
25570
26344
  /**
25571
26345
  The name of transitionEvent that this stateManager will dispatch