pyro 0.9.0 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/bin/pyro +31 -10
- data/lib/pyro.rb +4 -4
- data/lib/pyro/asset.rb +101 -0
- data/lib/pyro/assets.rb +31 -112
- data/lib/pyro/server.rb +10 -5
- data/pyro.gemspec +2 -2
- data/templates/app/index.erb +10 -5
- data/templates/app/lib/app.coffee +0 -2
- data/templates/app/test/example.coffee +15 -0
- data/templates/app/vendor/ember/ember-data.js +6947 -0
- data/templates/app/vendor/ember/ember-data.prod.js +284 -0
- data/templates/app/vendor/ember/{ember-1.0.0-rc.8.js → ember.js} +1302 -1799
- data/templates/app/vendor/ember/ember.prod.js +1260 -1785
- data/templates/app/vendor/qunit/qunit.css +244 -0
- data/templates/app/vendor/qunit/qunit.js +2212 -0
- data/test/test_pyro.rb +7 -7
- metadata +13 -10
- data/templates/app/README.md +0 -0
- data/templates/app/test/test.coffee +0 -1
- data/templates/app/vendor/ember/ember-data-0.13.js +0 -8887
@@ -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
|
2
|
-
// Last commit:
|
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
|
162
|
-
// Last commit:
|
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
|
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
|
267
|
+
@default '1.0.0'
|
256
268
|
@final
|
257
269
|
*/
|
258
|
-
Ember.VERSION = '1.0.0
|
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`
|
4605
|
-
|
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({
|
4625
|
+
var todoList = ToDoList.create({todos: ['Unit Test', 'Documentation', 'Release']});
|
4614
4626
|
todoList.get('done'); // false
|
4615
|
-
todoList.get('
|
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 =
|
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
|
-
|
7573
|
+
|
7574
|
+
valueWillChange: Ember.beforeObserver(function(obj, keyName) {
|
7531
7575
|
this.changingFrom = obj.get(keyName);
|
7532
|
-
}
|
7533
|
-
|
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
|
-
|
7537
|
-
|
7581
|
+
var color = obj.get(keyName) > this.changingFrom ? 'green' : 'red';
|
7582
|
+
// logic
|
7538
7583
|
}
|
7539
|
-
}
|
7540
|
-
|
7584
|
+
}, 'content.value'),
|
7585
|
+
|
7586
|
+
friendsDidChange: Ember.observer(function(obj, keyName) {
|
7541
7587
|
// some logic
|
7542
7588
|
// obj.get(keyName) returns friends array
|
7543
|
-
}
|
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
|
-
|
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
|
-
|
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,
|
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
|
-
}
|
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
|
11135
|
+
var guid = guidFor(obj);
|
11067
11136
|
|
11068
|
-
if (!this.changedItems[
|
11069
|
-
this.changedItems[
|
11070
|
-
array: array,
|
11137
|
+
if (!this.changedItems[guid]) {
|
11138
|
+
this.changedItems[guid] = {
|
11139
|
+
array: array,
|
11071
11140
|
index: index,
|
11072
11141
|
obj: obj,
|
11073
|
-
|
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.
|
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,
|
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 (
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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 =
|
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
|
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 =
|
12134
|
+
var itemGuid = guidFor(item),
|
11583
12135
|
dependentGuids = getDependentKeyGuids(changeMeta),
|
11584
|
-
dependentGuid =
|
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 =
|
12151
|
+
var itemGuid = guidFor(item),
|
11600
12152
|
dependentGuids = getDependentKeyGuids(changeMeta),
|
11601
|
-
dependentGuid =
|
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.
|
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.
|
12195
|
-
firstName:
|
12196
|
-
lastName:
|
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.
|
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.
|
12218
|
-
firstName:
|
12219
|
-
lastName:
|
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.
|
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
|
-
|
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
|
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.
|
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.
|
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[
|
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 {{
|
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
|
-
|
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 '
|
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
|
-
|
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.
|
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
|
-
|
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('
|
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,
|
26265
|
-
on = get(view, 'onEvent')
|
27028
|
+
var action = get(view, eventName),
|
27029
|
+
on = get(view, 'onEvent'),
|
27030
|
+
value = get(view, 'value');
|
26266
27031
|
|
26267
|
-
|
26268
|
-
|
26269
|
-
|
26270
|
-
|
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
|
-
|
27039
|
+
view.sendAction(eventName, value);
|
26273
27040
|
|
26274
|
-
|
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.
|
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
|
29825
|
-
class or mixin
|
30683
|
+
action handler if it overrides a handler defined on a parent
|
30684
|
+
class or mixin:
|
29826
30685
|
|
29827
|
-
|
29828
|
-
|
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
|
-
|
30303
|
-
|
31209
|
+
return this.findModel(name, value);
|
31210
|
+
},
|
31211
|
+
|
31212
|
+
/**
|
30304
31213
|
|
30305
|
-
|
30306
|
-
|
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
|
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 =
|
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)
|
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('
|
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
|
-
|
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
|
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
|
34182
|
-
var
|
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
|
-
|
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
|
-
|
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
|
-
|
34254
|
-
|
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:
|
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
|
-
|
34459
|
-
|
34460
|
-
|
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
|
-
|
34468
|
-
|
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
|
35268
|
+
Ember Application
|
35783
35269
|
|
35784
35270
|
@module ember
|
35785
|
-
@submodule ember-
|
35786
|
-
@requires ember-
|
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
|
|