pyro 0.9.0 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,284 @@
1
+ (function() {
2
+ var define, requireModule;
3
+
4
+ (function() {
5
+ var registry = {}, seen = {};
6
+
7
+ define = function(name, deps, callback) {
8
+ registry[name] = { deps: deps, callback: callback };
9
+ };
10
+
11
+ requireModule = function(name) {
12
+ if (seen[name]) { return seen[name]; }
13
+ seen[name] = {};
14
+
15
+ var mod, deps, callback, reified , exports;
16
+
17
+ mod = registry[name];
18
+
19
+ if (!mod) {
20
+ throw new Error("Module '" + name + "' not found.");
21
+ }
22
+
23
+ deps = mod.deps;
24
+ callback = mod.callback;
25
+ reified = [];
26
+ exports;
27
+
28
+ for (var i=0, l=deps.length; i<l; i++) {
29
+ if (deps[i] === 'exports') {
30
+ reified.push(exports = {});
31
+ } else {
32
+ reified.push(requireModule(deps[i]));
33
+ }
34
+ }
35
+
36
+ var value = callback.apply(this, reified);
37
+ return seen[name] = exports || value;
38
+ };
39
+ })();
40
+ (function() {
41
+ Ember.String.pluralize = function(word) {
42
+ return Ember.Inflector.inflector.pluralize(word);
43
+ };
44
+
45
+ Ember.String.singularize = function(word) {
46
+ return Ember.Inflector.inflector.singularize(word);
47
+ };
48
+
49
+ })();
50
+
51
+
52
+
53
+ (function() {
54
+ var BLANK_REGEX = /^\s*$/;
55
+
56
+ function loadUncountable(rules, uncountable) {
57
+ for (var i = 0, length = uncountable.length; i < length; i++) {
58
+ rules.uncountable[uncountable[i]] = true;
59
+ }
60
+ }
61
+
62
+ function loadIrregular(rules, irregularPairs) {
63
+ var pair;
64
+
65
+ for (var i = 0, length = irregularPairs.length; i < length; i++) {
66
+ pair = irregularPairs[i];
67
+
68
+ rules.irregular[pair[0]] = pair[1];
69
+ rules.irregularInverse[pair[1]] = pair[0];
70
+ }
71
+ }
72
+
73
+ function Inflector(ruleSet) {
74
+ ruleSet = ruleSet || {};
75
+ ruleSet.uncountable = ruleSet.uncountable || {};
76
+ ruleSet.irregularPairs= ruleSet.irregularPairs|| {};
77
+
78
+ var rules = this.rules = {
79
+ plurals: ruleSet.plurals || [],
80
+ singular: ruleSet.singular || [],
81
+ irregular: {},
82
+ irregularInverse: {},
83
+ uncountable: {}
84
+ };
85
+
86
+ loadUncountable(rules, ruleSet.uncountable);
87
+ loadIrregular(rules, ruleSet.irregularPairs);
88
+ }
89
+
90
+ Inflector.prototype = {
91
+ pluralize: function(word) {
92
+ return this.inflect(word, this.rules.plurals);
93
+ },
94
+
95
+ singularize: function(word) {
96
+ return this.inflect(word, this.rules.singular);
97
+ },
98
+
99
+ inflect: function(word, typeRules) {
100
+ var inflection, substitution, result, lowercase, isBlank,
101
+ isUncountable, isIrregular, isIrregularInverse, rule;
102
+
103
+ isBlank = BLANK_REGEX.test(word);
104
+
105
+ if (isBlank) {
106
+ return word;
107
+ }
108
+
109
+ lowercase = word.toLowerCase();
110
+
111
+ isUncountable = this.rules.uncountable[lowercase];
112
+
113
+ if (isUncountable) {
114
+ return word;
115
+ }
116
+
117
+ isIrregular = this.rules.irregular[lowercase];
118
+
119
+ if (isIrregular) {
120
+ return isIrregular;
121
+ }
122
+
123
+ isIrregularInverse = this.rules.irregularInverse[lowercase];
124
+
125
+ if (isIrregularInverse) {
126
+ return isIrregularInverse;
127
+ }
128
+
129
+ for (var i = typeRules.length, min = 0; i > min; i--) {
130
+ inflection = typeRules[i-1];
131
+ rule = inflection[0];
132
+
133
+ if (rule.test(word)) {
134
+ break;
135
+ }
136
+ }
137
+
138
+ inflection = inflection || [];
139
+
140
+ rule = inflection[0];
141
+ substitution = inflection[1];
142
+
143
+ result = word.replace(rule, substitution);
144
+
145
+ return result;
146
+ }
147
+ };
148
+
149
+ Ember.Inflector = Inflector;
150
+
151
+ })();
152
+
153
+
154
+
155
+ (function() {
156
+ Ember.Inflector.defaultRules = {
157
+ plurals: [
158
+ [/$/, 's'],
159
+ [/s$/i, 's'],
160
+ [/^(ax|test)is$/i, '$1es'],
161
+ [/(octop|vir)us$/i, '$1i'],
162
+ [/(octop|vir)i$/i, '$1i'],
163
+ [/(alias|status)$/i, '$1es'],
164
+ [/(bu)s$/i, '$1ses'],
165
+ [/(buffal|tomat)o$/i, '$1oes'],
166
+ [/([ti])um$/i, '$1a'],
167
+ [/([ti])a$/i, '$1a'],
168
+ [/sis$/i, 'ses'],
169
+ [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],
170
+ [/(hive)$/i, '$1s'],
171
+ [/([^aeiouy]|qu)y$/i, '$1ies'],
172
+ [/(x|ch|ss|sh)$/i, '$1es'],
173
+ [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'],
174
+ [/^(m|l)ouse$/i, '$1ice'],
175
+ [/^(m|l)ice$/i, '$1ice'],
176
+ [/^(ox)$/i, '$1en'],
177
+ [/^(oxen)$/i, '$1'],
178
+ [/(quiz)$/i, '$1zes']
179
+ ],
180
+
181
+ singular: [
182
+ [/s$/i, ''],
183
+ [/(ss)$/i, '$1'],
184
+ [/(n)ews$/i, '$1ews'],
185
+ [/([ti])a$/i, '$1um'],
186
+ [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'],
187
+ [/(^analy)(sis|ses)$/i, '$1sis'],
188
+ [/([^f])ves$/i, '$1fe'],
189
+ [/(hive)s$/i, '$1'],
190
+ [/(tive)s$/i, '$1'],
191
+ [/([lr])ves$/i, '$1f'],
192
+ [/([^aeiouy]|qu)ies$/i, '$1y'],
193
+ [/(s)eries$/i, '$1eries'],
194
+ [/(m)ovies$/i, '$1ovie'],
195
+ [/(x|ch|ss|sh)es$/i, '$1'],
196
+ [/^(m|l)ice$/i, '$1ouse'],
197
+ [/(bus)(es)?$/i, '$1'],
198
+ [/(o)es$/i, '$1'],
199
+ [/(shoe)s$/i, '$1'],
200
+ [/(cris|test)(is|es)$/i, '$1is'],
201
+ [/^(a)x[ie]s$/i, '$1xis'],
202
+ [/(octop|vir)(us|i)$/i, '$1us'],
203
+ [/(alias|status)(es)?$/i, '$1'],
204
+ [/^(ox)en/i, '$1'],
205
+ [/(vert|ind)ices$/i, '$1ex'],
206
+ [/(matr)ices$/i, '$1ix'],
207
+ [/(quiz)zes$/i, '$1'],
208
+ [/(database)s$/i, '$1']
209
+ ],
210
+
211
+ irregularPairs: [
212
+ ['person', 'people'],
213
+ ['man', 'men'],
214
+ ['child', 'children'],
215
+ ['sex', 'sexes'],
216
+ ['move', 'moves'],
217
+ ['cow', 'kine'],
218
+ ['zombie', 'zombies']
219
+ ],
220
+
221
+ uncountable: [
222
+ 'equipment',
223
+ 'information',
224
+ 'rice',
225
+ 'money',
226
+ 'species',
227
+ 'series',
228
+ 'fish',
229
+ 'sheep',
230
+ 'jeans',
231
+ 'police'
232
+ ]
233
+ };
234
+
235
+ })();
236
+
237
+
238
+
239
+ (function() {
240
+ if (Ember.EXTEND_PROTOTYPES) {
241
+ /**
242
+ See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
243
+
244
+ @method pluralize
245
+ @for String
246
+ */
247
+ String.prototype.pluralize = function() {
248
+ return Ember.String.pluralize(this);
249
+ };
250
+
251
+ /**
252
+ See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
253
+
254
+ @method singularize
255
+ @for String
256
+ */
257
+ String.prototype.singularize = function() {
258
+ return Ember.String.singularize(this);
259
+ };
260
+ }
261
+
262
+ })();
263
+
264
+
265
+
266
+ (function() {
267
+ Ember.Inflector.inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
268
+
269
+ })();
270
+
271
+
272
+
273
+ (function() {
274
+
275
+ })();
276
+
277
+
278
+ })();
279
+
280
+
281
+ if (typeof location !== 'undefined' && (location.hostname === 'localhost' || location.hostname === '127.0.0.1')) {
282
+ Ember.Logger.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. "+
283
+ "If you want full error messages please use the non-minified build provided on the Ember website.");
284
+ }
@@ -1,5 +1,5 @@
1
- // Version: v1.0.0-rc.7-205-ga347ce2
2
- // Last commit: a347ce2 (2013-08-28 22:01:01 -0700)
1
+ // Version: v1.0.0
2
+ // Last commit: e2ea0cf (2013-08-31 23:47:39 -0700)
3
3
 
4
4
 
5
5
  (function() {
@@ -156,10 +156,22 @@ Ember.deprecateFunc = function(message, func) {
156
156
  };
157
157
  };
158
158
 
159
+
160
+ // Inform the developer about the Ember Inspector if not installed.
161
+ if (!Ember.testing) {
162
+ if (typeof window !== 'undefined' && window.chrome && window.addEventListener) {
163
+ window.addEventListener("load", function() {
164
+ if (document.body && document.body.dataset && !document.body.dataset.emberExtension) {
165
+ Ember.debug('For more advanced debugging, install the Ember Inspector from https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi');
166
+ }
167
+ }, false);
168
+ }
169
+ }
170
+
159
171
  })();
160
172
 
161
- // Version: v1.0.0-rc.7-205-ga347ce2
162
- // Last commit: a347ce2 (2013-08-28 22:01:01 -0700)
173
+ // Version: v1.0.0
174
+ // Last commit: e2ea0cf (2013-08-31 23:47:39 -0700)
163
175
 
164
176
 
165
177
  (function() {
@@ -225,7 +237,7 @@ var define, requireModule;
225
237
 
226
238
  @class Ember
227
239
  @static
228
- @version 1.0.0-rc.8
240
+ @version 1.0.0
229
241
  */
230
242
 
231
243
  if ('undefined' === typeof Ember) {
@@ -252,10 +264,10 @@ Ember.toString = function() { return "Ember"; };
252
264
  /**
253
265
  @property VERSION
254
266
  @type String
255
- @default '1.0.0-rc.8'
267
+ @default '1.0.0'
256
268
  @final
257
269
  */
258
- Ember.VERSION = '1.0.0-rc.8';
270
+ Ember.VERSION = '1.0.0';
259
271
 
260
272
  /**
261
273
  Standard environmental variables. You can define these in a global `ENV`
@@ -4601,8 +4613,8 @@ function registerComputedWithProperties(name, macro) {
4601
4613
  property is null, an empty string, empty array, or empty function.
4602
4614
 
4603
4615
  Note: When using `Ember.computed.empty` to watch an array make sure to
4604
- use the `array.length` or `array.@each` syntax so the computed can
4605
- subscribe to transitions from empty to non-empty states.
4616
+ use the `array.length` syntax so the computed can subscribe to transitions
4617
+ from empty to non-empty states.
4606
4618
 
4607
4619
  Example
4608
4620
 
@@ -4610,9 +4622,9 @@ function registerComputedWithProperties(name, macro) {
4610
4622
  var ToDoList = Ember.Object.extend({
4611
4623
  done: Ember.computed.empty('todos.length')
4612
4624
  });
4613
- var todoList = ToDoList.create({todoList: ['Unit Test', 'Documentation', 'Release']});
4625
+ var todoList = ToDoList.create({todos: ['Unit Test', 'Documentation', 'Release']});
4614
4626
  todoList.get('done'); // false
4615
- todoList.get('todoList').clear(); // []
4627
+ todoList.get('todos').clear(); // []
4616
4628
  todoList.get('done'); // true
4617
4629
  ```
4618
4630
 
@@ -5714,7 +5726,7 @@ define("backburner",
5714
5726
  clearTimeout(debouncee[2]);
5715
5727
  }
5716
5728
 
5717
- var timer = window.setTimeout(function() {
5729
+ var timer = global.setTimeout(function() {
5718
5730
  if (!immediate) {
5719
5731
  self.run.apply(self, args);
5720
5732
  }
@@ -5783,8 +5795,8 @@ define("backburner",
5783
5795
  function createAutorun(backburner) {
5784
5796
  backburner.begin();
5785
5797
  autorun = global.setTimeout(function() {
5786
- backburner.end();
5787
5798
  autorun = null;
5799
+ backburner.end();
5788
5800
  });
5789
5801
  }
5790
5802
 
@@ -7225,19 +7237,19 @@ Ember.mixin = function(obj) {
7225
7237
  `Ember.Mixin.extend`.
7226
7238
 
7227
7239
  Note that mixins extend a constructor's prototype so arrays and object literals
7228
- defined as properties will be shared amongst objects that implement the mixin.
7240
+ defined as properties will be shared amongst objects that implement the mixin.
7229
7241
  If you want to define an property in a mixin that is not shared, you can define
7230
7242
  it either as a computed property or have it be created on initialization of the object.
7231
-
7243
+
7232
7244
  ```javascript
7233
7245
  //filters array will be shared amongst any object implementing mixin
7234
7246
  App.Filterable = Ember.Mixin.create({
7235
- filters: Ember.A()
7247
+ filters: Ember.A()
7236
7248
  });
7237
7249
 
7238
7250
  //filters will be a separate array for every object implementing the mixin
7239
7251
  App.Filterable = Ember.Mixin.create({
7240
- filters: Ember.computed(function(){return Ember.A();})
7252
+ filters: Ember.computed(function(){return Ember.A();})
7241
7253
  });
7242
7254
 
7243
7255
  //filters will be created as a separate array during the object's initialization
@@ -7484,6 +7496,22 @@ Ember.aliasMethod = function(methodName) {
7484
7496
  //
7485
7497
 
7486
7498
  /**
7499
+ Specify a method that observes property changes.
7500
+
7501
+ ```javascript
7502
+ Ember.Object.extend({
7503
+ valueObserver: Ember.observer(function() {
7504
+ // Executes whenever the "value" property changes
7505
+ }, 'value')
7506
+ });
7507
+ ```
7508
+
7509
+ In the future this method may become asynchronous. If you want to ensure
7510
+ synchronous behavior, use `immediateObserver`.
7511
+
7512
+ Also available as `Function.prototype.observes` if prototype extensions are
7513
+ enabled.
7514
+
7487
7515
  @method observer
7488
7516
  @for Ember
7489
7517
  @param {Function} func
@@ -7496,9 +7524,23 @@ Ember.observer = function(func) {
7496
7524
  return func;
7497
7525
  };
7498
7526
 
7499
- // If observers ever become asynchronous, Ember.immediateObserver
7500
- // must remain synchronous.
7501
7527
  /**
7528
+ Specify a method that observes property changes.
7529
+
7530
+ ```javascript
7531
+ Ember.Object.extend({
7532
+ valueObserver: Ember.immediateObserver(function() {
7533
+ // Executes whenever the "value" property changes
7534
+ }, 'value')
7535
+ });
7536
+ ```
7537
+
7538
+ In the future, `Ember.observer` may become asynchronous. In this event,
7539
+ `Ember.immediateObserver` will maintain the synchronous behavior.
7540
+
7541
+ Also available as `Function.prototype.observesImmediately` if prototype extensions are
7542
+ enabled.
7543
+
7502
7544
  @method immediateObserver
7503
7545
  @for Ember
7504
7546
  @param {Function} func
@@ -7526,24 +7568,31 @@ Ember.immediateObserver = function() {
7526
7568
 
7527
7569
  ```javascript
7528
7570
  App.PersonView = Ember.View.extend({
7571
+
7529
7572
  friends: [{ name: 'Tom' }, { name: 'Stefan' }, { name: 'Kris' }],
7530
- valueWillChange: function (obj, keyName) {
7573
+
7574
+ valueWillChange: Ember.beforeObserver(function(obj, keyName) {
7531
7575
  this.changingFrom = obj.get(keyName);
7532
- }.observesBefore('content.value'),
7533
- valueDidChange: function(obj, keyName) {
7576
+ }, 'content.value'),
7577
+
7578
+ valueDidChange: Ember.observer(function(obj, keyName) {
7534
7579
  // only run if updating a value already in the DOM
7535
7580
  if (this.get('state') === 'inDOM') {
7536
- var color = obj.get(keyName) > this.changingFrom ? 'green' : 'red';
7537
- // logic
7581
+ var color = obj.get(keyName) > this.changingFrom ? 'green' : 'red';
7582
+ // logic
7538
7583
  }
7539
- }.observes('content.value'),
7540
- friendsDidChange: function(obj, keyName) {
7584
+ }, 'content.value'),
7585
+
7586
+ friendsDidChange: Ember.observer(function(obj, keyName) {
7541
7587
  // some logic
7542
7588
  // obj.get(keyName) returns friends array
7543
- }.observes('friends.@each.name')
7589
+ }, 'friends.@each.name')
7544
7590
  });
7545
7591
  ```
7546
7592
 
7593
+ Also available as `Function.prototype.observesBefore` if prototype extensions are
7594
+ enabled.
7595
+
7547
7596
  @method beforeObserver
7548
7597
  @for Ember
7549
7598
  @param {Function} func
@@ -7627,6 +7676,7 @@ define("rsvp/async",
7627
7676
  var browserGlobal = (typeof window !== 'undefined') ? window : {};
7628
7677
  var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
7629
7678
  var async;
7679
+ var local = (typeof global !== 'undefined') ? global : this;
7630
7680
 
7631
7681
  // old node
7632
7682
  function useNextTick() {
@@ -7677,7 +7727,7 @@ define("rsvp/async",
7677
7727
 
7678
7728
  function useSetTimeout() {
7679
7729
  return function(callback, arg) {
7680
- global.setTimeout(function() {
7730
+ local.setTimeout(function() {
7681
7731
  callback(arg);
7682
7732
  }, 1);
7683
7733
  };
@@ -8216,6 +8266,13 @@ define("rsvp",
8216
8266
  })();
8217
8267
 
8218
8268
  (function() {
8269
+ /**
8270
+ Flag to enable/disable model factory injections (disabled by default)
8271
+ If model factory injections are enabled, models should not be
8272
+ accessed globally (only through `container.lookupFactory('model:modelName'))`);
8273
+ */
8274
+ Ember.MODEL_FACTORY_INJECTIONS = false || !!Ember.ENV.MODEL_FACTORY_INJECTIONS;
8275
+
8219
8276
  define("container",
8220
8277
  [],
8221
8278
  function() {
@@ -8494,6 +8551,7 @@ define("container",
8494
8551
 
8495
8552
  container.unregister('model:user')
8496
8553
  container.lookup('model:user') === undefined //=> true
8554
+ ```
8497
8555
 
8498
8556
  @method unregister
8499
8557
  @param {String} fullName
@@ -8577,7 +8635,7 @@ define("container",
8577
8635
  */
8578
8636
  makeToString: function(factory, fullName) {
8579
8637
  return factory.toString();
8580
- },
8638
+ },
8581
8639
 
8582
8640
  /**
8583
8641
  Given a fullName return a corresponding instance.
@@ -8985,6 +9043,7 @@ define("container",
8985
9043
  var factory = container.resolve(name);
8986
9044
  var injectedFactory;
8987
9045
  var cache = container.factoryCache;
9046
+ var type = fullName.split(":")[0];
8988
9047
 
8989
9048
  if (!factory) { return; }
8990
9049
 
@@ -8992,7 +9051,7 @@ define("container",
8992
9051
  return cache.get(fullName);
8993
9052
  }
8994
9053
 
8995
- if (typeof factory.extend !== 'function') {
9054
+ if (typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) {
8996
9055
  // TODO: think about a 'safe' merge style extension
8997
9056
  // for now just fallback to create time injection
8998
9057
  return factory;
@@ -10796,6 +10855,9 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
10796
10855
  return an enumerable that maps automatically to the named key on the
10797
10856
  member objects.
10798
10857
 
10858
+ If you merely want to watch for any items being added or removed to the array,
10859
+ use the `[]` property instead of `@each`.
10860
+
10799
10861
  @property @each
10800
10862
  */
10801
10863
  '@each': Ember.computed(function() {
@@ -10827,7 +10889,7 @@ var get = Ember.get,
10827
10889
  eachPropertyPattern = /^(.*)\.@each\.(.*)/,
10828
10890
  doubleEachPropertyPattern = /(.*\.@each){2,}/;
10829
10891
 
10830
- /**
10892
+ /*
10831
10893
  Tracks changes to dependent arrays, as well as to properties of items in
10832
10894
  dependent arrays.
10833
10895
 
@@ -11016,22 +11078,29 @@ DependentArraysObserver.prototype = {
11016
11078
  guid = guidFor(dependentArray),
11017
11079
  dependentKey = this.dependentKeysByGuid[guid],
11018
11080
  itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || [],
11081
+ item,
11019
11082
  itemIndex,
11083
+ sliceIndex,
11020
11084
  observerContexts;
11021
11085
 
11022
11086
  observerContexts = this.removeTransformation(dependentKey, index, removedCount);
11023
- forEach(dependentArray.slice(index, index + removedCount), function (item, sliceIndex) {
11087
+
11088
+
11089
+ function removeObservers(propertyKey) {
11090
+ removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver);
11091
+ removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer);
11092
+ }
11093
+
11094
+ for (sliceIndex = removedCount - 1; sliceIndex >= 0; --sliceIndex) {
11024
11095
  itemIndex = index + sliceIndex;
11096
+ item = dependentArray.objectAt(itemIndex);
11025
11097
 
11026
- forEach(itemPropertyKeys, function (propertyKey) {
11027
- removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver);
11028
- removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer);
11029
- }, this);
11098
+ forEach(itemPropertyKeys, removeObservers, this);
11030
11099
 
11031
11100
  changeMeta = createChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp);
11032
11101
  this.setValue( removedItem.call(
11033
11102
  this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta));
11034
- }, this);
11103
+ }
11035
11104
  },
11036
11105
 
11037
11106
  dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) {
@@ -11045,8 +11114,8 @@ DependentArraysObserver.prototype = {
11045
11114
 
11046
11115
  forEach(dependentArray.slice(index, index + addedCount), function (item, sliceIndex) {
11047
11116
  if (itemPropertyKeys) {
11048
- observerContext =
11049
- observerContexts[sliceIndex] =
11117
+ observerContext =
11118
+ observerContexts[sliceIndex] =
11050
11119
  this.createPropertyObserverContext(dependentArray, index + sliceIndex, this.trackedArraysByGuid[dependentKey]);
11051
11120
  forEach(itemPropertyKeys, function (propertyKey) {
11052
11121
  addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver);
@@ -11063,30 +11132,29 @@ DependentArraysObserver.prototype = {
11063
11132
  },
11064
11133
 
11065
11134
  itemPropertyWillChange: function (obj, keyName, array, index) {
11066
- var changeId = guidFor(obj)+":"+keyName;
11135
+ var guid = guidFor(obj);
11067
11136
 
11068
- if (!this.changedItems[changeId]) {
11069
- this.changedItems[changeId] = {
11070
- array: array,
11137
+ if (!this.changedItems[guid]) {
11138
+ this.changedItems[guid] = {
11139
+ array: array,
11071
11140
  index: index,
11072
11141
  obj: obj,
11073
- keyChanged: keyName,
11074
- previousValue: get(obj, keyName)
11142
+ previousValues: {}
11075
11143
  };
11076
11144
  }
11145
+
11146
+ this.changedItems[guid].previousValues[keyName] = get(obj, keyName);
11077
11147
  },
11078
11148
 
11079
11149
  itemPropertyDidChange: function(obj, keyName, array, index) {
11080
11150
  Ember.run.once(this, 'flushChanges');
11081
11151
  },
11082
11152
 
11083
- // TODO: it probably makes more sense to remove the item during `willChange`
11084
- // and add it back (with the new value) during `didChange`
11085
11153
  flushChanges: function() {
11086
11154
  var changedItems = this.changedItems, key, c, changeMeta;
11087
11155
  for (key in changedItems) {
11088
11156
  c = changedItems[key];
11089
- changeMeta = createChangeMeta(c.array, c.obj, c.index, this.instanceMeta.propertyName, this.cp, c.keyChanged, c.previousValue);
11157
+ changeMeta = createChangeMeta(c.array, c.obj, c.index, this.instanceMeta.propertyName, this.cp, c.previousValues);
11090
11158
  this.setValue(
11091
11159
  this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta));
11092
11160
  this.setValue(
@@ -11096,18 +11164,19 @@ DependentArraysObserver.prototype = {
11096
11164
  }
11097
11165
  };
11098
11166
 
11099
- function createChangeMeta(dependentArray, item, index, propertyName, property, key, previousValue) {
11167
+ function createChangeMeta(dependentArray, item, index, propertyName, property, previousValues) {
11100
11168
  var meta = {
11101
11169
  arrayChanged: dependentArray,
11102
11170
  index: index,
11103
11171
  item: item,
11104
11172
  propertyName: propertyName,
11105
- property: property,
11106
- // previous value is only available for item property changes!
11107
- previousValue: previousValue
11173
+ property: property
11108
11174
  };
11109
11175
 
11110
- if (key) { meta.keyChanged = key; }
11176
+ if (previousValues) {
11177
+ // previous values only available for item property changes
11178
+ meta.previousValues = previousValues;
11179
+ }
11111
11180
 
11112
11181
  return meta;
11113
11182
  }
@@ -11231,7 +11300,9 @@ function ReduceComputedProperty(options) {
11231
11300
 
11232
11301
  forEach(cp._dependentKeys, function(dependentKey) {
11233
11302
  var dependentArray = get(this, dependentKey);
11234
- addItems.call(this, dependentArray, callbacks, cp, propertyName, meta);
11303
+ if (dependentArray) {
11304
+ addItems.call(this, dependentArray, callbacks, cp, propertyName, meta);
11305
+ }
11235
11306
  }, this);
11236
11307
  };
11237
11308
 
@@ -11333,7 +11404,122 @@ ReduceComputedProperty.prototype.property = function () {
11333
11404
  return ComputedProperty.prototype.property.apply(this, propertyArgs);
11334
11405
  };
11335
11406
 
11407
+ /**
11408
+ Creates a computed property which operates on dependent arrays and
11409
+ is updated with "one at a time" semantics. When items are added or
11410
+ removed from the dependent array(s) a reduce computed only operates
11411
+ on the change instead of re-evaluating the entire array.
11412
+
11413
+ If there are more than one arguments the first arguments are
11414
+ considered to be dependent property keys. The last argument is
11415
+ required to be an options object. The options object can have the
11416
+ following four properties.
11417
+
11418
+ `initialValue` - A value or function that will be used as the initial
11419
+ value for the computed. If this property is a function the result of calling
11420
+ the function will be used as the initial value. This property is required.
11421
+
11422
+ `initialize` - An optional initialize function. Typically this will be used
11423
+ to set up state on the instanceMeta object.
11424
+
11425
+ `removedItem` - A function that is called each time an element is removed
11426
+ from the array.
11427
+
11428
+ `addedItem` - A function that is called each time an element is added to
11429
+ the array.
11430
+
11431
+
11432
+ The `initialize` function has the following signature:
11433
+
11434
+ ```javascript
11435
+ function (initialValue, changeMeta, instanceMeta)
11436
+ ```
11437
+
11438
+ `initialValue` - The value of the `initialValue` property from the
11439
+ options object.
11440
+
11441
+ `changeMeta` - An object which contains meta information about the
11442
+ computed. It contains the following properties:
11443
+
11444
+ - `property` the computed property
11445
+ - `propertyName` the name of the property on the object
11446
+
11447
+ `instanceMeta` - An object that can be used to store meta
11448
+ information needed for calculating your computed. For example a
11449
+ unique computed might use this to store the number of times a given
11450
+ element is found in the dependent array.
11336
11451
 
11452
+
11453
+ The `removedItem` and `addedItem` functions both have the following signature:
11454
+
11455
+ ```javascript
11456
+ function (accumulatedValue, item, changeMeta, instanceMeta)
11457
+ ```
11458
+
11459
+ `accumulatedValue` - The value returned from the last time
11460
+ `removedItem` or `addedItem` was called or `initialValue`.
11461
+
11462
+ `item` - the element added or removed from the array
11463
+
11464
+ `changeMeta` - An object which contains meta information about the
11465
+ change. It contains the following properties:
11466
+
11467
+ - `property` the computed property
11468
+ - `propertyName` the name of the property on the object
11469
+ - `index` the index of the added or removed item
11470
+ - `item` the added or removed item: this is exactly the same as
11471
+ the second arg
11472
+ - `arrayChanged` the array that triggered the change. Can be
11473
+ useful when depending on multiple arrays.
11474
+
11475
+ For property changes triggered on an item property change (when
11476
+ depKey is something like `someArray.@each.someProperty`),
11477
+ `changeMeta` will also contain the following property:
11478
+
11479
+ - `previousValues` an object whose keys are the properties that changed on
11480
+ the item, and whose values are the item's previous values.
11481
+
11482
+ `previousValues` is important Ember coalesces item property changes via
11483
+ Ember.run.once. This means that by the time removedItem gets called, item has
11484
+ the new values, but you may need the previous value (eg for sorting &
11485
+ filtering).
11486
+
11487
+ `instanceMeta` - An object that can be used to store meta
11488
+ information needed for calculating your computed. For example a
11489
+ unique computed might use this to store the number of times a given
11490
+ element is found in the dependent array.
11491
+
11492
+ The `removedItem` and `addedItem` functions should return the accumulated
11493
+ value. It is acceptable to not return anything (ie return undefined)
11494
+ to invalidate the computation. This is generally not a good idea for
11495
+ arrayComputed but it's used in eg max and min.
11496
+
11497
+ Example
11498
+
11499
+ ```javascript
11500
+ Ember.computed.max = function (dependentKey) {
11501
+ return Ember.reduceComputed.call(null, dependentKey, {
11502
+ initialValue: -Infinity,
11503
+
11504
+ addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
11505
+ return Math.max(accumulatedValue, item);
11506
+ },
11507
+
11508
+ removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) {
11509
+ if (item < accumulatedValue) {
11510
+ return accumulatedValue;
11511
+ }
11512
+ }
11513
+ });
11514
+ };
11515
+ ```
11516
+
11517
+ @method reduceComputed
11518
+ @for Ember
11519
+ @param {String} [dependentKeys*]
11520
+ @param {Object} options
11521
+ @returns {Ember.ComputedProperty}
11522
+ */
11337
11523
  Ember.reduceComputed = function (options) {
11338
11524
  var args;
11339
11525
 
@@ -11359,7 +11545,6 @@ Ember.reduceComputed = function (options) {
11359
11545
  return cp;
11360
11546
  };
11361
11547
 
11362
-
11363
11548
  })();
11364
11549
 
11365
11550
 
@@ -11404,7 +11589,120 @@ ArrayComputedProperty.prototype.resetValue = function (array) {
11404
11589
  return array;
11405
11590
  };
11406
11591
 
11592
+ /**
11593
+ Creates a computed property which operates on dependent arrays and
11594
+ is updated with "one at a time" semantics. When items are added or
11595
+ removed from the dependent array(s) an array computed only operates
11596
+ on the change instead of re-evaluating the entire array. This should
11597
+ return an array, if you'd like to use "one at a time" semantics and
11598
+ compute some value other then an array look at
11599
+ `Ember.reduceComputed`.
11600
+
11601
+ If there are more than one arguments the first arguments are
11602
+ considered to be dependent property keys. The last argument is
11603
+ required to be an options object. The options object can have the
11604
+ following three properties.
11605
+
11606
+ `initialize` - An optional initialize function. Typically this will be used
11607
+ to set up state on the instanceMeta object.
11608
+
11609
+ `removedItem` - A function that is called each time an element is
11610
+ removed from the array.
11611
+
11612
+ `addedItem` - A function that is called each time an element is
11613
+ added to the array.
11407
11614
 
11615
+
11616
+ The `initialize` function has the following signature:
11617
+
11618
+ ```javascript
11619
+ function (array, changeMeta, instanceMeta)
11620
+ ```
11621
+
11622
+ `array` - The initial value of the arrayComputed, an empty array.
11623
+
11624
+ `changeMeta` - An object which contains meta information about the
11625
+ computed. It contains the following properties:
11626
+
11627
+ - `property` the computed property
11628
+ - `propertyName` the name of the property on the object
11629
+
11630
+ `instanceMeta` - An object that can be used to store meta
11631
+ information needed for calculating your computed. For example a
11632
+ unique computed might use this to store the number of times a given
11633
+ element is found in the dependent array.
11634
+
11635
+
11636
+ The `removedItem` and `addedItem` functions both have the following signature:
11637
+
11638
+ ```javascript
11639
+ function (accumulatedValue, item, changeMeta, instanceMeta)
11640
+ ```
11641
+
11642
+ `accumulatedValue` - The value returned from the last time
11643
+ `removedItem` or `addedItem` was called or an empty array.
11644
+
11645
+ `item` - the element added or removed from the array
11646
+
11647
+ `changeMeta` - An object which contains meta information about the
11648
+ change. It contains the following properties:
11649
+
11650
+ - `property` the computed property
11651
+ - `propertyName` the name of the property on the object
11652
+ - `index` the index of the added or removed item
11653
+ - `item` the added or removed item: this is exactly the same as
11654
+ the second arg
11655
+ - `arrayChanged` the array that triggered the change. Can be
11656
+ useful when depending on multiple arrays.
11657
+
11658
+ For property changes triggered on an item property change (when
11659
+ depKey is something like `someArray.@each.someProperty`),
11660
+ `changeMeta` will also contain the following property:
11661
+
11662
+ - `previousValues` an object whose keys are the properties that changed on
11663
+ the item, and whose values are the item's previous values.
11664
+
11665
+ `previousValues` is important Ember coalesces item property changes via
11666
+ Ember.run.once. This means that by the time removedItem gets called, item has
11667
+ the new values, but you may need the previous value (eg for sorting &
11668
+ filtering).
11669
+
11670
+ `instanceMeta` - An object that can be used to store meta
11671
+ information needed for calculating your computed. For example a
11672
+ unique computed might use this to store the number of times a given
11673
+ element is found in the dependent array.
11674
+
11675
+ The `removedItem` and `addedItem` functions should return the accumulated
11676
+ value. It is acceptable to not return anything (ie return undefined)
11677
+ to invalidate the computation. This is generally not a good idea for
11678
+ arrayComputed but it's used in eg max and min.
11679
+
11680
+ Example
11681
+
11682
+ ```javascript
11683
+ Ember.computed.map = function(dependentKey, callback) {
11684
+ var options = {
11685
+ addedItem: function(array, item, changeMeta, instanceMeta) {
11686
+ var mapped = callback(item);
11687
+ array.insertAt(changeMeta.index, mapped);
11688
+ return array;
11689
+ },
11690
+ removedItem: function(array, item, changeMeta, instanceMeta) {
11691
+ array.removeAt(changeMeta.index, 1);
11692
+ return array;
11693
+ }
11694
+ };
11695
+
11696
+ return Ember.arrayComputed(dependentKey, options);
11697
+ };
11698
+ ```
11699
+
11700
+ @method arrayComputed
11701
+ @for Ember
11702
+ @param {String} [dependentKeys*]
11703
+ @param {Object} options
11704
+ @returns {Ember.ComputedProperty}
11705
+ */
11408
11706
  Ember.arrayComputed = function (options) {
11409
11707
  var args;
11410
11708
 
@@ -11431,12 +11729,45 @@ Ember.arrayComputed = function (options) {
11431
11729
 
11432
11730
 
11433
11731
  (function() {
11732
+ /**
11733
+ @module ember
11734
+ @submodule ember-runtime
11735
+ */
11736
+
11434
11737
  var get = Ember.get,
11435
11738
  set = Ember.set,
11739
+ guidFor = Ember.guidFor,
11740
+ merge = Ember.merge,
11436
11741
  a_slice = [].slice,
11437
11742
  forEach = Ember.EnumerableUtils.forEach,
11438
11743
  map = Ember.EnumerableUtils.map;
11439
11744
 
11745
+ /**
11746
+ A computed property that calculates the maximum value in the
11747
+ dependent array. This will return `-Infinity` when the dependent
11748
+ array is empty.
11749
+
11750
+ Example
11751
+
11752
+ ```javascript
11753
+ App.Person = Ember.Object.extend({
11754
+ childAges: Ember.computed.mapBy('children', 'age'),
11755
+ maxChildAge: Ember.computed.max('childAges')
11756
+ });
11757
+
11758
+ var lordByron = App.Person.create({children: []});
11759
+ lordByron.get('maxChildAge'); // -Infinity
11760
+ lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
11761
+ lordByron.get('maxChildAge'); // 7
11762
+ lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]);
11763
+ lordByron.get('maxChildAge'); // 8
11764
+ ```
11765
+
11766
+ @method computed.max
11767
+ @for Ember
11768
+ @param {String} dependentKey
11769
+ @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array
11770
+ */
11440
11771
  Ember.computed.max = function (dependentKey) {
11441
11772
  return Ember.reduceComputed.call(null, dependentKey, {
11442
11773
  initialValue: -Infinity,
@@ -11453,6 +11784,32 @@ Ember.computed.max = function (dependentKey) {
11453
11784
  });
11454
11785
  };
11455
11786
 
11787
+ /**
11788
+ A computed property that calculates the minimum value in the
11789
+ dependent array. This will return `Infinity` when the dependent
11790
+ array is empty.
11791
+
11792
+ Example
11793
+
11794
+ ```javascript
11795
+ App.Person = Ember.Object.extend({
11796
+ childAges: Ember.computed.mapBy('children', 'age'),
11797
+ minChildAge: Ember.computed.min('childAges')
11798
+ });
11799
+
11800
+ var lordByron = App.Person.create({children: []});
11801
+ lordByron.get('minChildAge'); // Infinity
11802
+ lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
11803
+ lordByron.get('minChildAge'); // 7
11804
+ lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]);
11805
+ lordByron.get('minChildAge'); // 5
11806
+ ```
11807
+
11808
+ @method computed.min
11809
+ @for Ember
11810
+ @param {String} dependentKey
11811
+ @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array
11812
+ */
11456
11813
  Ember.computed.min = function (dependentKey) {
11457
11814
  return Ember.reduceComputed.call(null, dependentKey, {
11458
11815
  initialValue: Infinity,
@@ -11469,6 +11826,36 @@ Ember.computed.min = function (dependentKey) {
11469
11826
  });
11470
11827
  };
11471
11828
 
11829
+ /**
11830
+ Returns an array mapped via the callback
11831
+
11832
+ The callback method you provide should have the following signature:
11833
+
11834
+ ```javascript
11835
+ function(item);
11836
+ ```
11837
+
11838
+ - `item` is the current item in the iteration.
11839
+
11840
+ Example
11841
+
11842
+ ```javascript
11843
+ App.Hampster = Ember.Object.extend({
11844
+ excitingChores: Ember.computed.map('chores', function(chore) {
11845
+ return chore.toUpperCase() + '!';
11846
+ })
11847
+ });
11848
+
11849
+ var hampster = App.Hampster.create({chores: ['cook', 'clean', 'write more unit tests']});
11850
+ hampster.get('excitingChores'); // ['COOK!', 'CLEAN!', 'WRITE MORE UNIT TESTS!']
11851
+ ```
11852
+
11853
+ @method computed.map
11854
+ @for Ember
11855
+ @param {String} dependentKey
11856
+ @param {Function} callback
11857
+ @return {Ember.ComputedProperty} an array mapped via the callback
11858
+ */
11472
11859
  Ember.computed.map = function(dependentKey, callback) {
11473
11860
  var options = {
11474
11861
  addedItem: function(array, item, changeMeta, instanceMeta) {
@@ -11485,11 +11872,79 @@ Ember.computed.map = function(dependentKey, callback) {
11485
11872
  return Ember.arrayComputed(dependentKey, options);
11486
11873
  };
11487
11874
 
11488
- Ember.computed.mapProperty = function(dependentKey, propertyKey) {
11875
+ /**
11876
+ Returns an array mapped to the specified key.
11877
+
11878
+ Example
11879
+
11880
+ ```javascript
11881
+ App.Person = Ember.Object.extend({
11882
+ childAges: Ember.computed.mapBy('children', 'age'),
11883
+ minChildAge: Ember.computed.min('childAges')
11884
+ });
11885
+
11886
+ var lordByron = App.Person.create({children: []});
11887
+ lordByron.get('childAge'); // []
11888
+ lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7});
11889
+ lordByron.get('childAge'); // [7]
11890
+ lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]);
11891
+ lordByron.get('childAge'); // [7, 5, 8]
11892
+ ```
11893
+
11894
+ @method computed.mapBy
11895
+ @for Ember
11896
+ @param {String} dependentKey
11897
+ @param {String} propertyKey
11898
+ @return {Ember.ComputedProperty} an array mapped to the specified key
11899
+ */
11900
+ Ember.computed.mapBy = function(dependentKey, propertyKey) {
11489
11901
  var callback = function(item) { return get(item, propertyKey); };
11490
11902
  return Ember.computed.map(dependentKey + '.@each.' + propertyKey, callback);
11491
11903
  };
11492
11904
 
11905
+ /**
11906
+ @method computed.mapProperty
11907
+ @for Ember
11908
+ @deprecated Use `Ember.computed.mapBy` instead
11909
+ @param dependentKey
11910
+ @param propertyKey
11911
+ */
11912
+ Ember.computed.mapProperty = Ember.computed.mapBy;
11913
+
11914
+ /**
11915
+ Filters the array by the callback.
11916
+
11917
+ The callback method you provide should have the following signature:
11918
+
11919
+ ```javascript
11920
+ function(item);
11921
+ ```
11922
+
11923
+ - `item` is the current item in the iteration.
11924
+
11925
+ Example
11926
+
11927
+ ```javascript
11928
+ App.Hampster = Ember.Object.extend({
11929
+ remainingChores: Ember.computed.filter('chores', function(chore) {
11930
+ return !chore.done;
11931
+ })
11932
+ });
11933
+
11934
+ var hampster = App.Hampster.create({chores: [
11935
+ {name: 'cook', done: true},
11936
+ {name: 'clean', done: true},
11937
+ {name: 'write more unit tests', done: false}
11938
+ ]});
11939
+ hampster.get('remainingChores'); // [{name: 'write more unit tests', done: false}]
11940
+ ```
11941
+
11942
+ @method computed.filter
11943
+ @for Ember
11944
+ @param {String} dependentKey
11945
+ @param {Function} callback
11946
+ @return {Ember.ComputedProperty} the filtered array
11947
+ */
11493
11948
  Ember.computed.filter = function(dependentKey, callback) {
11494
11949
  var options = {
11495
11950
  initialize: function (array, changeMeta, instanceMeta) {
@@ -11503,6 +11958,8 @@ Ember.computed.filter = function(dependentKey, callback) {
11503
11958
  if (match) {
11504
11959
  array.insertAt(filterIndex, item);
11505
11960
  }
11961
+
11962
+ return array;
11506
11963
  },
11507
11964
 
11508
11965
  removedItem: function(array, item, changeMeta, instanceMeta) {
@@ -11511,13 +11968,40 @@ Ember.computed.filter = function(dependentKey, callback) {
11511
11968
  if (filterIndex > -1) {
11512
11969
  array.removeAt(filterIndex);
11513
11970
  }
11971
+
11972
+ return array;
11514
11973
  }
11515
11974
  };
11516
11975
 
11517
11976
  return Ember.arrayComputed(dependentKey, options);
11518
11977
  };
11519
11978
 
11520
- Ember.computed.filterProperty = function(dependentKey, propertyKey, value) {
11979
+ /**
11980
+ Filters the array by the property and value
11981
+
11982
+ Example
11983
+
11984
+ ```javascript
11985
+ App.Hampster = Ember.Object.extend({
11986
+ remainingChores: Ember.computed.filterBy('chores', 'done', false)
11987
+ });
11988
+
11989
+ var hampster = App.Hampster.create({chores: [
11990
+ {name: 'cook', done: true},
11991
+ {name: 'clean', done: true},
11992
+ {name: 'write more unit tests', done: false}
11993
+ ]});
11994
+ hampster.get('remainingChores'); // [{name: 'write more unit tests', done: false}]
11995
+ ```
11996
+
11997
+ @method computed.filterBy
11998
+ @for Ember
11999
+ @param {String} dependentKey
12000
+ @param {String} propertyKey
12001
+ @param {String} value
12002
+ @return {Ember.ComputedProperty} the filtered array
12003
+ */
12004
+ Ember.computed.filterBy = function(dependentKey, propertyKey, value) {
11521
12005
  var callback;
11522
12006
 
11523
12007
  if (arguments.length === 2) {
@@ -11533,6 +12017,42 @@ Ember.computed.filterProperty = function(dependentKey, propertyKey, value) {
11533
12017
  return Ember.computed.filter(dependentKey + '.@each.' + propertyKey, callback);
11534
12018
  };
11535
12019
 
12020
+ /**
12021
+ @method computed.filterProperty
12022
+ @for Ember
12023
+ @param dependentKey
12024
+ @param propertyKey
12025
+ @param value
12026
+ @deprecated Use `Ember.computed.filterBy` instead
12027
+ */
12028
+ Ember.computed.filterProperty = Ember.computed.filterBy;
12029
+
12030
+ /**
12031
+ A computed property which returns a new array with all the unique
12032
+ elements from one or more dependent arrays.
12033
+
12034
+ Example
12035
+
12036
+ ```javascript
12037
+ App.Hampster = Ember.Object.extend({
12038
+ uniqueFruits: Ember.computed.uniq('fruits')
12039
+ });
12040
+
12041
+ var hampster = App.Hampster.create({fruits: [
12042
+ 'banana',
12043
+ 'grape',
12044
+ 'kale',
12045
+ 'banana'
12046
+ ]});
12047
+ hampster.get('uniqueFruits'); // ['banana', 'grape', 'kale']
12048
+ ```
12049
+
12050
+ @method computed.uniq
12051
+ @for Ember
12052
+ @param {String} propertyKey*
12053
+ @return {Ember.ComputedProperty} computes a new array with all the
12054
+ unique elements from the dependent array
12055
+ */
11536
12056
  Ember.computed.uniq = function() {
11537
12057
  var args = a_slice.call(arguments);
11538
12058
  args.push({
@@ -11541,7 +12061,7 @@ Ember.computed.uniq = function() {
11541
12061
  },
11542
12062
 
11543
12063
  addedItem: function(array, item, changeMeta, instanceMeta) {
11544
- var guid = Ember.guidFor(item);
12064
+ var guid = guidFor(item);
11545
12065
 
11546
12066
  if (!instanceMeta.itemCounts[guid]) {
11547
12067
  instanceMeta.itemCounts[guid] = 1;
@@ -11552,7 +12072,7 @@ Ember.computed.uniq = function() {
11552
12072
  return array;
11553
12073
  },
11554
12074
  removedItem: function(array, item, _, instanceMeta) {
11555
- var guid = Ember.guidFor(item),
12075
+ var guid = guidFor(item),
11556
12076
  itemCounts = instanceMeta.itemCounts;
11557
12077
 
11558
12078
  if (--itemCounts[guid] === 0) {
@@ -11563,12 +12083,44 @@ Ember.computed.uniq = function() {
11563
12083
  });
11564
12084
  return Ember.arrayComputed.apply(null, args);
11565
12085
  };
12086
+
12087
+ /**
12088
+ Alias for [Ember.computed.uniq](/api/#method_computed_uniq).
12089
+
12090
+ @method computed.union
12091
+ @for Ember
12092
+ @param {String} propertyKey*
12093
+ @return {Ember.ComputedProperty} computes a new array with all the
12094
+ unique elements from the dependent array
12095
+ */
11566
12096
  Ember.computed.union = Ember.computed.uniq;
11567
12097
 
12098
+ /**
12099
+ A computed property which returns a new array with all the duplicated
12100
+ elements from two or more dependeny arrays.
12101
+
12102
+ Example
12103
+
12104
+ ```javascript
12105
+ var obj = Ember.Object.createWithMixins({
12106
+ adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'],
12107
+ charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'],
12108
+ friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends')
12109
+ });
12110
+
12111
+ obj.get('friendsInCommon'); // ['William King', 'Mary Somerville']
12112
+ ```
12113
+
12114
+ @method computed.intersect
12115
+ @for Ember
12116
+ @param {String} propertyKey*
12117
+ @return {Ember.ComputedProperty} computes a new array with all the
12118
+ duplicated elements from the dependent arrays
12119
+ */
11568
12120
  Ember.computed.intersect = function () {
11569
12121
  var getDependentKeyGuids = function (changeMeta) {
11570
12122
  return map(changeMeta.property._dependentKeys, function (dependentKey) {
11571
- return Ember.guidFor(dependentKey);
12123
+ return guidFor(dependentKey);
11572
12124
  });
11573
12125
  };
11574
12126
 
@@ -11579,9 +12131,9 @@ Ember.computed.intersect = function () {
11579
12131
  },
11580
12132
 
11581
12133
  addedItem: function(array, item, changeMeta, instanceMeta) {
11582
- var itemGuid = Ember.guidFor(item),
12134
+ var itemGuid = guidFor(item),
11583
12135
  dependentGuids = getDependentKeyGuids(changeMeta),
11584
- dependentGuid = Ember.guidFor(changeMeta.arrayChanged),
12136
+ dependentGuid = guidFor(changeMeta.arrayChanged),
11585
12137
  numberOfDependentArrays = changeMeta.property._dependentKeys.length,
11586
12138
  itemCounts = instanceMeta.itemCounts;
11587
12139
 
@@ -11590,15 +12142,15 @@ Ember.computed.intersect = function () {
11590
12142
 
11591
12143
  if (++itemCounts[itemGuid][dependentGuid] === 1 &&
11592
12144
  numberOfDependentArrays === Ember.keys(itemCounts[itemGuid]).length) {
11593
-
12145
+
11594
12146
  array.addObject(item);
11595
12147
  }
11596
12148
  return array;
11597
12149
  },
11598
12150
  removedItem: function(array, item, changeMeta, instanceMeta) {
11599
- var itemGuid = Ember.guidFor(item),
12151
+ var itemGuid = guidFor(item),
11600
12152
  dependentGuids = getDependentKeyGuids(changeMeta),
11601
- dependentGuid = Ember.guidFor(changeMeta.arrayChanged),
12153
+ dependentGuid = guidFor(changeMeta.arrayChanged),
11602
12154
  numberOfDependentArrays = changeMeta.property._dependentKeys.length,
11603
12155
  numberOfArraysItemAppearsIn,
11604
12156
  itemCounts = instanceMeta.itemCounts;
@@ -11619,6 +12171,34 @@ Ember.computed.intersect = function () {
11619
12171
  return Ember.arrayComputed.apply(null, args);
11620
12172
  };
11621
12173
 
12174
+ /**
12175
+ A computed property which returns a new array with all the
12176
+ properties from the first dependent array that are not in the second
12177
+ dependent array.
12178
+
12179
+ Example
12180
+
12181
+ ```javascript
12182
+ App.Hampster = Ember.Object.extend({
12183
+ likes: ['banana', 'grape', 'kale'],
12184
+ wants: Ember.computed.setDiff('likes', 'fruits')
12185
+ });
12186
+
12187
+ var hampster = App.Hampster.create({fruits: [
12188
+ 'grape',
12189
+ 'kale',
12190
+ ]});
12191
+ hampster.get('wants'); // ['banana']
12192
+ ```
12193
+
12194
+ @method computed.setDiff
12195
+ @for Ember
12196
+ @param {String} setAProperty
12197
+ @param {String} setBProperty
12198
+ @return {Ember.ComputedProperty} computes a new array with all the
12199
+ items from the first dependent array that are not in the second
12200
+ dependent array
12201
+ */
11622
12202
  Ember.computed.setDiff = function (setAProperty, setBProperty) {
11623
12203
  if (arguments.length !== 2) {
11624
12204
  throw new Error("setDiff requires exactly two dependent arrays.");
@@ -11627,7 +12207,7 @@ Ember.computed.setDiff = function (setAProperty, setBProperty) {
11627
12207
  addedItem: function (array, item, changeMeta, instanceMeta) {
11628
12208
  var setA = get(this, setAProperty),
11629
12209
  setB = get(this, setBProperty);
11630
-
12210
+
11631
12211
  if (changeMeta.arrayChanged === setA) {
11632
12212
  if (!setB.contains(item)) {
11633
12213
  array.addObject(item);
@@ -11641,7 +12221,7 @@ Ember.computed.setDiff = function (setAProperty, setBProperty) {
11641
12221
  removedItem: function (array, item, changeMeta, instanceMeta) {
11642
12222
  var setA = get(this, setAProperty),
11643
12223
  setB = get(this, setBProperty);
11644
-
12224
+
11645
12225
  if (changeMeta.arrayChanged === setB) {
11646
12226
  if (setA.contains(item)) {
11647
12227
  array.addObject(item);
@@ -11655,7 +12235,7 @@ Ember.computed.setDiff = function (setAProperty, setBProperty) {
11655
12235
  };
11656
12236
 
11657
12237
  function binarySearch(array, item, low, high) {
11658
- var mid, midItem, res;
12238
+ var mid, midItem, res, guidMid, guidItem;
11659
12239
 
11660
12240
  if (arguments.length < 4) { high = get(array, 'length'); }
11661
12241
  if (arguments.length < 3) { low = 0; }
@@ -11667,7 +12247,18 @@ function binarySearch(array, item, low, high) {
11667
12247
  mid = low + Math.floor((high - low) / 2);
11668
12248
  midItem = array.objectAt(mid);
11669
12249
 
12250
+ guidMid = _guidFor(midItem);
12251
+ guidItem = _guidFor(item);
12252
+
12253
+ if (guidMid === guidItem) {
12254
+ return mid;
12255
+ }
12256
+
11670
12257
  res = this.order(midItem, item);
12258
+ if (res === 0) {
12259
+ res = guidMid < guidItem ? -1 : 1;
12260
+ }
12261
+
11671
12262
 
11672
12263
  if (res < 0) {
11673
12264
  return this.binarySearch(array, item, mid+1, high);
@@ -11676,8 +12267,66 @@ function binarySearch(array, item, low, high) {
11676
12267
  }
11677
12268
 
11678
12269
  return mid;
12270
+
12271
+ function _guidFor(item) {
12272
+ if (Ember.ObjectProxy.detectInstance(item)) {
12273
+ return guidFor(get(item, 'content'));
12274
+ }
12275
+ return guidFor(item);
12276
+ }
11679
12277
  }
11680
12278
 
12279
+ /**
12280
+ A computed property which returns a new array with all the
12281
+ properties from the first dependent array sorted based on a property
12282
+ or sort function.
12283
+
12284
+ The callback method you provide should have the following signature:
12285
+
12286
+ ```javascript
12287
+ function(itemA, itemB);
12288
+ ```
12289
+
12290
+ - `itemA` the first item to compare.
12291
+ - `itemB` the second item to compare.
12292
+
12293
+ This function should return `-1` when `itemA` should come before
12294
+ `itemB`. It should return `1` when `itemA` should come after
12295
+ `itemB`. If the `itemA` and `itemB` are equal this function should return `0`.
12296
+
12297
+ Example
12298
+
12299
+ ```javascript
12300
+ var ToDoList = Ember.Object.extend({
12301
+ todosSorting: ['name'],
12302
+ sortedTodos: Ember.computed.sort('todos', 'todosSorting'),
12303
+ priorityTodos: Ember.computed.sort('todos', function(a, b){
12304
+ if (a.priority > b.priority) {
12305
+ return 1;
12306
+ } else if (a.priority < b.priority) {
12307
+ return -1;
12308
+ }
12309
+ return 0;
12310
+ }),
12311
+ });
12312
+ var todoList = ToDoList.create({todos: [
12313
+ {name: 'Unit Test', priority: 2},
12314
+ {name: 'Documentation', priority: 3},
12315
+ {name: 'Release', priority: 1}
12316
+ ]});
12317
+
12318
+ todoList.get('sortedTodos'); // [{name:'Documentation', priority:3}, {name:'Release', priority:1}, {name:'Unit Test', priority:2}]
12319
+ todoList.get('priroityTodos'); // [{name:'Release', priority:1}, {name:'Unit Test', priority:2}, {name:'Documentation', priority:3}]
12320
+ ```
12321
+
12322
+ @method computed.sort
12323
+ @for Ember
12324
+ @param {String} dependentKey
12325
+ @param {String or Function} sortDefinition a dependent key to an
12326
+ array of sort properties or a function to use when sorting
12327
+ @return {Ember.ComputedProperty} computes a new sorted array based
12328
+ on the sort property array or callback function
12329
+ */
11681
12330
  Ember.computed.sort = function (itemsKey, sortDefinition) {
11682
12331
  Ember.assert("Ember.computed.sort requires two arguments: an array key to sort and either a sort properties key or sort function", arguments.length === 2);
11683
12332
 
@@ -11765,9 +12414,8 @@ Ember.computed.sort = function (itemsKey, sortDefinition) {
11765
12414
  removedItem: function (array, item, changeMeta, instanceMeta) {
11766
12415
  var proxyProperties, index, searchItem;
11767
12416
 
11768
- if (changeMeta.keyChanged) {
11769
- proxyProperties = { content: item };
11770
- proxyProperties[changeMeta.keyChanged] = changeMeta.previousValue;
12417
+ if (changeMeta.previousValues) {
12418
+ proxyProperties = merge({ content: item }, changeMeta.previousValues);
11771
12419
 
11772
12420
  searchItem = Ember.ObjectProxy.create(proxyProperties);
11773
12421
  } else {
@@ -12191,9 +12839,9 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
12191
12839
  Computed properties allow you to treat a function like a property:
12192
12840
 
12193
12841
  ```javascript
12194
- MyApp.president = Ember.Object.create({
12195
- firstName: "Barack",
12196
- lastName: "Obama",
12842
+ MyApp.President = Ember.Object.extend({
12843
+ firstName: '',
12844
+ lastName: '',
12197
12845
 
12198
12846
  fullName: function() {
12199
12847
  return this.get('firstName') + ' ' + this.get('lastName');
@@ -12202,7 +12850,12 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
12202
12850
  }.property()
12203
12851
  });
12204
12852
 
12205
- MyApp.president.get('fullName'); // "Barack Obama"
12853
+ var president = MyApp.President.create({
12854
+ firstName: "Barack",
12855
+ lastName: "Obama"
12856
+ });
12857
+
12858
+ president.get('fullName'); // "Barack Obama"
12206
12859
  ```
12207
12860
 
12208
12861
  Treating a function like a property is useful because they can work with
@@ -12214,9 +12867,9 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
12214
12867
  about these dependencies like this:
12215
12868
 
12216
12869
  ```javascript
12217
- MyApp.president = Ember.Object.create({
12218
- firstName: "Barack",
12219
- lastName: "Obama",
12870
+ MyApp.President = Ember.Object.extend({
12871
+ firstName: '',
12872
+ lastName: '',
12220
12873
 
12221
12874
  fullName: function() {
12222
12875
  return this.get('firstName') + ' ' + this.get('lastName');
@@ -12253,15 +12906,18 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
12253
12906
  For example:
12254
12907
 
12255
12908
  ```javascript
12256
- Ember.Object.create({
12909
+ Ember.Object.extend({
12257
12910
  valueObserver: function() {
12258
12911
  // Executes whenever the "value" property changes
12259
12912
  }.observes('value')
12260
12913
  });
12261
12914
  ```
12262
12915
 
12263
- See `Ember.observes`.
12264
-
12916
+ In the future this method may become asynchronous. If you want to ensure
12917
+ synchronous behavior, use `observesImmediately`.
12918
+
12919
+ See `Ember.observer`.
12920
+
12265
12921
  @method observes
12266
12922
  @for Function
12267
12923
  */
@@ -12270,24 +12926,58 @@ if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) {
12270
12926
  return this;
12271
12927
  };
12272
12928
 
12929
+ /**
12930
+ The `observesImmediately` extension of Javascript's Function prototype is
12931
+ available when `Ember.EXTEND_PROTOTYPES` or
12932
+ `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default.
12933
+
12934
+ You can observe property changes simply by adding the `observesImmediately`
12935
+ call to the end of your method declarations in classes that you write.
12936
+ For example:
12937
+
12938
+ ```javascript
12939
+ Ember.Object.extend({
12940
+ valueObserver: function() {
12941
+ // Executes immediately after the "value" property changes
12942
+ }.observesImmediately('value')
12943
+ });
12944
+ ```
12945
+
12946
+ In the future, `observes` may become asynchronous. In this event,
12947
+ `observesImmediately` will maintain the synchronous behavior.
12948
+
12949
+ See `Ember.immediateObserver`.
12950
+
12951
+ @method observesImmediately
12952
+ @for Function
12953
+ */
12954
+ Function.prototype.observesImmediately = function() {
12955
+ for (var i=0, l=arguments.length; i<l; i++) {
12956
+ var arg = arguments[i];
12957
+ Ember.assert("Immediate observers must observe internal properties only, not properties on other objects.", arg.indexOf('.') === -1);
12958
+ }
12959
+
12960
+ return this.observes.apply(this, arguments);
12961
+ };
12962
+
12273
12963
  /**
12274
12964
  The `observesBefore` extension of Javascript's Function prototype is
12275
12965
  available when `Ember.EXTEND_PROTOTYPES` or
12276
12966
  `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default.
12277
12967
 
12278
- You can get notified when a property changes is about to happen by
12968
+ You can get notified when a property change is about to happen by
12279
12969
  by adding the `observesBefore` call to the end of your method
12280
12970
  declarations in classes that you write. For example:
12281
12971
 
12282
12972
  ```javascript
12283
- Ember.Object.create({
12973
+ Ember.Object.extend({
12284
12974
  valueObserver: function() {
12285
12975
  // Executes whenever the "value" property is about to change
12286
12976
  }.observesBefore('value')
12287
12977
  });
12288
12978
  ```
12289
12979
 
12290
- See `Ember.observesBefore`.
12980
+ See `Ember.beforeObserver`.
12291
12981
 
12292
12982
  @method observesBefore
12293
12983
  @for Function
@@ -13730,11 +14420,6 @@ Ember.Evented = Ember.Mixin.create({
13730
14420
  Ember.sendEvent(this, name, args);
13731
14421
  },
13732
14422
 
13733
- fire: function(name) {
13734
- Ember.deprecate("Ember.Evented#fire() has been deprecated in favor of trigger() for compatibility with jQuery. It will be removed in 1.0. Please update your code to call trigger() instead.");
13735
- this.trigger.apply(this, arguments);
13736
- },
13737
-
13738
14423
  /**
13739
14424
  Cancels subscription for given name, target, and method.
13740
14425
 
@@ -13913,6 +14598,121 @@ Ember.ActionHandler = Ember.Mixin.create({
13913
14598
 
13914
14599
 
13915
14600
 
14601
+ (function() {
14602
+ var set = Ember.set, get = Ember.get,
14603
+ resolve = Ember.RSVP.resolve,
14604
+ rethrow = Ember.RSVP.rethrow,
14605
+ not = Ember.computed.not,
14606
+ or = Ember.computed.or;
14607
+
14608
+ /**
14609
+ @module ember
14610
+ @submodule ember-runtime
14611
+ */
14612
+
14613
+ function installPromise(proxy, promise) {
14614
+ promise.then(function(value) {
14615
+ set(proxy, 'isFulfilled', true);
14616
+ set(proxy, 'content', value);
14617
+
14618
+ return value;
14619
+ }, function(reason) {
14620
+ set(proxy, 'isRejected', true);
14621
+ set(proxy, 'reason', reason);
14622
+ }).fail(rethrow);
14623
+ }
14624
+
14625
+ /**
14626
+ A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware.
14627
+
14628
+ ```javascript
14629
+ var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin);
14630
+
14631
+ var controller = ObjectPromiseController.create({
14632
+ promise: $.getJSON('/some/remote/data.json')
14633
+ });
14634
+
14635
+ controller.then(function(json){
14636
+ // the json
14637
+ }, function(reason) {
14638
+ // the reason why you have no json
14639
+ });
14640
+ ```
14641
+
14642
+ the controller has bindable attributes which
14643
+ track the promises life cycle
14644
+
14645
+ ```javascript
14646
+ controller.get('isPending') //=> true
14647
+ controller.get('isSettled') //=> false
14648
+ controller.get('isRejected') //=> false
14649
+ controller.get('isFulfilled') //=> false
14650
+ ```
14651
+
14652
+ When the the $.getJSON completes, and the promise is fulfilled
14653
+ with json, the life cycle attributes will update accordingly.
14654
+
14655
+ ```javascript
14656
+ controller.get('isPending') //=> false
14657
+ controller.get('isSettled') //=> true
14658
+ controller.get('isRejected') //=> false
14659
+ controller.get('isFulfilled') //=> true
14660
+ ```
14661
+
14662
+ As the controller is an ObjectController, and the json now its content,
14663
+ all the json properties will be available directly from the controller.
14664
+
14665
+ ```javascript
14666
+ // Assuming the following json:
14667
+ {
14668
+ firstName: 'Stefan',
14669
+ lastName: 'Penner'
14670
+ }
14671
+
14672
+ // both properties will accessible on the controller
14673
+ controller.get('firstName') //=> 'Stefan'
14674
+ controller.get('lastName') //=> 'Penner'
14675
+ ```
14676
+
14677
+ If the controller is backing a template, the attributes are
14678
+ bindable from within that template
14679
+ ```handlebars
14680
+ {{#if isPending}}
14681
+ loading...
14682
+ {{else}}
14683
+ firstName: {{firstName}}
14684
+ lastName: {{lastName}}
14685
+ {{/if}}
14686
+ ```
14687
+ @class Ember.PromiseProxyMixin
14688
+ */
14689
+ Ember.PromiseProxyMixin = Ember.Mixin.create({
14690
+ reason: null,
14691
+ isPending: not('isSettled').readOnly(),
14692
+ isSettled: or('isRejected', 'isFulfilled').readOnly(),
14693
+ isRejected: false,
14694
+ isFulfilled: false,
14695
+
14696
+ promise: Ember.computed(function(key, promise) {
14697
+ if (arguments.length === 2) {
14698
+ promise = resolve(promise);
14699
+ installPromise(this, promise);
14700
+ return promise;
14701
+ } else {
14702
+ throw new Error("PromiseProxy's promise must be set");
14703
+ }
14704
+ }),
14705
+
14706
+ then: function(fulfill, reject) {
14707
+ return get(this, 'promise').then(fulfill, reject);
14708
+ }
14709
+ });
14710
+
14711
+
14712
+ })();
14713
+
14714
+
14715
+
13916
14716
  (function() {
13917
14717
 
13918
14718
  })();
@@ -15613,7 +16413,9 @@ var get = Ember.get,
15613
16413
  removeBeforeObserver = Ember.removeBeforeObserver,
15614
16414
  removeObserver = Ember.removeObserver,
15615
16415
  propertyWillChange = Ember.propertyWillChange,
15616
- propertyDidChange = Ember.propertyDidChange;
16416
+ propertyDidChange = Ember.propertyDidChange,
16417
+ meta = Ember.meta,
16418
+ defineProperty = Ember.defineProperty;
15617
16419
 
15618
16420
  function contentPropertyWillChange(content, contentKey) {
15619
16421
  var key = contentKey.slice(8); // remove "content."
@@ -15731,6 +16533,14 @@ Ember.ObjectProxy = Ember.Object.extend(/** @scope Ember.ObjectProxy.prototype *
15731
16533
  },
15732
16534
 
15733
16535
  setUnknownProperty: function (key, value) {
16536
+ var m = meta(this);
16537
+ if (m.proto === this) {
16538
+ // if marked as prototype then just defineProperty
16539
+ // rather than delegate
16540
+ defineProperty(this, key, null, value);
16541
+ return value;
16542
+ }
16543
+
15734
16544
  var content = get(this, 'content');
15735
16545
  Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content);
15736
16546
  return set(content, key, value);
@@ -15738,25 +16548,6 @@ Ember.ObjectProxy = Ember.Object.extend(/** @scope Ember.ObjectProxy.prototype *
15738
16548
 
15739
16549
  });
15740
16550
 
15741
- Ember.ObjectProxy.reopenClass({
15742
- create: function () {
15743
- var mixin, prototype, i, l, properties, keyName;
15744
- if (arguments.length) {
15745
- prototype = this.proto();
15746
- for (i = 0, l = arguments.length; i < l; i++) {
15747
- properties = arguments[i];
15748
- for (keyName in properties) {
15749
- if (!properties.hasOwnProperty(keyName) || keyName in prototype) { continue; }
15750
- if (!mixin) mixin = {};
15751
- mixin[keyName] = null;
15752
- }
15753
- }
15754
- if (mixin) this._initMixins([mixin]);
15755
- }
15756
- return this._super.apply(this, arguments);
15757
- }
15758
- });
15759
-
15760
16551
  })();
15761
16552
 
15762
16553
 
@@ -15769,7 +16560,8 @@ Ember.ObjectProxy.reopenClass({
15769
16560
 
15770
16561
 
15771
16562
  var set = Ember.set, get = Ember.get, guidFor = Ember.guidFor;
15772
- var forEach = Ember.EnumerableUtils.forEach;
16563
+ var forEach = Ember.EnumerableUtils.forEach,
16564
+ indexOf = Ember.ArrayPolyfills.indexOf;
15773
16565
 
15774
16566
  var EachArray = Ember.Object.extend(Ember.Array, {
15775
16567
 
@@ -15827,7 +16619,7 @@ function removeObserverForContentKey(content, keyName, proxy, idx, loc) {
15827
16619
 
15828
16620
  guid = guidFor(item);
15829
16621
  indicies = objects[guid];
15830
- indicies[indicies.indexOf(loc)] = null;
16622
+ indicies[indexOf.call(indicies, loc)] = null;
15831
16623
  }
15832
16624
  }
15833
16625
  }
@@ -16752,7 +17544,7 @@ Ember.ControllerMixin = Ember.Mixin.create(Ember.ActionHandler, {
16752
17544
  deprecatedSend: function(actionName) {
16753
17545
  var args = [].slice.call(arguments, 1);
16754
17546
  Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function');
16755
- Ember.deprecate('Action handlers implemented directly on controllers are deprecated in favor of action handlers on an `actions` object', false);
17547
+ Ember.deprecate('Action handlers implemented directly on controllers are deprecated in favor of action handlers on an `actions` object (' + actionName + ' on ' + this + ')', false);
16756
17548
  this[actionName].apply(this, args);
16757
17549
  return;
16758
17550
  }
@@ -17232,11 +18024,15 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
17232
18024
  },
17233
18025
 
17234
18026
  init: function() {
17235
- if (!this.get('content')) { Ember.defineProperty(this, 'content', undefined, Ember.A()); }
17236
18027
  this._super();
18028
+
17237
18029
  this.set('_subControllers', Ember.A());
17238
18030
  },
17239
18031
 
18032
+ content: Ember.computed(function () {
18033
+ return Ember.A();
18034
+ }),
18035
+
17240
18036
  controllerAt: function(idx, object, controllerClass) {
17241
18037
  var container = get(this, 'container'),
17242
18038
  subControllers = get(this, '_subControllers'),
@@ -18507,7 +19303,7 @@ Ember.CoreView = Ember.Object.extend(Ember.Evented, Ember.ActionHandler, {
18507
19303
  deprecatedSend: function(actionName) {
18508
19304
  var args = [].slice.call(arguments, 1);
18509
19305
  Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function');
18510
- Ember.deprecate('Action handlers implemented directly on views are deprecated in favor of action handlers on an `actions` object', false);
19306
+ Ember.deprecate('Action handlers implemented directly on views are deprecated in favor of action handlers on an `actions` object (' + actionName + ' on ' + this + ')', false);
18511
19307
  this[actionName].apply(this, args);
18512
19308
  return;
18513
19309
  },
@@ -18891,9 +19687,6 @@ var EMPTY_ARRAY = [];
18891
19687
  Using a value for `templateName` that does not have a Handlebars template
18892
19688
  with a matching `data-template-name` attribute will throw an error.
18893
19689
 
18894
- Assigning a value to both `template` and `templateName` properties will throw
18895
- an error.
18896
-
18897
19690
  For views classes that may have a template later defined (e.g. as the block
18898
19691
  portion of a `{{view}}` Handlebars helper call in another template or in
18899
19692
  a subclass), you can provide a `defaultTemplate` property set to compiled
@@ -21436,7 +22229,7 @@ Ember.ContainerView = Ember.View.extend(Ember.MutableArray, {
21436
22229
 
21437
22230
  length: Ember.computed(function () {
21438
22231
  return this._childViews.length;
21439
- }),
22232
+ }).volatile(),
21440
22233
 
21441
22234
  /**
21442
22235
  @private
@@ -21766,11 +22559,6 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
21766
22559
  manipulated. Instead, add, remove, replace items from its `content` property.
21767
22560
  This will trigger appropriate changes to its rendered HTML.
21768
22561
 
21769
- ## Use in templates via the `{{collection}}` `Ember.Handlebars` helper
21770
-
21771
- `Ember.Handlebars` provides a helper specifically for adding
21772
- `CollectionView`s to templates. See [Ember.Handlebars.helpers.collection](/api/classes/Ember.Handlebars.helpers.html#method_collection)
21773
- for more details
21774
22562
 
21775
22563
  @class CollectionView
21776
22564
  @namespace Ember
@@ -22079,7 +22867,7 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone;
22079
22867
  ```html
22080
22868
  <!-- app-profile template -->
22081
22869
  <h1>{{person.title}}</h1>
22082
- <img {{bindAttr src=person.avatar}}>
22870
+ <img {{bind-attr src=person.avatar}}>
22083
22871
  <p class='signature'>{{person.signature}}</p>
22084
22872
  ```
22085
22873
 
@@ -22101,7 +22889,7 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone;
22101
22889
  If you want to customize the component, in order to
22102
22890
  handle events or actions, you implement a subclass
22103
22891
  of `Ember.Component` named after the name of the
22104
- component. Note that `Component` needs to be appended to the name of
22892
+ component. Note that `Component` needs to be appended to the name of
22105
22893
  your subclass like `AppProfileComponent`.
22106
22894
 
22107
22895
  For example, you could implement the action
@@ -22163,6 +22951,7 @@ Ember.Component = Ember.View.extend(Ember.TargetActionSupport, {
22163
22951
  view.appendChild(Ember.View, {
22164
22952
  isVirtual: true,
22165
22953
  tagName: '',
22954
+ _contextView: parentView,
22166
22955
  template: get(this, 'template'),
22167
22956
  context: get(parentView, 'context'),
22168
22957
  controller: get(parentView, 'controller'),
@@ -22912,16 +23701,7 @@ function makeBindings(options) {
22912
23701
  @param {String} dependentKeys*
22913
23702
  */
22914
23703
  Ember.Handlebars.helper = function(name, value) {
22915
- if (Ember.Component.detect(value)) {
22916
- Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", name.match(/-/));
22917
-
22918
- var proto = value.proto();
22919
- if (!proto.layoutName && !proto.templateName) {
22920
- value.reopen({
22921
- layoutName: 'components/' + name
22922
- });
22923
- }
22924
- }
23704
+ Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Ember.Component.detect(value) || name.match(/-/));
22925
23705
 
22926
23706
  if (Ember.View.detect(value)) {
22927
23707
  Ember.Handlebars.registerHelper(name, function(options) {
@@ -23712,6 +24492,8 @@ function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) {
23712
24492
  this.morph = Metamorph();
23713
24493
  this.state = 'preRender';
23714
24494
  this.updateId = null;
24495
+ this._parentView = null;
24496
+ this.buffer = null;
23715
24497
  }
23716
24498
 
23717
24499
  Ember._SimpleHandlebarsView = SimpleHandlebarsView;
@@ -23725,7 +24507,11 @@ SimpleHandlebarsView.prototype = {
23725
24507
  Ember.run.cancel(this.updateId);
23726
24508
  this.updateId = null;
23727
24509
  }
24510
+ if (this._parentView) {
24511
+ this._parentView.removeChild(this);
24512
+ }
23728
24513
  this.morph = null;
24514
+ this.state = 'destroyed';
23729
24515
  },
23730
24516
 
23731
24517
  propertyWillChange: Ember.K,
@@ -23780,7 +24566,7 @@ SimpleHandlebarsView.prototype = {
23780
24566
  rerender: function() {
23781
24567
  switch(this.state) {
23782
24568
  case 'preRender':
23783
- case 'destroying':
24569
+ case 'destroyed':
23784
24570
  break;
23785
24571
  case 'inBuffer':
23786
24572
  throw new Ember.Error("Something you did tried to replace an {{expression}} before it was inserted into the DOM.");
@@ -25483,6 +26269,8 @@ GroupedEach.prototype = {
25483
26269
  },
25484
26270
 
25485
26271
  addArrayObservers: function() {
26272
+ if (!this.content) { return; }
26273
+
25486
26274
  this.content.addArrayObserver(this, {
25487
26275
  willChange: 'contentArrayWillChange',
25488
26276
  didChange: 'contentArrayDidChange'
@@ -25490,6 +26278,8 @@ GroupedEach.prototype = {
25490
26278
  },
25491
26279
 
25492
26280
  removeArrayObservers: function() {
26281
+ if (!this.content) { return; }
26282
+
25493
26283
  this.content.removeArrayObserver(this, {
25494
26284
  willChange: 'contentArrayWillChange',
25495
26285
  didChange: 'contentArrayDidChange'
@@ -25507,6 +26297,8 @@ GroupedEach.prototype = {
25507
26297
  },
25508
26298
 
25509
26299
  render: function() {
26300
+ if (!this.content) { return; }
26301
+
25510
26302
  var content = this.content,
25511
26303
  contentLength = get(content, 'length'),
25512
26304
  data = this.options.data,
@@ -25519,12 +26311,21 @@ GroupedEach.prototype = {
25519
26311
  },
25520
26312
 
25521
26313
  rerenderContainingView: function() {
25522
- Ember.run.scheduleOnce('render', this.containingView, 'rerender');
26314
+ var self = this;
26315
+ Ember.run.scheduleOnce('render', this, function() {
26316
+ // It's possible it's been destroyed after we enqueued a re-render call.
26317
+ if (!self.destroyed) {
26318
+ self.containingView.rerender();
26319
+ }
26320
+ });
25523
26321
  },
25524
26322
 
25525
26323
  destroy: function() {
25526
26324
  this.removeContentObservers();
25527
- this.removeArrayObservers();
26325
+ if (this.content) {
26326
+ this.removeArrayObservers();
26327
+ }
26328
+ this.destroyed = true;
25528
26329
  }
25529
26330
  };
25530
26331
 
@@ -25865,20 +26666,20 @@ var get = Ember.get, set = Ember.set;
25865
26666
  inserting the view's own rendered output at the `{{yield}}` location.
25866
26667
 
25867
26668
  An empty `<body>` and the following application code:
25868
-
26669
+
25869
26670
  ```javascript
25870
26671
  AView = Ember.View.extend({
25871
26672
  classNames: ['a-view-with-layout'],
25872
26673
  layout: Ember.Handlebars.compile('<div class="wrapper">{{yield}}</div>'),
25873
26674
  template: Ember.Handlebars.compile('<span>I am wrapped</span>')
25874
26675
  });
25875
-
26676
+
25876
26677
  aView = AView.create();
25877
26678
  aView.appendTo('body');
25878
26679
  ```
25879
-
26680
+
25880
26681
  Will result in the following HTML output:
25881
-
26682
+
25882
26683
  ```html
25883
26684
  <body>
25884
26685
  <div class='ember-view a-view-with-layout'>
@@ -25888,50 +26689,50 @@ var get = Ember.get, set = Ember.set;
25888
26689
  </div>
25889
26690
  </body>
25890
26691
  ```
25891
-
26692
+
25892
26693
  The `yield` helper cannot be used outside of a template assigned to an
25893
26694
  `Ember.View`'s `layout` property and will throw an error if attempted.
25894
-
26695
+
25895
26696
  ```javascript
25896
26697
  BView = Ember.View.extend({
25897
26698
  classNames: ['a-view-with-layout'],
25898
26699
  template: Ember.Handlebars.compile('{{yield}}')
25899
26700
  });
25900
-
26701
+
25901
26702
  bView = BView.create();
25902
26703
  bView.appendTo('body');
25903
-
26704
+
25904
26705
  // throws
25905
- // Uncaught Error: assertion failed:
26706
+ // Uncaught Error: assertion failed:
25906
26707
  // You called yield in a template that was not a layout
25907
26708
  ```
25908
26709
 
25909
26710
  ### Use with Ember.Component
25910
26711
  When designing components `{{yield}}` is used to denote where, inside the component's
25911
26712
  template, an optional block passed to the component should render:
25912
-
26713
+
25913
26714
  ```handlebars
25914
26715
  <!-- application.hbs -->
25915
26716
  {{#labeled-textfield value=someProperty}}
25916
26717
  First name:
25917
26718
  {{/my-component}}
25918
26719
  ```
25919
-
26720
+
25920
26721
  ```handlebars
25921
26722
  <!-- components/my-component.hbs -->
25922
26723
  <label>
25923
26724
  {{yield}} {{input value=value}}
25924
26725
  </label>
25925
26726
  ```
25926
-
26727
+
25927
26728
  Result:
25928
-
26729
+
25929
26730
  ```html
25930
26731
  <label>
25931
26732
  First name: <input type="text" />
25932
26733
  <label>
25933
26734
  ```
25934
-
26735
+
25935
26736
  @method yield
25936
26737
  @for Ember.Handlebars.helpers
25937
26738
  @param {Hash} options
@@ -25941,7 +26742,11 @@ Ember.Handlebars.registerHelper('yield', function(options) {
25941
26742
  var view = options.data.view;
25942
26743
 
25943
26744
  while (view && !get(view, 'layout')) {
25944
- view = get(view, 'parentView');
26745
+ if (view._contextView) {
26746
+ view = view._contextView;
26747
+ } else {
26748
+ view = get(view, 'parentView');
26749
+ }
25945
26750
  }
25946
26751
 
25947
26752
  Ember.assert("You called yield in a template that was not a layout", !!view);
@@ -26083,9 +26888,6 @@ Ember.TextSupport = Ember.Mixin.create({
26083
26888
  disabled: false,
26084
26889
  maxlength: null,
26085
26890
 
26086
- insertNewline: Ember.K,
26087
- cancel: Ember.K,
26088
-
26089
26891
  init: function() {
26090
26892
  this._super();
26091
26893
  this.on("focusOut", this, this._elementValueDidChange);
@@ -26096,99 +26898,6 @@ Ember.TextSupport = Ember.Mixin.create({
26096
26898
  this.on("keyUp", this, this.interpretKeyEvents);
26097
26899
  },
26098
26900
 
26099
- interpretKeyEvents: function(event) {
26100
- var map = Ember.TextSupport.KEY_EVENTS;
26101
- var method = map[event.keyCode];
26102
-
26103
- this._elementValueDidChange();
26104
- if (method) { return this[method](event); }
26105
- },
26106
-
26107
- _elementValueDidChange: function() {
26108
- set(this, 'value', this.$().val());
26109
- }
26110
-
26111
- });
26112
-
26113
- Ember.TextSupport.KEY_EVENTS = {
26114
- 13: 'insertNewline',
26115
- 27: 'cancel'
26116
- };
26117
-
26118
- })();
26119
-
26120
-
26121
-
26122
- (function() {
26123
- /**
26124
- @module ember
26125
- @submodule ember-handlebars
26126
- */
26127
-
26128
- var get = Ember.get, set = Ember.set;
26129
-
26130
- /**
26131
-
26132
- The internal class used to create text inputs when the `{{input}}`
26133
- helper is used with `type` of `text`.
26134
-
26135
- See Handlebars.helpers.input for usage details.
26136
-
26137
- ## Layout and LayoutName properties
26138
-
26139
- Because HTML `input` elements are self closing `layout` and `layoutName`
26140
- properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s
26141
- layout section for more information.
26142
-
26143
- @class TextField
26144
- @namespace Ember
26145
- @extends Ember.View
26146
- @uses Ember.TextSupport
26147
- */
26148
- Ember.TextField = Ember.View.extend(Ember.TextSupport,
26149
- /** @scope Ember.TextField.prototype */ {
26150
-
26151
- classNames: ['ember-text-field'],
26152
- tagName: "input",
26153
- attributeBindings: ['type', 'value', 'size', 'pattern', 'name'],
26154
-
26155
- /**
26156
- The `value` attribute of the input element. As the user inputs text, this
26157
- property is updated live.
26158
-
26159
- @property value
26160
- @type String
26161
- @default ""
26162
- */
26163
- value: "",
26164
-
26165
- /**
26166
- The `type` attribute of the input element.
26167
-
26168
- @property type
26169
- @type String
26170
- @default "text"
26171
- */
26172
- type: "text",
26173
-
26174
- /**
26175
- The `size` of the text field in characters.
26176
-
26177
- @property size
26178
- @type String
26179
- @default null
26180
- */
26181
- size: null,
26182
-
26183
- /**
26184
- The `pattern` the pattern attribute of input element.
26185
-
26186
- @property pattern
26187
- @type String
26188
- @default null
26189
- */
26190
- pattern: null,
26191
-
26192
26901
  /**
26193
26902
  The action to be sent when the user presses the return key.
26194
26903
 
@@ -26233,6 +26942,18 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
26233
26942
  */
26234
26943
  bubbles: false,
26235
26944
 
26945
+ interpretKeyEvents: function(event) {
26946
+ var map = Ember.TextSupport.KEY_EVENTS;
26947
+ var method = map[event.keyCode];
26948
+
26949
+ this._elementValueDidChange();
26950
+ if (method) { return this[method](event); }
26951
+ },
26952
+
26953
+ _elementValueDidChange: function() {
26954
+ set(this, 'value', this.$().val());
26955
+ },
26956
+
26236
26957
  /**
26237
26958
  The action to be sent when the user inserts a new line.
26238
26959
 
@@ -26244,6 +26965,40 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
26244
26965
  */
26245
26966
  insertNewline: function(event) {
26246
26967
  sendAction('enter', this, event);
26968
+ sendAction('insert-newline', this, event);
26969
+ },
26970
+
26971
+ /**
26972
+ Called when the user hits escape.
26973
+
26974
+ Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13.
26975
+ Uses sendAction to send the `enter` action to the controller.
26976
+
26977
+ @method cancel
26978
+ @param {Event} event
26979
+ */
26980
+ cancel: function(event) {
26981
+ sendAction('escape-press', this, event);
26982
+ },
26983
+
26984
+ /**
26985
+ Called when the text area is focused.
26986
+
26987
+ @method focusIn
26988
+ @param {Event} event
26989
+ */
26990
+ focusIn: function(event) {
26991
+ sendAction('focus-in', this, event);
26992
+ },
26993
+
26994
+ /**
26995
+ Called when the text area is blurred.
26996
+
26997
+ @method focusOut
26998
+ @param {Event} event
26999
+ */
27000
+ focusOut: function(event) {
27001
+ sendAction('focus-out', this, event);
26247
27002
  },
26248
27003
 
26249
27004
  /**
@@ -26256,22 +27011,35 @@ Ember.TextField = Ember.View.extend(Ember.TextSupport,
26256
27011
  @param {Event} event
26257
27012
  */
26258
27013
  keyPress: function(event) {
26259
- sendAction('keyPress', this, event);
27014
+ sendAction('key-press', this, event);
26260
27015
  }
27016
+
26261
27017
  });
26262
27018
 
27019
+ Ember.TextSupport.KEY_EVENTS = {
27020
+ 13: 'insertNewline',
27021
+ 27: 'cancel'
27022
+ };
27023
+
27024
+ // In principle, this shouldn't be necessary, but the legacy
27025
+ // sectionAction semantics for TextField are different from
27026
+ // the component semantics so this method normalizes them.
26263
27027
  function sendAction(eventName, view, event) {
26264
- var action = get(view, 'action'),
26265
- on = get(view, 'onEvent');
27028
+ var action = get(view, eventName),
27029
+ on = get(view, 'onEvent'),
27030
+ value = get(view, 'value');
26266
27031
 
26267
- if (action && on === eventName) {
26268
- var controller = get(view, 'controller'),
26269
- value = get(view, 'value'),
26270
- bubbles = get(view, 'bubbles');
27032
+ // back-compat support for keyPress as an event name even though
27033
+ // it's also a method name that consumes the event (and therefore
27034
+ // incompatible with sendAction semantics).
27035
+ if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) {
27036
+ view.sendAction('action', value);
27037
+ }
26271
27038
 
26272
- controller.send(action, value, view);
27039
+ view.sendAction(eventName, value);
26273
27040
 
26274
- if (!bubbles) {
27041
+ if (action || on === eventName) {
27042
+ if(!get(view, 'bubbles')) {
26275
27043
  event.stopPropagation();
26276
27044
  }
26277
27045
  }
@@ -26281,6 +27049,81 @@ function sendAction(eventName, view, event) {
26281
27049
 
26282
27050
 
26283
27051
 
27052
+ (function() {
27053
+ /**
27054
+ @module ember
27055
+ @submodule ember-handlebars
27056
+ */
27057
+
27058
+ var get = Ember.get, set = Ember.set;
27059
+
27060
+ /**
27061
+
27062
+ The internal class used to create text inputs when the `{{input}}`
27063
+ helper is used with `type` of `text`.
27064
+
27065
+ See Handlebars.helpers.input for usage details.
27066
+
27067
+ ## Layout and LayoutName properties
27068
+
27069
+ Because HTML `input` elements are self closing `layout` and `layoutName`
27070
+ properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s
27071
+ layout section for more information.
27072
+
27073
+ @class TextField
27074
+ @namespace Ember
27075
+ @extends Ember.View
27076
+ @uses Ember.TextSupport
27077
+ */
27078
+ Ember.TextField = Ember.Component.extend(Ember.TextSupport,
27079
+ /** @scope Ember.TextField.prototype */ {
27080
+
27081
+ classNames: ['ember-text-field'],
27082
+ tagName: "input",
27083
+ attributeBindings: ['type', 'value', 'size', 'pattern', 'name'],
27084
+
27085
+ /**
27086
+ The `value` attribute of the input element. As the user inputs text, this
27087
+ property is updated live.
27088
+
27089
+ @property value
27090
+ @type String
27091
+ @default ""
27092
+ */
27093
+ value: "",
27094
+
27095
+ /**
27096
+ The `type` attribute of the input element.
27097
+
27098
+ @property type
27099
+ @type String
27100
+ @default "text"
27101
+ */
27102
+ type: "text",
27103
+
27104
+ /**
27105
+ The `size` of the text field in characters.
27106
+
27107
+ @property size
27108
+ @type String
27109
+ @default null
27110
+ */
27111
+ size: null,
27112
+
27113
+ /**
27114
+ The `pattern` the pattern attribute of input element.
27115
+
27116
+ @property pattern
27117
+ @type String
27118
+ @default null
27119
+ */
27120
+ pattern: null
27121
+ });
27122
+
27123
+ })();
27124
+
27125
+
27126
+
26284
27127
  (function() {
26285
27128
  /*
26286
27129
  @module ember
@@ -26434,7 +27277,7 @@ var get = Ember.get, set = Ember.set;
26434
27277
  @extends Ember.View
26435
27278
  @uses Ember.TextSupport
26436
27279
  */
26437
- Ember.TextArea = Ember.View.extend(Ember.TextSupport, {
27280
+ Ember.TextArea = Ember.Component.extend(Ember.TextSupport, {
26438
27281
  classNames: ['ember-text-area'],
26439
27282
 
26440
27283
  tagName: "textarea",
@@ -28975,8 +29818,6 @@ define("router",
28975
29818
 
28976
29819
  var params = paramsForHandler(router, handlerName, objects);
28977
29820
 
28978
- transition.providedModelsArray = [];
28979
- transition.providedContexts = {};
28980
29821
  router.currentParams = params;
28981
29822
 
28982
29823
  var urlMethod = transition.urlMethod;
@@ -29593,6 +30434,7 @@ Ember.Router = Ember.Object.extend({
29593
30434
  if (passedName.charAt(0) === '/') {
29594
30435
  name = passedName;
29595
30436
  } else {
30437
+
29596
30438
  if (!this.router.hasRoute(passedName)) {
29597
30439
  name = args[0] = passedName + '.index';
29598
30440
  } else {
@@ -29611,6 +30453,8 @@ Ember.Router = Ember.Object.extend({
29611
30453
 
29612
30454
  transitionPromise.then(function(route) {
29613
30455
  self._transitionCompleted(route);
30456
+ }, function(error){
30457
+ Ember.assert("The URL '" + error.message + "' did match any routes in your application", error.name !== "UnrecognizedURLError");
29614
30458
  });
29615
30459
 
29616
30460
  // We want to return the configurable promise object
@@ -29672,7 +30516,7 @@ function triggerEvent(handlerInfos, ignoreFailure, args) {
29672
30516
  return;
29673
30517
  }
29674
30518
  } else if (handler.events && handler.events[name]) {
29675
- Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object', false);
30519
+ Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object (' + name + ' on ' + handler + ')', false);
29676
30520
  if (handler.events[name].apply(handler, args) === true) {
29677
30521
  eventWasHandled = true;
29678
30522
  } else {
@@ -29820,18 +30664,81 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, {
29820
30664
  this.send('playMusic');
29821
30665
  ```
29822
30666
 
30667
+ Within a route's action handler, the value of the `this` context
30668
+ is the Route object:
30669
+
30670
+ ```js
30671
+ App.SongRoute = Ember.Route.extend({
30672
+ actions: {
30673
+ myAction: function() {
30674
+ this.controllerFor("song");
30675
+ this.transitionTo("other.route");
30676
+ ...
30677
+ }
30678
+ }
30679
+ });
30680
+ ```
30681
+
29823
30682
  It is also possible to call `this._super()` from within an
29824
- action handler if it overrides a handle defined on a parent
29825
- class or mixin.
30683
+ action handler if it overrides a handler defined on a parent
30684
+ class or mixin:
29826
30685
 
29827
- Within a route's action handler, the value of the `this` context
29828
- is the Route object.
30686
+ Take for example the following routes:
30687
+
30688
+ ```js
30689
+ App.DebugRoute = Ember.Mixin.create({
30690
+ actions: {
30691
+ debugRouteInformation: function() {
30692
+ console.debug("trololo");
30693
+ }
30694
+ }
30695
+ });
30696
+
30697
+ App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, {
30698
+ actions: {
30699
+ debugRouteInformation: function() {
30700
+ // also call the debugRouteInformation of mixed in App.DebugRoute
30701
+ this._super();
30702
+
30703
+ // show additional annoyance
30704
+ window.alert(...);
30705
+ }
30706
+ }
30707
+ });
30708
+ ```
29829
30709
 
29830
30710
  ## Bubbling
29831
30711
 
29832
30712
  By default, an action will stop bubbling once a handler defined
29833
30713
  on the `actions` hash handles it. To continue bubbling the action,
29834
- you must return `true` from the handler.
30714
+ you must return `true` from the handler:
30715
+
30716
+ ```js
30717
+ App.Router.map(function() {
30718
+ this.resource("album", function() {
30719
+ this.route("song");
30720
+ });
30721
+ });
30722
+
30723
+ App.AlbumRoute = Ember.Route.extend({
30724
+ actions: {
30725
+ startPlaying: function() {
30726
+ }
30727
+ }
30728
+ });
30729
+
30730
+ App.AlbumSongRoute = Ember.Route.extend({
30731
+ actions: {
30732
+ startPlaying: function() {
30733
+ // ...
30734
+
30735
+ if (actionShouldAlsoBeTriggeredOnParentRoute) {
30736
+ return true;
30737
+ }
30738
+ }
30739
+ }
30740
+ });
30741
+ ```
29835
30742
 
29836
30743
  ## Built-in actions
29837
30744
 
@@ -30299,13 +31206,49 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, {
30299
31206
  if (!name && sawParams) { return params; }
30300
31207
  else if (!name) { return; }
30301
31208
 
30302
- var modelClass = this.container.lookupFactory('model:' + name).superclass;
30303
- var namespace = get(this, 'router.namespace');
31209
+ return this.findModel(name, value);
31210
+ },
31211
+
31212
+ /**
30304
31213
 
30305
- Ember.assert("You used the dynamic segment " + name + "_id in your router, but " + namespace + "." + classify(name) + " did not exist and you did not override your route's `model` hook.", modelClass);
30306
- return modelClass.find(value);
31214
+ @method findModel
31215
+ @param {String} type the model type
31216
+ @param {Object} value the value passed to find
31217
+ */
31218
+ findModel: function(){
31219
+ var store = get(this, 'store');
31220
+ return store.find.apply(store, arguments);
30307
31221
  },
30308
31222
 
31223
+ /**
31224
+ Store property provides a hook for data persistence libraries to inject themselves.
31225
+
31226
+ By default, this store property provides the exact same functionality previously
31227
+ in the model hook.
31228
+
31229
+ Currently, the required interface is:
31230
+
31231
+ `store.find(modelName, findArguments)`
31232
+
31233
+ @method store
31234
+ @param {Object} store
31235
+ */
31236
+ store: Ember.computed(function(){
31237
+ var container = this.container;
31238
+ var routeName = this.routeName;
31239
+ var namespace = get(this, 'router.namespace');
31240
+
31241
+ return {
31242
+ find: function(name, value) {
31243
+ var modelClass = container.lookupFactory('model:' + name);
31244
+
31245
+ Ember.assert("You used the dynamic segment " + name + "_id in your route "+ routeName + ", but " + namespace + "." + classify(name) + " did not exist and you did not override your route's `model` hook.", modelClass);
31246
+
31247
+ return modelClass.find(value);
31248
+ }
31249
+ };
31250
+ }),
31251
+
30309
31252
  /**
30310
31253
  A hook you can implement to convert the route's model into parameters
30311
31254
  for the URL.
@@ -30328,8 +31271,10 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, {
30328
31271
  });
30329
31272
  ```
30330
31273
 
30331
- The default `serialize` method inserts the model's `id` into the
30332
- route's dynamic segment (in this case, `:post_id`).
31274
+ The default `serialize` method will insert the model's `id` into the
31275
+ route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
31276
+ If the route has multiple dynamic segments or does not contain '_id', `serialize`
31277
+ will return `Ember.getProperties(model, params)`
30333
31278
 
30334
31279
  This method is called when `transitionTo` is called with a context
30335
31280
  in order to populate the URL.
@@ -30612,13 +31557,18 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, {
30612
31557
  name = this.routeName;
30613
31558
  }
30614
31559
 
31560
+ options = options || {};
30615
31561
  name = name ? name.replace(/\//g, '.') : this.routeName;
30616
- var viewName = this.viewName || name;
31562
+ var viewName = options.view || this.viewName || name;
30617
31563
  var templateName = this.templateName || name;
30618
31564
 
30619
31565
  var container = this.container,
30620
31566
  view = container.lookup('view:' + viewName),
30621
- template = container.lookup('template:' + templateName);
31567
+ template = view ? view.get('template') : null;
31568
+
31569
+ if (!template) {
31570
+ template = container.lookup('template:' + templateName);
31571
+ }
30622
31572
 
30623
31573
  if (!view && !template) {
30624
31574
  Ember.assert("Could not find \"" + name + "\" template or view.", !namePassed);
@@ -30746,7 +31696,7 @@ function normalizeOptions(route, name, template, options) {
30746
31696
  } else if (namedController = route.container.lookup('controller:' + name)) {
30747
31697
  controller = namedController;
30748
31698
  } else {
30749
- controller = route.routeName;
31699
+ controller = route.controllerName || route.routeName;
30750
31700
  }
30751
31701
 
30752
31702
  if (typeof controller === 'string') {
@@ -30828,7 +31778,7 @@ Ember.onLoad('Ember.Handlebars', function() {
30828
31778
  handlebarsGet = Ember.Handlebars.get;
30829
31779
 
30830
31780
  function resolveParams(context, params, options) {
30831
- return resolvePaths(context, params, options).map(function(path, i) {
31781
+ return map.call(resolvePaths(context, params, options), function(path, i) {
30832
31782
  if (null === path) {
30833
31783
  // Param was string/number, not a path, so just return raw string/number.
30834
31784
  return params[i];
@@ -31075,7 +32025,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
31075
32025
  whenever the helpers
31076
32026
  */
31077
32027
  _paramsChanged: function() {
31078
- this.notifyPropertyChange('routeArgs');
32028
+ this.notifyPropertyChange('resolvedParams');
31079
32029
  },
31080
32030
 
31081
32031
  /**
@@ -31120,13 +32070,14 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
31120
32070
  var router = get(this, 'router'),
31121
32071
  routeArgs = get(this, 'routeArgs'),
31122
32072
  contexts = routeArgs.slice(1),
31123
- currentWhen = this.currentWhen || routeArgs[0],
32073
+ resolvedParams = get(this, 'resolvedParams'),
32074
+ currentWhen = this.currentWhen || resolvedParams[0],
31124
32075
  currentWithIndex = currentWhen + '.index',
31125
32076
  isActive = router.isActive.apply(router, [currentWhen].concat(contexts)) ||
31126
32077
  router.isActive.apply(router, [currentWithIndex].concat(contexts));
31127
32078
 
31128
32079
  if (isActive) { return get(this, 'activeClass'); }
31129
- }).property('routeArgs', 'router.url'),
32080
+ }).property('resolvedParams', 'routeArgs', 'router.url'),
31130
32081
 
31131
32082
  /**
31132
32083
  Accessed as a classname binding to apply the `LinkView`'s `loadingClass`
@@ -31185,6 +32136,23 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
31185
32136
  }
31186
32137
  },
31187
32138
 
32139
+ /**
32140
+ @private
32141
+
32142
+ Computed property that returns the resolved parameters.
32143
+
32144
+ @property
32145
+ @return {Array}
32146
+ */
32147
+ resolvedParams: Ember.computed(function() {
32148
+ var parameters = this.parameters,
32149
+ options = parameters.options,
32150
+ types = options.types,
32151
+ data = options.data;
32152
+
32153
+ return resolveParams(parameters.context, parameters.params, { types: types, data: data });
32154
+ }).property(),
32155
+
31188
32156
  /**
31189
32157
  @private
31190
32158
 
@@ -31196,11 +32164,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
31196
32164
  */
31197
32165
  routeArgs: Ember.computed(function() {
31198
32166
 
31199
- var parameters = this.parameters,
31200
- options = parameters.options,
31201
- types = options.types,
31202
- data = options.data,
31203
- resolvedParams = resolveParams(parameters.context, parameters.params, { types: types, data: data }),
32167
+ var resolvedParams = get(this, 'resolvedParams').slice(0),
31204
32168
  router = get(this, 'router'),
31205
32169
  namedRoute = resolvedParams[0];
31206
32170
 
@@ -31220,7 +32184,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
31220
32184
  }
31221
32185
 
31222
32186
  return resolvedParams;
31223
- }).property(),
32187
+ }).property('resolvedParams'),
31224
32188
 
31225
32189
  /**
31226
32190
  Sets the element's `href` attribute to the url for
@@ -32948,7 +33912,6 @@ Ember Routing
32948
33912
 
32949
33913
  @module ember
32950
33914
  @submodule ember-routing
32951
- @requires ember-states
32952
33915
  @requires ember-views
32953
33916
  */
32954
33917
 
@@ -34178,11 +35141,8 @@ Ember.runLoadHooks('Ember.Application', Ember.Application);
34178
35141
 
34179
35142
  var get = Ember.get, set = Ember.set;
34180
35143
 
34181
- function verifyDependencies(controller) {
34182
- var needs = get(controller, 'needs'),
34183
- container = get(controller, 'container'),
34184
- satisfied = true,
34185
- dependency, i, l;
35144
+ function verifyNeedsDependencies(controller, container, needs) {
35145
+ var dependency, i, l;
34186
35146
 
34187
35147
  for (i=0, l=needs.length; i<l; i++) {
34188
35148
  dependency = needs[i];
@@ -34190,26 +35150,11 @@ function verifyDependencies(controller) {
34190
35150
  dependency = "controller:" + dependency;
34191
35151
  }
34192
35152
 
35153
+ // Structure assert to still do verification but not string concat in production
34193
35154
  if (!container.has(dependency)) {
34194
- satisfied = false;
34195
- Ember.assert(controller + " needs " + dependency + " but it does not exist", false);
35155
+ Ember.assert(Ember.inspect(controller) + " needs " + dependency + " but it does not exist", false);
34196
35156
  }
34197
35157
  }
34198
-
34199
- if (l > 0) {
34200
- set(controller, 'controllers', {
34201
- unknownProperty: function(controllerName) {
34202
- var dependency, i, l;
34203
- for (i=0, l=needs.length; i<l; i++) {
34204
- dependency = needs[i];
34205
- if (dependency === controllerName) {
34206
- return container.lookup('controller:' + controllerName);
34207
- }
34208
- }
34209
- }
34210
- });
34211
- }
34212
- return satisfied;
34213
35158
  }
34214
35159
 
34215
35160
  /**
@@ -34248,12 +35193,17 @@ Ember.ControllerMixin.reopen({
34248
35193
  needs: [],
34249
35194
 
34250
35195
  init: function() {
34251
- this._super.apply(this, arguments);
35196
+ var needs = get(this, 'needs'),
35197
+ length = get(needs, 'length');
35198
+
35199
+ if (length > 0) {
35200
+ verifyNeedsDependencies(this, this.container, needs);
34252
35201
 
34253
- // Structure asserts to still do verification but not string concat in production
34254
- if (!verifyDependencies(this)) {
34255
- Ember.assert("Missing dependencies", false);
35202
+ // if needs then initialize controllers proxy
35203
+ get(this, 'controllers');
34256
35204
  }
35205
+
35206
+ this._super.apply(this, arguments);
34257
35207
  },
34258
35208
 
34259
35209
  controllerFor: function(controllerName) {
@@ -34263,7 +35213,7 @@ Ember.ControllerMixin.reopen({
34263
35213
 
34264
35214
  /**
34265
35215
  Stores the instances of other controllers available from within
34266
- this controller. Any controller listed by name in the `needs`
35216
+ this controller. Any controller listed by name in the `needs`
34267
35217
  property will be accessible by name through this property.
34268
35218
 
34269
35219
  ```javascript
@@ -34275,398 +35225,32 @@ Ember.ControllerMixin.reopen({
34275
35225
  }.property('controllers.post.title')
34276
35226
  });
34277
35227
  ```
34278
-
35228
+
34279
35229
  @see {Ember.ControllerMixin#needs}
34280
35230
  @property {Object} controllers
34281
35231
  @default null
34282
35232
  */
34283
- controllers: null
34284
- });
34285
-
34286
- })();
34287
-
34288
-
34289
-
34290
- (function() {
34291
-
34292
- })();
34293
-
34294
-
34295
-
34296
- (function() {
34297
- /**
34298
- Ember Application
34299
-
34300
- @module ember
34301
- @submodule ember-application
34302
- @requires ember-views, ember-states, ember-routing
34303
- */
34304
-
34305
- })();
34306
-
34307
- (function() {
34308
- var get = Ember.get, set = Ember.set;
34309
-
34310
- /**
34311
- @module ember
34312
- @submodule ember-states
34313
- */
34314
-
34315
- /**
34316
- The State class allows you to define individual states within a finite state machine
34317
- inside your Ember application.
34318
-
34319
- ### How States Work
34320
-
34321
- When you setup a finite state machine this means you are setting up a mechanism to precisely
34322
- manage the change within a system. You can control the various states or modes that your
34323
- application can be in at any given time. Additionally, you can manage what specific states
34324
- are allowed to transition to other states.
34325
-
34326
- The state machine is in only one state at a time. This state is known as the current state.
34327
- It is possible to change from one state to another by a triggering event or condition.
34328
- This is called a transition.
34329
-
34330
- Finite state machines are important because they allow the application developer to be
34331
- deterministic about the the sequence of events that can happen within a system. Some states
34332
- cannot be entered when the application is a given state.
34333
-
34334
- For example:
34335
-
34336
- A door that is in the `locked` state cannot be `opened` (you must transition to the `unlocked`
34337
- state first).
34338
-
34339
- A door that is in the `open` state cannot be `locked` (you must transition to the `closed`
34340
- state first).
34341
-
34342
-
34343
- Each state instance has the following characteristics:
34344
-
34345
- - Zero or more parent states
34346
- - A start state
34347
- - A name
34348
- - A path (a computed value that prefixes parent states and the complete hierarchy to itself )
34349
-
34350
- A state is known as a "leafState" when it is the last item on the path and has no children
34351
- beneath it.
34352
-
34353
- The isLeaf property returns a boolean.
34354
-
34355
- Each state can emit the following transition events
34356
-
34357
- - setup
34358
- - enter
34359
- - exit
34360
-
34361
- A state object is ususally created in the context of a state manager.
34362
-
34363
- ```javascript
34364
- doorStateManager = Ember.StateManager.create({
34365
- locked: Ember.State.create(),
34366
- closed: Ember.State.create(),
34367
- unlocked: Ember.State.create(),
34368
- open: Ember.State.create()
34369
- });
34370
- ```
34371
-
34372
- @class State
34373
- @namespace Ember
34374
- @extends Ember.Object
34375
- @uses Ember.Evented
34376
- */
34377
- Ember.State = Ember.Object.extend(Ember.Evented,
34378
- /** @scope Ember.State.prototype */{
34379
- /**
34380
- A reference to the parent state.
34381
-
34382
- @property parentState
34383
- @type Ember.State
34384
- */
34385
- parentState: null,
34386
- start: null,
34387
-
34388
- /**
34389
- The name of this state.
34390
-
34391
- @property name
34392
- @type String
34393
- */
34394
- name: null,
34395
-
34396
- /**
34397
- The full path to this state.
34398
-
34399
- @property path
34400
- @type String
34401
- */
34402
- path: Ember.computed(function() {
34403
- var parentPath = get(this, 'parentState.path'),
34404
- path = get(this, 'name');
34405
-
34406
- if (parentPath) {
34407
- path = parentPath + '.' + path;
34408
- }
34409
-
34410
- return path;
34411
- }),
34412
-
34413
- /**
34414
- @private
34415
-
34416
- Override the default event firing from `Ember.Evented` to
34417
- also call methods with the given name.
34418
-
34419
- @method trigger
34420
- @param name
34421
- */
34422
- trigger: function(name) {
34423
- if (this[name]) {
34424
- this[name].apply(this, [].slice.call(arguments, 1));
34425
- }
34426
- this._super.apply(this, arguments);
34427
- },
34428
-
34429
- /**
34430
- Initialize Ember.State object
34431
- Sets childStates to Ember.NativeArray
34432
- Sets eventTransitions to empty object unless already defined.
34433
- Loops over properties of this state and ensures that any property that
34434
- is an instance of Ember.State is moved to `states` hash.
34435
-
34436
-
34437
- @method init
34438
- */
34439
- init: function() {
34440
- var states = get(this, 'states');
34441
- set(this, 'childStates', Ember.A());
34442
- set(this, 'eventTransitions', get(this, 'eventTransitions') || {});
34443
-
34444
- var name, value, transitionTarget;
34445
-
34446
- // As a convenience, loop over the properties
34447
- // of this state and look for any that are other
34448
- // Ember.State instances or classes, and move them
34449
- // to the `states` hash. This avoids having to
34450
- // create an explicit separate hash.
34451
-
34452
- if (!states) {
34453
- states = {};
34454
-
34455
- for (name in this) {
34456
- if (name === "constructor") { continue; }
35233
+ controllers: Ember.computed(function() {
35234
+ var controller = this;
34457
35235
 
34458
- if (value = this[name]) {
34459
- if (transitionTarget = value.transitionTarget) {
34460
- this.eventTransitions[name] = transitionTarget;
35236
+ return {
35237
+ needs: get(controller, 'needs'),
35238
+ container: get(controller, 'container'),
35239
+ unknownProperty: function(controllerName) {
35240
+ var needs = this.needs,
35241
+ dependency, i, l;
35242
+ for (i=0, l=needs.length; i<l; i++) {
35243
+ dependency = needs[i];
35244
+ if (dependency === controllerName) {
35245
+ return this.container.lookup('controller:' + controllerName);
34461
35246
  }
34462
-
34463
- this.setupChild(states, name, value);
34464
35247
  }
34465
- }
34466
35248
 
34467
- set(this, 'states', states);
34468
- } else {
34469
- for (name in states) {
34470
- this.setupChild(states, name, states[name]);
35249
+ var errorMessage = Ember.inspect(controller) + '#needs does not include `' + controllerName + '`. To access the ' + controllerName + ' controller from ' + Ember.inspect(controller) + ', ' + Ember.inspect(controller) + ' should have a `needs` property that is an array of the controllers it has access to.';
35250
+ throw new ReferenceError(errorMessage);
34471
35251
  }
34472
- }
34473
-
34474
- // pathsCaches is a nested hash of the form:
34475
- // pathsCaches[stateManagerTypeGuid][path] == transitions_hash
34476
- set(this, 'pathsCaches', {});
34477
- },
34478
-
34479
- /**
34480
- Sets a cached instance of the state. Ember.guidFor is used
34481
- to find the guid of the associated state manager. If a cache can be found
34482
- the state path is added to that cache, otherwise an empty JavaScript object
34483
- is created. And the state path is appended to that instead.
34484
-
34485
- @method setPathsCache
34486
- @param stateManager
34487
- @param path
34488
- @param transitions
34489
- */
34490
- setPathsCache: function(stateManager, path, transitions) {
34491
- var stateManagerTypeGuid = Ember.guidFor(stateManager.constructor),
34492
- pathsCaches = get(this, 'pathsCaches'),
34493
- pathsCacheForManager = pathsCaches[stateManagerTypeGuid] || {};
34494
-
34495
- pathsCacheForManager[path] = transitions;
34496
- pathsCaches[stateManagerTypeGuid] = pathsCacheForManager;
34497
- },
34498
-
34499
- /**
34500
- Returns a cached path for the state instance. Each state manager
34501
- has a GUID and this is used to look up a cached path if it has already
34502
- been created. If a cached path is not found an empty JavaScript object
34503
- is returned instead.
34504
-
34505
- @method getPathsCache
34506
- @param stateManager
34507
- @param path
34508
- */
34509
- getPathsCache: function(stateManager, path) {
34510
- var stateManagerTypeGuid = Ember.guidFor(stateManager.constructor),
34511
- pathsCaches = get(this, 'pathsCaches'),
34512
- pathsCacheForManager = pathsCaches[stateManagerTypeGuid] || {};
34513
-
34514
- return pathsCacheForManager[path];
34515
- },
34516
-
34517
- /**
34518
- @private
34519
-
34520
- Create the child instance and ensure that it is an instance of Ember.State
34521
-
34522
- @method setupChild
34523
- @param states
34524
- @param name
34525
- @param value
34526
- */
34527
- setupChild: function(states, name, value) {
34528
- if (!value) { return false; }
34529
- var instance;
34530
-
34531
- if (value instanceof Ember.State) {
34532
- set(value, 'name', name);
34533
- instance = value;
34534
- instance.container = this.container;
34535
- } else if (Ember.State.detect(value)) {
34536
- instance = value.create({
34537
- name: name,
34538
- container: this.container
34539
- });
34540
- }
34541
-
34542
- if (instance instanceof Ember.State) {
34543
- set(instance, 'parentState', this);
34544
- get(this, 'childStates').pushObject(instance);
34545
- states[name] = instance;
34546
- return instance;
34547
- }
34548
- },
34549
-
34550
- /**
34551
- @private
34552
-
34553
- @method lookupEventTransition
34554
- @param name
34555
- */
34556
- lookupEventTransition: function(name) {
34557
- var path, state = this;
34558
-
34559
- while(state && !path) {
34560
- path = state.eventTransitions[name];
34561
- state = state.get('parentState');
34562
- }
34563
-
34564
- return path;
34565
- },
34566
-
34567
- /**
34568
- A Boolean value indicating whether the state is a leaf state
34569
- in the state hierarchy. This is `false` if the state has child
34570
- states; otherwise it is true.
34571
-
34572
- @property isLeaf
34573
- @type Boolean
34574
- */
34575
- isLeaf: Ember.computed(function() {
34576
- return !get(this, 'childStates').length;
34577
- }),
34578
-
34579
- /**
34580
- A boolean value indicating whether the state takes a context.
34581
- By default we assume all states take contexts.
34582
-
34583
- @property hasContext
34584
- @default true
34585
- */
34586
- hasContext: true,
34587
-
34588
- /**
34589
- This is the default transition event.
34590
-
34591
- @event setup
34592
- @param {Ember.StateManager} manager
34593
- @param context
34594
- @see Ember.StateManager#transitionEvent
34595
- */
34596
- setup: Ember.K,
34597
-
34598
- /**
34599
- This event fires when the state is entered.
34600
-
34601
- @event enter
34602
- @param {Ember.StateManager} manager
34603
- */
34604
- enter: Ember.K,
34605
-
34606
- /**
34607
- This event fires when the state is exited.
34608
-
34609
- @event exit
34610
- @param {Ember.StateManager} manager
34611
- */
34612
- exit: Ember.K
34613
- });
34614
-
34615
- Ember.State.reopenClass({
34616
-
34617
- /**
34618
- Creates an action function for transitioning to the named state while
34619
- preserving context.
34620
-
34621
- The following example StateManagers are equivalent:
34622
-
34623
- ```javascript
34624
- aManager = Ember.StateManager.create({
34625
- stateOne: Ember.State.create({
34626
- changeToStateTwo: Ember.State.transitionTo('stateTwo')
34627
- }),
34628
- stateTwo: Ember.State.create({})
34629
- })
34630
-
34631
- bManager = Ember.StateManager.create({
34632
- stateOne: Ember.State.create({
34633
- changeToStateTwo: function(manager, context) {
34634
- manager.transitionTo('stateTwo', context)
34635
- }
34636
- }),
34637
- stateTwo: Ember.State.create({})
34638
- })
34639
- ```
34640
-
34641
- @method transitionTo
34642
- @static
34643
- @param {String} target
34644
- */
34645
-
34646
- transitionTo: function(target) {
34647
-
34648
- var transitionFunction = function(stateManager, contextOrEvent) {
34649
- var contexts = [],
34650
- Event = Ember.$ && Ember.$.Event;
34651
-
34652
- if (contextOrEvent && (Event && contextOrEvent instanceof Event)) {
34653
- if (contextOrEvent.hasOwnProperty('contexts')) {
34654
- contexts = contextOrEvent.contexts.slice();
34655
- }
34656
- }
34657
- else {
34658
- contexts = [].slice.call(arguments, 1);
34659
- }
34660
-
34661
- contexts.unshift(target);
34662
- stateManager.transitionTo.apply(stateManager, contexts);
34663
35252
  };
34664
-
34665
- transitionFunction.transitionTarget = target;
34666
-
34667
- return transitionFunction;
34668
- }
34669
-
35253
+ }).readOnly()
34670
35254
  });
34671
35255
 
34672
35256
  })();
@@ -34674,1104 +35258,6 @@ Ember.State.reopenClass({
34674
35258
 
34675
35259
 
34676
35260
  (function() {
34677
- /**
34678
- @module ember
34679
- @submodule ember-states
34680
- */
34681
-
34682
- var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
34683
- var arrayForEach = Ember.ArrayPolyfills.forEach;
34684
- /**
34685
- A Transition takes the enter, exit and resolve states and normalizes
34686
- them:
34687
-
34688
- * takes any passed in contexts into consideration
34689
- * adds in `initialState`s
34690
-
34691
- @class Transition
34692
- @private
34693
- */
34694
- var Transition = function(raw) {
34695
- this.enterStates = raw.enterStates.slice();
34696
- this.exitStates = raw.exitStates.slice();
34697
- this.resolveState = raw.resolveState;
34698
-
34699
- this.finalState = raw.enterStates[raw.enterStates.length - 1] || raw.resolveState;
34700
- };
34701
-
34702
- Transition.prototype = {
34703
- /**
34704
- Normalize the passed in enter, exit and resolve states.
34705
-
34706
- This process also adds `finalState` and `contexts` to the Transition object.
34707
-
34708
- @method normalize
34709
- @param {Ember.StateManager} manager the state manager running the transition
34710
- @param {Array} contexts a list of contexts passed into `transitionTo`
34711
- */
34712
- normalize: function(manager, contexts) {
34713
- this.matchContextsToStates(contexts);
34714
- this.addInitialStates();
34715
- this.removeUnchangedContexts(manager);
34716
- return this;
34717
- },
34718
-
34719
- /**
34720
- Match each of the contexts passed to `transitionTo` to a state.
34721
- This process may also require adding additional enter and exit
34722
- states if there are more contexts than enter states.
34723
-
34724
- @method matchContextsToStates
34725
- @param {Array} contexts a list of contexts passed into `transitionTo`
34726
- */
34727
- matchContextsToStates: function(contexts) {
34728
- var stateIdx = this.enterStates.length - 1,
34729
- matchedContexts = [],
34730
- state,
34731
- context;
34732
-
34733
- // Next, we will match the passed in contexts to the states they
34734
- // represent.
34735
- //
34736
- // First, assign a context to each enter state in reverse order. If
34737
- // any contexts are left, add a parent state to the list of states
34738
- // to enter and exit, and assign a context to the parent state.
34739
- //
34740
- // If there are still contexts left when the state manager is
34741
- // reached, raise an exception.
34742
- //
34743
- // This allows the following:
34744
- //
34745
- // |- root
34746
- // | |- post
34747
- // | | |- comments
34748
- // | |- about (* current state)
34749
- //
34750
- // For `transitionTo('post.comments', post, post.get('comments')`,
34751
- // the first context (`post`) will be assigned to `root.post`, and
34752
- // the second context (`post.get('comments')`) will be assigned
34753
- // to `root.post.comments`.
34754
- //
34755
- // For the following:
34756
- //
34757
- // |- root
34758
- // | |- post
34759
- // | | |- index (* current state)
34760
- // | | |- comments
34761
- //
34762
- // For `transitionTo('post.comments', otherPost, otherPost.get('comments')`,
34763
- // the `<root.post>` state will be added to the list of enter and exit
34764
- // states because its context has changed.
34765
-
34766
- while (contexts.length > 0) {
34767
- if (stateIdx >= 0) {
34768
- state = this.enterStates[stateIdx--];
34769
- } else {
34770
- if (this.enterStates.length) {
34771
- state = get(this.enterStates[0], 'parentState');
34772
- if (!state) { throw "Cannot match all contexts to states"; }
34773
- } else {
34774
- // If re-entering the current state with a context, the resolve
34775
- // state will be the current state.
34776
- state = this.resolveState;
34777
- }
34778
-
34779
- this.enterStates.unshift(state);
34780
- this.exitStates.unshift(state);
34781
- }
34782
-
34783
- // in routers, only states with dynamic segments have a context
34784
- if (get(state, 'hasContext')) {
34785
- context = contexts.pop();
34786
- } else {
34787
- context = null;
34788
- }
34789
-
34790
- matchedContexts.unshift(context);
34791
- }
34792
-
34793
- this.contexts = matchedContexts;
34794
- },
34795
-
34796
- /**
34797
- Add any `initialState`s to the list of enter states.
34798
-
34799
- @method addInitialStates
34800
- */
34801
- addInitialStates: function() {
34802
- var finalState = this.finalState, initialState;
34803
-
34804
- while(true) {
34805
- initialState = get(finalState, 'initialState') || 'start';
34806
- finalState = get(finalState, 'states.' + initialState);
34807
-
34808
- if (!finalState) { break; }
34809
-
34810
- this.finalState = finalState;
34811
- this.enterStates.push(finalState);
34812
- this.contexts.push(undefined);
34813
- }
34814
- },
34815
-
34816
- /**
34817
- Remove any states that were added because the number of contexts
34818
- exceeded the number of explicit enter states, but the context has
34819
- not changed since the last time the state was entered.
34820
-
34821
- @method removeUnchangedContexts
34822
- @param {Ember.StateManager} manager passed in to look up the last
34823
- context for a state
34824
- */
34825
- removeUnchangedContexts: function(manager) {
34826
- // Start from the beginning of the enter states. If the state was added
34827
- // to the list during the context matching phase, make sure the context
34828
- // has actually changed since the last time the state was entered.
34829
- while (this.enterStates.length > 0) {
34830
- if (this.enterStates[0] !== this.exitStates[0]) { break; }
34831
-
34832
- if (this.enterStates.length === this.contexts.length) {
34833
- if (manager.getStateMeta(this.enterStates[0], 'context') !== this.contexts[0]) { break; }
34834
- this.contexts.shift();
34835
- }
34836
-
34837
- this.resolveState = this.enterStates.shift();
34838
- this.exitStates.shift();
34839
- }
34840
- }
34841
- };
34842
-
34843
-
34844
- /**
34845
- Sends the event to the currentState, if the event is not handled this method
34846
- will proceed to call the parentState recursively until it encounters an
34847
- event handler or reaches the top or root of the state path hierarchy.
34848
-
34849
- @method sendRecursively
34850
- @param event
34851
- @param currentState
34852
- @param isUnhandledPass
34853
- */
34854
- var sendRecursively = function(event, currentState, isUnhandledPass) {
34855
- var log = this.enableLogging,
34856
- eventName = isUnhandledPass ? 'unhandledEvent' : event,
34857
- action = currentState[eventName],
34858
- contexts, sendRecursiveArguments, actionArguments;
34859
-
34860
- contexts = [].slice.call(arguments, 3);
34861
-
34862
- // Test to see if the action is a method that
34863
- // can be invoked. Don't blindly check just for
34864
- // existence, because it is possible the state
34865
- // manager has a child state of the given name,
34866
- // and we should still raise an exception in that
34867
- // case.
34868
- if (typeof action === 'function') {
34869
- if (log) {
34870
- if (isUnhandledPass) {
34871
- Ember.Logger.log(fmt("STATEMANAGER: Unhandled event '%@' being sent to state %@.", [event, get(currentState, 'path')]));
34872
- } else {
34873
- Ember.Logger.log(fmt("STATEMANAGER: Sending event '%@' to state %@.", [event, get(currentState, 'path')]));
34874
- }
34875
- }
34876
-
34877
- actionArguments = contexts;
34878
- if (isUnhandledPass) {
34879
- actionArguments.unshift(event);
34880
- }
34881
- actionArguments.unshift(this);
34882
-
34883
- return action.apply(currentState, actionArguments);
34884
- } else {
34885
- var parentState = get(currentState, 'parentState');
34886
- if (parentState) {
34887
-
34888
- sendRecursiveArguments = contexts;
34889
- sendRecursiveArguments.unshift(event, parentState, isUnhandledPass);
34890
-
34891
- return sendRecursively.apply(this, sendRecursiveArguments);
34892
- } else if (!isUnhandledPass) {
34893
- return sendEvent.call(this, event, contexts, true);
34894
- }
34895
- }
34896
- };
34897
-
34898
- /**
34899
- Send an event to the currentState.
34900
-
34901
- @method sendEvent
34902
- @param eventName
34903
- @param sendRecursiveArguments
34904
- @param isUnhandledPass
34905
- */
34906
- var sendEvent = function(eventName, sendRecursiveArguments, isUnhandledPass) {
34907
- sendRecursiveArguments.unshift(eventName, get(this, 'currentState'), isUnhandledPass);
34908
- return sendRecursively.apply(this, sendRecursiveArguments);
34909
- };
34910
-
34911
- /**
34912
- StateManager is part of Ember's implementation of a finite state machine. A
34913
- StateManager instance manages a number of properties that are instances of
34914
- `Ember.State`,
34915
- tracks the current active state, and triggers callbacks when states have changed.
34916
-
34917
- ## Defining States
34918
-
34919
- The states of StateManager can be declared in one of two ways. First, you can
34920
- define a `states` property that contains all the states:
34921
-
34922
- ```javascript
34923
- var managerA = Ember.StateManager.create({
34924
- states: {
34925
- stateOne: Ember.State.create(),
34926
- stateTwo: Ember.State.create()
34927
- }
34928
- });
34929
-
34930
- managerA.get('states');
34931
- // {
34932
- // stateOne: Ember.State.create(),
34933
- // stateTwo: Ember.State.create()
34934
- // }
34935
- ```
34936
-
34937
- You can also add instances of `Ember.State` (or an `Ember.State` subclass)
34938
- directly as properties of a StateManager. These states will be collected into
34939
- the `states` property for you.
34940
-
34941
- ```javascript
34942
- var managerA = Ember.StateManager.create({
34943
- stateOne: Ember.State.create(),
34944
- stateTwo: Ember.State.create()
34945
- });
34946
-
34947
- managerA.get('states');
34948
- // {
34949
- // stateOne: Ember.State.create(),
34950
- // stateTwo: Ember.State.create()
34951
- // }
34952
- ```
34953
-
34954
- ## The Initial State
34955
-
34956
- When created, a StateManager instance will immediately enter into the state
34957
- defined as its `start` property or the state referenced by name in its
34958
- `initialState` property:
34959
-
34960
- ```javascript
34961
- var managerA = Ember.StateManager.create({
34962
- start: Ember.State.create({})
34963
- });
34964
-
34965
- managerA.get('currentState.name'); // 'start'
34966
-
34967
- var managerB = Ember.StateManager.create({
34968
- initialState: 'beginHere',
34969
- beginHere: Ember.State.create({})
34970
- });
34971
-
34972
- managerB.get('currentState.name'); // 'beginHere'
34973
- ```
34974
-
34975
- Because it is a property you may also provide a computed function if you wish
34976
- to derive an `initialState` programmatically:
34977
-
34978
- ```javascript
34979
- var managerC = Ember.StateManager.create({
34980
- initialState: function() {
34981
- if (someLogic) {
34982
- return 'active';
34983
- } else {
34984
- return 'passive';
34985
- }
34986
- }.property(),
34987
- active: Ember.State.create({}),
34988
- passive: Ember.State.create({})
34989
- });
34990
- ```
34991
-
34992
- ## Moving Between States
34993
-
34994
- A StateManager can have any number of `Ember.State` objects as properties
34995
- and can have a single one of these states as its current state.
34996
-
34997
- Calling `transitionTo` transitions between states:
34998
-
34999
- ```javascript
35000
- var robotManager = Ember.StateManager.create({
35001
- initialState: 'poweredDown',
35002
- poweredDown: Ember.State.create({}),
35003
- poweredUp: Ember.State.create({})
35004
- });
35005
-
35006
- robotManager.get('currentState.name'); // 'poweredDown'
35007
- robotManager.transitionTo('poweredUp');
35008
- robotManager.get('currentState.name'); // 'poweredUp'
35009
- ```
35010
-
35011
- Before transitioning into a new state the existing `currentState` will have
35012
- its `exit` method called with the StateManager instance as its first argument
35013
- and an object representing the transition as its second argument.
35014
-
35015
- After transitioning into a new state the new `currentState` will have its
35016
- `enter` method called with the StateManager instance as its first argument
35017
- and an object representing the transition as its second argument.
35018
-
35019
- ```javascript
35020
- var robotManager = Ember.StateManager.create({
35021
- initialState: 'poweredDown',
35022
- poweredDown: Ember.State.create({
35023
- exit: function(stateManager) {
35024
- console.log("exiting the poweredDown state")
35025
- }
35026
- }),
35027
- poweredUp: Ember.State.create({
35028
- enter: function(stateManager) {
35029
- console.log("entering the poweredUp state. Destroy all humans.")
35030
- }
35031
- })
35032
- });
35033
-
35034
- robotManager.get('currentState.name'); // 'poweredDown'
35035
- robotManager.transitionTo('poweredUp');
35036
-
35037
- // will log
35038
- // 'exiting the poweredDown state'
35039
- // 'entering the poweredUp state. Destroy all humans.'
35040
- ```
35041
-
35042
- Once a StateManager is already in a state, subsequent attempts to enter that
35043
- state will not trigger enter or exit method calls. Attempts to transition
35044
- into a state that the manager does not have will result in no changes in the
35045
- StateManager's current state:
35046
-
35047
- ```javascript
35048
- var robotManager = Ember.StateManager.create({
35049
- initialState: 'poweredDown',
35050
- poweredDown: Ember.State.create({
35051
- exit: function(stateManager) {
35052
- console.log("exiting the poweredDown state")
35053
- }
35054
- }),
35055
- poweredUp: Ember.State.create({
35056
- enter: function(stateManager) {
35057
- console.log("entering the poweredUp state. Destroy all humans.")
35058
- }
35059
- })
35060
- });
35061
-
35062
- robotManager.get('currentState.name'); // 'poweredDown'
35063
- robotManager.transitionTo('poweredUp');
35064
- // will log
35065
- // 'exiting the poweredDown state'
35066
- // 'entering the poweredUp state. Destroy all humans.'
35067
- robotManager.transitionTo('poweredUp'); // no logging, no state change
35068
-
35069
- robotManager.transitionTo('someUnknownState'); // silently fails
35070
- robotManager.get('currentState.name'); // 'poweredUp'
35071
- ```
35072
-
35073
- Each state property may itself contain properties that are instances of
35074
- `Ember.State`. The StateManager can transition to specific sub-states in a
35075
- series of transitionTo method calls or via a single transitionTo with the
35076
- full path to the specific state. The StateManager will also keep track of the
35077
- full path to its currentState
35078
-
35079
- ```javascript
35080
- var robotManager = Ember.StateManager.create({
35081
- initialState: 'poweredDown',
35082
- poweredDown: Ember.State.create({
35083
- charging: Ember.State.create(),
35084
- charged: Ember.State.create()
35085
- }),
35086
- poweredUp: Ember.State.create({
35087
- mobile: Ember.State.create(),
35088
- stationary: Ember.State.create()
35089
- })
35090
- });
35091
-
35092
- robotManager.get('currentState.name'); // 'poweredDown'
35093
-
35094
- robotManager.transitionTo('poweredUp');
35095
- robotManager.get('currentState.name'); // 'poweredUp'
35096
-
35097
- robotManager.transitionTo('mobile');
35098
- robotManager.get('currentState.name'); // 'mobile'
35099
-
35100
- // transition via a state path
35101
- robotManager.transitionTo('poweredDown.charging');
35102
- robotManager.get('currentState.name'); // 'charging'
35103
-
35104
- robotManager.get('currentState.path'); // 'poweredDown.charging'
35105
- ```
35106
-
35107
- Enter transition methods will be called for each state and nested child state
35108
- in their hierarchical order. Exit methods will be called for each state and
35109
- its nested states in reverse hierarchical order.
35110
-
35111
- Exit transitions for a parent state are not called when entering into one of
35112
- its child states, only when transitioning to a new section of possible states
35113
- in the hierarchy.
35114
-
35115
- ```javascript
35116
- var robotManager = Ember.StateManager.create({
35117
- initialState: 'poweredDown',
35118
- poweredDown: Ember.State.create({
35119
- enter: function() {},
35120
- exit: function() {
35121
- console.log("exited poweredDown state")
35122
- },
35123
- charging: Ember.State.create({
35124
- enter: function() {},
35125
- exit: function() {}
35126
- }),
35127
- charged: Ember.State.create({
35128
- enter: function() {
35129
- console.log("entered charged state")
35130
- },
35131
- exit: function() {
35132
- console.log("exited charged state")
35133
- }
35134
- })
35135
- }),
35136
- poweredUp: Ember.State.create({
35137
- enter: function() {
35138
- console.log("entered poweredUp state")
35139
- },
35140
- exit: function() {},
35141
- mobile: Ember.State.create({
35142
- enter: function() {
35143
- console.log("entered mobile state")
35144
- },
35145
- exit: function() {}
35146
- }),
35147
- stationary: Ember.State.create({
35148
- enter: function() {},
35149
- exit: function() {}
35150
- })
35151
- })
35152
- });
35153
-
35154
-
35155
- robotManager.get('currentState.path'); // 'poweredDown'
35156
- robotManager.transitionTo('charged');
35157
- // logs 'entered charged state'
35158
- // but does *not* log 'exited poweredDown state'
35159
- robotManager.get('currentState.name'); // 'charged
35160
-
35161
- robotManager.transitionTo('poweredUp.mobile');
35162
- // logs
35163
- // 'exited charged state'
35164
- // 'exited poweredDown state'
35165
- // 'entered poweredUp state'
35166
- // 'entered mobile state'
35167
- ```
35168
-
35169
- During development you can set a StateManager's `enableLogging` property to
35170
- `true` to receive console messages of state transitions.
35171
-
35172
- ```javascript
35173
- var robotManager = Ember.StateManager.create({
35174
- enableLogging: true
35175
- });
35176
- ```
35177
-
35178
- ## Managing currentState with Actions
35179
-
35180
- To control which transitions are possible for a given state, and
35181
- appropriately handle external events, the StateManager can receive and
35182
- route action messages to its states via the `send` method. Calling to
35183
- `send` with an action name will begin searching for a method with the same
35184
- name starting at the current state and moving up through the parent states
35185
- in a state hierarchy until an appropriate method is found or the StateManager
35186
- instance itself is reached.
35187
-
35188
- If an appropriately named method is found it will be called with the state
35189
- manager as the first argument and an optional `context` object as the second
35190
- argument.
35191
-
35192
- ```javascript
35193
- var managerA = Ember.StateManager.create({
35194
- initialState: 'stateOne.substateOne.subsubstateOne',
35195
- stateOne: Ember.State.create({
35196
- substateOne: Ember.State.create({
35197
- anAction: function(manager, context) {
35198
- console.log("an action was called")
35199
- },
35200
- subsubstateOne: Ember.State.create({})
35201
- })
35202
- })
35203
- });
35204
-
35205
- managerA.get('currentState.name'); // 'subsubstateOne'
35206
- managerA.send('anAction');
35207
- // 'stateOne.substateOne.subsubstateOne' has no anAction method
35208
- // so the 'anAction' method of 'stateOne.substateOne' is called
35209
- // and logs "an action was called"
35210
- // with managerA as the first argument
35211
- // and no second argument
35212
-
35213
- var someObject = {};
35214
- managerA.send('anAction', someObject);
35215
- // the 'anAction' method of 'stateOne.substateOne' is called again
35216
- // with managerA as the first argument and
35217
- // someObject as the second argument.
35218
- ```
35219
-
35220
- If the StateManager attempts to send an action but does not find an appropriately named
35221
- method in the current state or while moving upwards through the state hierarchy, it will
35222
- repeat the process looking for a `unhandledEvent` method. If an `unhandledEvent` method is
35223
- found, it will be called with the original event name as the second argument. If an
35224
- `unhandledEvent` method is not found, the StateManager will throw a new Ember.Error.
35225
-
35226
- ```javascript
35227
- var managerB = Ember.StateManager.create({
35228
- initialState: 'stateOne.substateOne.subsubstateOne',
35229
- stateOne: Ember.State.create({
35230
- substateOne: Ember.State.create({
35231
- subsubstateOne: Ember.State.create({}),
35232
- unhandledEvent: function(manager, eventName, context) {
35233
- console.log("got an unhandledEvent with name " + eventName);
35234
- }
35235
- })
35236
- })
35237
- });
35238
-
35239
- managerB.get('currentState.name'); // 'subsubstateOne'
35240
- managerB.send('anAction');
35241
- // neither `stateOne.substateOne.subsubstateOne` nor any of it's
35242
- // parent states have a handler for `anAction`. `subsubstateOne`
35243
- // also does not have a `unhandledEvent` method, but its parent
35244
- // state, `substateOne`, does, and it gets fired. It will log
35245
- // "got an unhandledEvent with name anAction"
35246
- ```
35247
-
35248
- Action detection only moves upwards through the state hierarchy from the current state.
35249
- It does not search in other portions of the hierarchy.
35250
-
35251
- ```javascript
35252
- var managerC = Ember.StateManager.create({
35253
- initialState: 'stateOne.substateOne.subsubstateOne',
35254
- stateOne: Ember.State.create({
35255
- substateOne: Ember.State.create({
35256
- subsubstateOne: Ember.State.create({})
35257
- })
35258
- }),
35259
- stateTwo: Ember.State.create({
35260
- anAction: function(manager, context) {
35261
- // will not be called below because it is
35262
- // not a parent of the current state
35263
- }
35264
- })
35265
- });
35266
-
35267
- managerC.get('currentState.name'); // 'subsubstateOne'
35268
- managerC.send('anAction');
35269
- // Error: <Ember.StateManager:ember132> could not
35270
- // respond to event anAction in state stateOne.substateOne.subsubstateOne.
35271
- ```
35272
-
35273
- Inside of an action method the given state should delegate `transitionTo` calls on its
35274
- StateManager.
35275
-
35276
- ```javascript
35277
- var robotManager = Ember.StateManager.create({
35278
- initialState: 'poweredDown.charging',
35279
- poweredDown: Ember.State.create({
35280
- charging: Ember.State.create({
35281
- chargeComplete: function(manager, context) {
35282
- manager.transitionTo('charged')
35283
- }
35284
- }),
35285
- charged: Ember.State.create({
35286
- boot: function(manager, context) {
35287
- manager.transitionTo('poweredUp')
35288
- }
35289
- })
35290
- }),
35291
- poweredUp: Ember.State.create({
35292
- beginExtermination: function(manager, context) {
35293
- manager.transitionTo('rampaging')
35294
- },
35295
- rampaging: Ember.State.create()
35296
- })
35297
- });
35298
-
35299
- robotManager.get('currentState.name'); // 'charging'
35300
- robotManager.send('boot'); // throws error, no boot action
35301
- // in current hierarchy
35302
- robotManager.get('currentState.name'); // remains 'charging'
35303
-
35304
- robotManager.send('beginExtermination'); // throws error, no beginExtermination
35305
- // action in current hierarchy
35306
- robotManager.get('currentState.name'); // remains 'charging'
35307
-
35308
- robotManager.send('chargeComplete');
35309
- robotManager.get('currentState.name'); // 'charged'
35310
-
35311
- robotManager.send('boot');
35312
- robotManager.get('currentState.name'); // 'poweredUp'
35313
-
35314
- robotManager.send('beginExtermination', allHumans);
35315
- robotManager.get('currentState.name'); // 'rampaging'
35316
- ```
35317
-
35318
- Transition actions can also be created using the `transitionTo` method of the `Ember.State` class. The
35319
- following example StateManagers are equivalent:
35320
-
35321
- ```javascript
35322
- var aManager = Ember.StateManager.create({
35323
- stateOne: Ember.State.create({
35324
- changeToStateTwo: Ember.State.transitionTo('stateTwo')
35325
- }),
35326
- stateTwo: Ember.State.create({})
35327
- });
35328
-
35329
- var bManager = Ember.StateManager.create({
35330
- stateOne: Ember.State.create({
35331
- changeToStateTwo: function(manager, context) {
35332
- manager.transitionTo('stateTwo', context)
35333
- }
35334
- }),
35335
- stateTwo: Ember.State.create({})
35336
- });
35337
- ```
35338
-
35339
- @class StateManager
35340
- @namespace Ember
35341
- @extends Ember.State
35342
- **/
35343
- Ember.StateManager = Ember.State.extend({
35344
- /**
35345
- @private
35346
-
35347
- When creating a new statemanager, look for a default state to transition
35348
- into. This state can either be named `start`, or can be specified using the
35349
- `initialState` property.
35350
-
35351
- @method init
35352
- */
35353
- init: function() {
35354
- this._super();
35355
-
35356
- set(this, 'stateMeta', Ember.Map.create());
35357
-
35358
- var initialState = get(this, 'initialState');
35359
-
35360
- if (!initialState && get(this, 'states.start')) {
35361
- initialState = 'start';
35362
- }
35363
-
35364
- if (initialState) {
35365
- this.transitionTo(initialState);
35366
- Ember.assert('Failed to transition to initial state "' + initialState + '"', !!get(this, 'currentState'));
35367
- }
35368
- },
35369
-
35370
- /**
35371
- Return the stateMeta, a hash of possible states. If no items exist in the stateMeta hash
35372
- this method sets the stateMeta to an empty JavaScript object and returns that instead.
35373
-
35374
- @method stateMetaFor
35375
- @param state
35376
- */
35377
- stateMetaFor: function(state) {
35378
- var meta = get(this, 'stateMeta'),
35379
- stateMeta = meta.get(state);
35380
-
35381
- if (!stateMeta) {
35382
- stateMeta = {};
35383
- meta.set(state, stateMeta);
35384
- }
35385
-
35386
- return stateMeta;
35387
- },
35388
-
35389
- /**
35390
- Sets a key value pair on the stateMeta hash.
35391
-
35392
- @method setStateMeta
35393
- @param state
35394
- @param key
35395
- @param value
35396
- */
35397
- setStateMeta: function(state, key, value) {
35398
- return set(this.stateMetaFor(state), key, value);
35399
- },
35400
-
35401
- /**
35402
- Returns the value of an item in the stateMeta hash at the given key.
35403
-
35404
- @method getStateMeta
35405
- @param state
35406
- @param key
35407
- */
35408
- getStateMeta: function(state, key) {
35409
- return get(this.stateMetaFor(state), key);
35410
- },
35411
-
35412
- /**
35413
- The current state from among the manager's possible states. This property should
35414
- not be set directly. Use `transitionTo` to move between states by name.
35415
-
35416
- @property currentState
35417
- @type Ember.State
35418
- */
35419
- currentState: null,
35420
-
35421
- /**
35422
- The path of the current state. Returns a string representation of the current
35423
- state.
35424
-
35425
- @property currentPath
35426
- @type String
35427
- */
35428
- currentPath: Ember.computed.alias('currentState.path'),
35429
-
35430
- /**
35431
- The name of transitionEvent that this stateManager will dispatch
35432
-
35433
- @property transitionEvent
35434
- @type String
35435
- @default 'setup'
35436
- */
35437
- transitionEvent: 'setup',
35438
-
35439
- /**
35440
- If set to true, `errorOnUnhandledEvents` will cause an exception to be
35441
- raised if you attempt to send an event to a state manager that is not
35442
- handled by the current state or any of its parent states.
35443
-
35444
- @property errorOnUnhandledEvents
35445
- @type Boolean
35446
- @default true
35447
- */
35448
- errorOnUnhandledEvent: true,
35449
-
35450
- /**
35451
- An alias to sendEvent method
35452
-
35453
- @method send
35454
- @param event
35455
- */
35456
- send: function(event) {
35457
- var contexts = [].slice.call(arguments, 1);
35458
- Ember.assert('Cannot send event "' + event + '" while currentState is ' + get(this, 'currentState'), get(this, 'currentState'));
35459
- return sendEvent.call(this, event, contexts, false);
35460
- },
35461
-
35462
- /**
35463
- If errorOnUnhandledEvent is true this event with throw an Ember.Error
35464
- indicating that the no state could respond to the event passed through the
35465
- state machine.
35466
-
35467
- @method unhandledEvent
35468
- @param manager
35469
- @param event
35470
- */
35471
- unhandledEvent: function(manager, event) {
35472
- if (get(this, 'errorOnUnhandledEvent')) {
35473
- throw new Ember.Error(this.toString() + " could not respond to event " + event + " in state " + get(this, 'currentState.path') + ".");
35474
- }
35475
- },
35476
-
35477
- /**
35478
- Finds a state by its state path.
35479
-
35480
- Example:
35481
-
35482
- ```javascript
35483
- var manager = Ember.StateManager.create({
35484
- root: Ember.State.create({
35485
- dashboard: Ember.State.create()
35486
- })
35487
- });
35488
-
35489
- manager.getStateByPath(manager, "root.dashboard");
35490
- // returns the dashboard state
35491
-
35492
- var aState = manager.getStateByPath(manager, "root.dashboard");
35493
-
35494
- var path = aState.get('path');
35495
- // path is 'root.dashboard'
35496
-
35497
- var name = aState.get('name');
35498
- // name is 'dashboard'
35499
- ```
35500
-
35501
- @method getStateByPath
35502
- @param {Ember.State} root the state to start searching from
35503
- @param {String} path the state path to follow
35504
- @return {Ember.State} the state at the end of the path
35505
- */
35506
- getStateByPath: function(root, path) {
35507
- var parts = path.split('.'),
35508
- state = root;
35509
-
35510
- for (var i=0, len=parts.length; i<len; i++) {
35511
- state = get(get(state, 'states'), parts[i]);
35512
- if (!state) { break; }
35513
- }
35514
-
35515
- return state;
35516
- },
35517
-
35518
- findStateByPath: function(state, path) {
35519
- var possible;
35520
-
35521
- while (!possible && state) {
35522
- possible = this.getStateByPath(state, path);
35523
- state = get(state, 'parentState');
35524
- }
35525
-
35526
- return possible;
35527
- },
35528
-
35529
- /**
35530
- A state stores its child states in its `states` hash.
35531
- This code takes a path like `posts.show` and looks
35532
- up `root.states.posts.states.show`.
35533
-
35534
- It returns a list of all of the states from the
35535
- root, which is the list of states to call `enter`
35536
- on.
35537
-
35538
- @method getStatesInPath
35539
- @param root
35540
- @param path
35541
- */
35542
- getStatesInPath: function(root, path) {
35543
- if (!path || path === "") { return undefined; }
35544
- var parts = path.split('.'),
35545
- result = [],
35546
- states,
35547
- state;
35548
-
35549
- for (var i=0, len=parts.length; i<len; i++) {
35550
- states = get(root, 'states');
35551
- if (!states) { return undefined; }
35552
- state = get(states, parts[i]);
35553
- if (state) { root = state; result.push(state); }
35554
- else { return undefined; }
35555
- }
35556
-
35557
- return result;
35558
- },
35559
-
35560
- /**
35561
- Alias for transitionTo.
35562
- This method applies a transitionTo to the arguments passed into this method.
35563
-
35564
- @method goToState
35565
- */
35566
- goToState: function() {
35567
- // not deprecating this yet so people don't constantly need to
35568
- // make trivial changes for little reason.
35569
- return this.transitionTo.apply(this, arguments);
35570
- },
35571
-
35572
- /**
35573
- Transition to another state within the state machine. If the path is empty returns
35574
- immediately. This method attempts to get a hash of the enter, exit and resolve states
35575
- from the existing state cache. Processes the raw state information based on the
35576
- passed in context. Creates a new transition object and triggers a new setupContext.
35577
-
35578
- @method transitionTo
35579
- @param path
35580
- @param context
35581
- */
35582
- transitionTo: function(path, context) {
35583
- // XXX When is transitionTo called with no path
35584
- if (Ember.isEmpty(path)) { return; }
35585
-
35586
- // The ES6 signature of this function is `path, ...contexts`
35587
- var contexts = context ? Array.prototype.slice.call(arguments, 1) : [],
35588
- currentState = get(this, 'currentState') || this;
35589
-
35590
- // First, get the enter, exit and resolve states for the current state
35591
- // and specified path. If possible, use an existing cache.
35592
- var hash = this.contextFreeTransition(currentState, path);
35593
-
35594
- // Next, process the raw state information for the contexts passed in.
35595
- var transition = new Transition(hash).normalize(this, contexts);
35596
-
35597
- this.enterState(transition);
35598
- this.triggerSetupContext(transition);
35599
- },
35600
-
35601
- /**
35602
- Allows you to transition to any other state in the state manager without
35603
- being constrained by the state hierarchy of the current state path.
35604
- This method will traverse the state path upwards through its parents until
35605
- it finds the specified state path. All the transitions are captured during the
35606
- traversal.
35607
-
35608
- Caches and returns hash of transitions, which contain the exitSates, enterStates and
35609
- resolvedState
35610
-
35611
- @method contextFreeTransition
35612
- @param currentState
35613
- @param path
35614
- */
35615
- contextFreeTransition: function(currentState, path) {
35616
- var cache = currentState.getPathsCache(this, path);
35617
- if (cache) { return cache; }
35618
-
35619
- var enterStates = this.getStatesInPath(currentState, path),
35620
- exitStates = [],
35621
- resolveState = currentState;
35622
-
35623
- // Walk up the states. For each state, check whether a state matching
35624
- // the `path` is nested underneath. This will find the closest
35625
- // parent state containing `path`.
35626
- //
35627
- // This allows the user to pass in a relative path. For example, for
35628
- // the following state hierarchy:
35629
- //
35630
- // | |root
35631
- // | |- posts
35632
- // | | |- show (* current)
35633
- // | |- comments
35634
- // | | |- show
35635
- //
35636
- // If the current state is `<root.posts.show>`, an attempt to
35637
- // transition to `comments.show` will match `<root.comments.show>`.
35638
- //
35639
- // First, this code will look for root.posts.show.comments.show.
35640
- // Next, it will look for root.posts.comments.show. Finally,
35641
- // it will look for `root.comments.show`, and find the state.
35642
- //
35643
- // After this process, the following variables will exist:
35644
- //
35645
- // * resolveState: a common parent state between the current
35646
- // and target state. In the above example, `<root>` is the
35647
- // `resolveState`.
35648
- // * enterStates: a list of all of the states represented
35649
- // by the path from the `resolveState`. For example, for
35650
- // the path `root.comments.show`, `enterStates` would have
35651
- // `[<root.comments>, <root.comments.show>]`
35652
- // * exitStates: a list of all of the states from the
35653
- // `resolveState` to the `currentState`. In the above
35654
- // example, `exitStates` would have
35655
- // `[<root.posts>`, `<root.posts.show>]`.
35656
- while (resolveState && !enterStates) {
35657
- exitStates.unshift(resolveState);
35658
-
35659
- resolveState = get(resolveState, 'parentState');
35660
- if (!resolveState) {
35661
- enterStates = this.getStatesInPath(this, path);
35662
- if (!enterStates) {
35663
- Ember.assert('Could not find state for path: "'+path+'"');
35664
- return;
35665
- }
35666
- }
35667
- enterStates = this.getStatesInPath(resolveState, path);
35668
- }
35669
-
35670
- // If the path contains some states that are parents of both the
35671
- // current state and the target state, remove them.
35672
- //
35673
- // For example, in the following hierarchy:
35674
- //
35675
- // |- root
35676
- // | |- post
35677
- // | | |- index (* current)
35678
- // | | |- show
35679
- //
35680
- // If the `path` is `root.post.show`, the three variables will
35681
- // be:
35682
- //
35683
- // * resolveState: `<state manager>`
35684
- // * enterStates: `[<root>, <root.post>, <root.post.show>]`
35685
- // * exitStates: `[<root>, <root.post>, <root.post.index>]`
35686
- //
35687
- // The goal of this code is to remove the common states, so we
35688
- // have:
35689
- //
35690
- // * resolveState: `<root.post>`
35691
- // * enterStates: `[<root.post.show>]`
35692
- // * exitStates: `[<root.post.index>]`
35693
- //
35694
- // This avoid unnecessary calls to the enter and exit transitions.
35695
- while (enterStates.length > 0 && enterStates[0] === exitStates[0]) {
35696
- resolveState = enterStates.shift();
35697
- exitStates.shift();
35698
- }
35699
-
35700
- // Cache the enterStates, exitStates, and resolveState for the
35701
- // current state and the `path`.
35702
- var transitions = {
35703
- exitStates: exitStates,
35704
- enterStates: enterStates,
35705
- resolveState: resolveState
35706
- };
35707
-
35708
- currentState.setPathsCache(this, path, transitions);
35709
-
35710
- return transitions;
35711
- },
35712
-
35713
- /**
35714
- A trigger to setup the state contexts. Each state is setup with
35715
- an enterState.
35716
-
35717
- @method triggerSetupContext
35718
- @param transitions
35719
- */
35720
- triggerSetupContext: function(transitions) {
35721
- var contexts = transitions.contexts,
35722
- offset = transitions.enterStates.length - contexts.length,
35723
- enterStates = transitions.enterStates,
35724
- transitionEvent = get(this, 'transitionEvent');
35725
-
35726
- Ember.assert("More contexts provided than states", offset >= 0);
35727
-
35728
- arrayForEach.call(enterStates, function(state, idx) {
35729
- state.trigger(transitionEvent, this, contexts[idx-offset]);
35730
- }, this);
35731
- },
35732
-
35733
- /**
35734
- Returns the state instance by name. If state is not found the parentState
35735
- is returned instead.
35736
-
35737
- @method getState
35738
- @param name
35739
- */
35740
- getState: function(name) {
35741
- var state = get(this, name),
35742
- parentState = get(this, 'parentState');
35743
-
35744
- if (state) {
35745
- return state;
35746
- } else if (parentState) {
35747
- return parentState.getState(name);
35748
- }
35749
- },
35750
-
35751
- /**
35752
- Causes a transition from the exitState of one state to the enterState of another
35753
- state in the state machine. At the end of the transition the currentState is set
35754
- to the finalState of the transition passed into this method.
35755
-
35756
- @method enterState
35757
- @param transition
35758
- */
35759
- enterState: function(transition) {
35760
- var log = this.enableLogging;
35761
-
35762
- var exitStates = transition.exitStates.slice(0).reverse();
35763
- arrayForEach.call(exitStates, function(state) {
35764
- state.trigger('exit', this);
35765
- }, this);
35766
-
35767
- arrayForEach.call(transition.enterStates, function(state) {
35768
- if (log) { Ember.Logger.log("STATEMANAGER: Entering " + get(state, 'path')); }
35769
- state.trigger('enter', this);
35770
- }, this);
35771
-
35772
- set(this, 'currentState', transition.finalState);
35773
- }
35774
- });
35775
35261
 
35776
35262
  })();
35777
35263
 
@@ -35779,11 +35265,11 @@ Ember.StateManager = Ember.State.extend({
35779
35265
 
35780
35266
  (function() {
35781
35267
  /**
35782
- Ember States
35268
+ Ember Application
35783
35269
 
35784
35270
  @module ember
35785
- @submodule ember-states
35786
- @requires ember-runtime
35271
+ @submodule ember-application
35272
+ @requires ember-views, ember-routing
35787
35273
  */
35788
35274
 
35789
35275
  })();
@@ -36810,7 +36296,7 @@ function chain(app, promise, fn) {
36810
36296
  * using your app.
36811
36297
  *
36812
36298
  * Example:
36813
- *
36299
+ *
36814
36300
  * ```
36815
36301
  * visit('posts/index').then(function() {
36816
36302
  * // assert something
@@ -36818,7 +36304,7 @@ function chain(app, promise, fn) {
36818
36304
  * ```
36819
36305
  *
36820
36306
  * @method visit
36821
- * @param {String} url the name of the route
36307
+ * @param {String} url the name of the route
36822
36308
  * @returns {RSVP.Promise}
36823
36309
  */
36824
36310
  helper('visit', visit);
@@ -36961,6 +36447,23 @@ Ember
36961
36447
  @module ember
36962
36448
  */
36963
36449
 
36450
+ function throwWithMessage(msg) {
36451
+ return function() {
36452
+ throw new Error(msg);
36453
+ };
36454
+ }
36455
+
36456
+ function generateRemovedClass(className) {
36457
+ var msg = " has been moved into a plugin: https://github.com/emberjs/ember-states";
36458
+
36459
+ return {
36460
+ extend: throwWithMessage(className + msg),
36461
+ create: throwWithMessage(className + msg)
36462
+ };
36463
+ }
36464
+
36465
+ Ember.StateManager = generateRemovedClass("Ember.StateManager");
36466
+ Ember.State = generateRemovedClass("Ember.State");
36964
36467
  })();
36965
36468
 
36966
36469