cadenero 0.0.2.a3 → 0.0.2.b1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +4 -3
- data/app/controllers/cadenero/v1/account/sessions_controller.rb +3 -1
- data/app/controllers/cadenero/v1/account/users_controller.rb +8 -2
- data/app/controllers/cadenero/v1/accounts_controller.rb +13 -1
- data/app/extenders/middleware/robustness.rb +19 -0
- data/app/models/cadenero/member.rb +1 -0
- data/app/models/cadenero/user.rb +2 -0
- data/app/models/cadenero/v1/account.rb +16 -1
- data/app/serializers/cadenero/account_serializer.rb +1 -0
- data/app/serializers/cadenero/user_serializer.rb +1 -0
- data/config/initializers/apartment.rb +4 -1
- data/config/initializers/warden/strategies/password.rb +1 -1
- data/config/routes.rb +1 -0
- data/lib/cadenero/constraints/subdomain_required.rb +2 -0
- data/lib/cadenero/engine.rb +1 -1
- data/lib/cadenero/testing_support/subdomain_helpers.rb +15 -0
- data/lib/cadenero/version.rb +1 -1
- data/lib/cadenero.rb +2 -0
- data/lib/generators/cadenero/install_generator.rb +17 -0
- data/spec/dummy/log/development.log +209 -0
- data/spec/dummy/log/test.log +26783 -5135
- data/spec/dummy/tmp/ember-rails/ember.js +1693 -676
- data/spec/features/users/sign_in_spec.rb +13 -3
- data/spec/models/cadenero/account_spec.rb +31 -1
- data/spec/spec_helper.rb +1 -0
- metadata +11 -44
- data/app/helpers/cadenero/application_helper.rb +0 -4
- data/app/helpers/cadenero/v1/accounts_helper.rb +0 -4
- data/app/helpers/cadenero/v1/users_helper.rb +0 -4
- data/spec/features/cadenero/account_spec.rb +0 -23
- data/spec/support/subdomain_helpers.rb +0 -8
@@ -1,5 +1,5 @@
|
|
1
|
-
// Version: v1.0.0-rc.
|
2
|
-
// Last commit:
|
1
|
+
// Version: v1.0.0-rc.6
|
2
|
+
// Last commit: 893bbc4 (2013-06-23 15:14:46 -0400)
|
3
3
|
|
4
4
|
|
5
5
|
(function() {
|
@@ -49,7 +49,12 @@ if (!('MANDATORY_SETTER' in Ember.ENV)) {
|
|
49
49
|
falsy, an exception will be thrown.
|
50
50
|
*/
|
51
51
|
Ember.assert = function(desc, test) {
|
52
|
-
|
52
|
+
Ember.Logger.assert(test, desc);
|
53
|
+
|
54
|
+
if (Ember.testing && !test) {
|
55
|
+
// when testing, ensure test failures when assertions fail
|
56
|
+
throw new Error("Assertion Failed: " + desc);
|
57
|
+
}
|
53
58
|
};
|
54
59
|
|
55
60
|
|
@@ -95,12 +100,12 @@ Ember.debug = function(message) {
|
|
95
100
|
will be displayed.
|
96
101
|
*/
|
97
102
|
Ember.deprecate = function(message, test) {
|
98
|
-
if (Ember
|
103
|
+
if (Ember.TESTING_DEPRECATION) { return; }
|
99
104
|
|
100
105
|
if (arguments.length === 1) { test = false; }
|
101
106
|
if (test) { return; }
|
102
107
|
|
103
|
-
if (Ember
|
108
|
+
if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); }
|
104
109
|
|
105
110
|
var error;
|
106
111
|
|
@@ -151,8 +156,8 @@ Ember.deprecateFunc = function(message, func) {
|
|
151
156
|
|
152
157
|
})();
|
153
158
|
|
154
|
-
// Version: v1.0.0-rc.
|
155
|
-
// Last commit:
|
159
|
+
// Version: v1.0.0-rc.6
|
160
|
+
// Last commit: 893bbc4 (2013-06-23 15:14:46 -0400)
|
156
161
|
|
157
162
|
|
158
163
|
(function() {
|
@@ -219,7 +224,7 @@ var define, requireModule;
|
|
219
224
|
|
220
225
|
@class Ember
|
221
226
|
@static
|
222
|
-
@version 1.0.0-rc.
|
227
|
+
@version 1.0.0-rc.6
|
223
228
|
*/
|
224
229
|
|
225
230
|
if ('undefined' === typeof Ember) {
|
@@ -246,10 +251,10 @@ Ember.toString = function() { return "Ember"; };
|
|
246
251
|
/**
|
247
252
|
@property VERSION
|
248
253
|
@type String
|
249
|
-
@default '1.0.0-rc.
|
254
|
+
@default '1.0.0-rc.6'
|
250
255
|
@final
|
251
256
|
*/
|
252
|
-
Ember.VERSION = '1.0.0-rc.
|
257
|
+
Ember.VERSION = '1.0.0-rc.6';
|
253
258
|
|
254
259
|
/**
|
255
260
|
Standard environmental variables. You can define these in a global `ENV`
|
@@ -364,6 +369,19 @@ function consoleMethod(name) {
|
|
364
369
|
}
|
365
370
|
}
|
366
371
|
|
372
|
+
function assertPolyfill(test, message) {
|
373
|
+
if (!test) {
|
374
|
+
try {
|
375
|
+
// attempt to preserve the stack
|
376
|
+
throw new Error("assertion failed: " + message);
|
377
|
+
} catch(error) {
|
378
|
+
setTimeout(function(){
|
379
|
+
throw error;
|
380
|
+
}, 0);
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
|
367
385
|
/**
|
368
386
|
Inside Ember-Metal, simply uses the methods from `imports.console`.
|
369
387
|
Override this to provide more robust logging functionality.
|
@@ -376,7 +394,8 @@ Ember.Logger = {
|
|
376
394
|
warn: consoleMethod('warn') || Ember.K,
|
377
395
|
error: consoleMethod('error') || Ember.K,
|
378
396
|
info: consoleMethod('info') || Ember.K,
|
379
|
-
debug: consoleMethod('debug') || consoleMethod('info') || Ember.K
|
397
|
+
debug: consoleMethod('debug') || consoleMethod('info') || Ember.K,
|
398
|
+
assert: consoleMethod('assert') || assertPolyfill
|
380
399
|
};
|
381
400
|
|
382
401
|
|
@@ -1644,6 +1663,7 @@ get = function get(obj, keyName) {
|
|
1644
1663
|
obj = null;
|
1645
1664
|
}
|
1646
1665
|
|
1666
|
+
Ember.assert("Cannot call get with "+ keyName +" key.", !!keyName);
|
1647
1667
|
Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined);
|
1648
1668
|
|
1649
1669
|
if (obj === null || keyName.indexOf('.') !== -1) {
|
@@ -1676,12 +1696,21 @@ if (Ember.config.overrideAccessors) {
|
|
1676
1696
|
get = Ember.get;
|
1677
1697
|
}
|
1678
1698
|
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1699
|
+
/**
|
1700
|
+
@private
|
1701
|
+
|
1702
|
+
Normalizes a target/path pair to reflect that actual target/path that should
|
1703
|
+
be observed, etc. This takes into account passing in global property
|
1704
|
+
paths (i.e. a path beginning with a captial letter not defined on the
|
1705
|
+
target) and * separators.
|
1682
1706
|
|
1683
|
-
|
1684
|
-
|
1707
|
+
@method normalizeTuple
|
1708
|
+
@for Ember
|
1709
|
+
@param {Object} target The current target. May be `null`.
|
1710
|
+
@param {String} path A path on the target or a global property path.
|
1711
|
+
@return {Array} a temporary array with the normalized target/path pair.
|
1712
|
+
*/
|
1713
|
+
var normalizeTuple = Ember.normalizeTuple = function(target, path) {
|
1685
1714
|
var hasThis = HAS_THIS.test(path),
|
1686
1715
|
isGlobal = !hasThis && IS_GLOBAL_PATH.test(path),
|
1687
1716
|
key;
|
@@ -1690,7 +1719,7 @@ function normalizeTuple(target, path) {
|
|
1690
1719
|
if (hasThis) path = path.slice(5);
|
1691
1720
|
|
1692
1721
|
if (target === Ember.lookup) {
|
1693
|
-
key =
|
1722
|
+
key = path.match(FIRST_KEY)[0];
|
1694
1723
|
target = get(target, key);
|
1695
1724
|
path = path.slice(key.length+1);
|
1696
1725
|
}
|
@@ -1699,7 +1728,7 @@ function normalizeTuple(target, path) {
|
|
1699
1728
|
if (!path || path.length===0) throw new Error('Invalid Path');
|
1700
1729
|
|
1701
1730
|
return [ target, path ];
|
1702
|
-
}
|
1731
|
+
};
|
1703
1732
|
|
1704
1733
|
var getPath = Ember._getPath = function(root, path) {
|
1705
1734
|
var hasThis, parts, tuple, idx, len;
|
@@ -1728,24 +1757,6 @@ var getPath = Ember._getPath = function(root, path) {
|
|
1728
1757
|
return root;
|
1729
1758
|
};
|
1730
1759
|
|
1731
|
-
/**
|
1732
|
-
@private
|
1733
|
-
|
1734
|
-
Normalizes a target/path pair to reflect that actual target/path that should
|
1735
|
-
be observed, etc. This takes into account passing in global property
|
1736
|
-
paths (i.e. a path beginning with a captial letter not defined on the
|
1737
|
-
target) and * separators.
|
1738
|
-
|
1739
|
-
@method normalizeTuple
|
1740
|
-
@for Ember
|
1741
|
-
@param {Object} target The current target. May be `null`.
|
1742
|
-
@param {String} path A path on the target or a global property path.
|
1743
|
-
@return {Array} a temporary array with the normalized target/path pair.
|
1744
|
-
*/
|
1745
|
-
Ember.normalizeTuple = function(target, path) {
|
1746
|
-
return normalizeTuple(target, path);
|
1747
|
-
};
|
1748
|
-
|
1749
1760
|
Ember.getWithDefault = function(root, key, defaultValue) {
|
1750
1761
|
var value = get(root, key);
|
1751
1762
|
|
@@ -2465,6 +2476,8 @@ var set = function set(obj, keyName, value, tolerant) {
|
|
2465
2476
|
obj = null;
|
2466
2477
|
}
|
2467
2478
|
|
2479
|
+
Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName);
|
2480
|
+
|
2468
2481
|
if (!obj || keyName.indexOf('.') !== -1) {
|
2469
2482
|
return setPath(obj, keyName, value, tolerant);
|
2470
2483
|
}
|
@@ -3116,9 +3129,9 @@ var changeProperties = Ember.changeProperties,
|
|
3116
3129
|
observers will be buffered.
|
3117
3130
|
|
3118
3131
|
@method setProperties
|
3119
|
-
@param
|
3120
|
-
@param {
|
3121
|
-
@return
|
3132
|
+
@param self
|
3133
|
+
@param {Object} hash
|
3134
|
+
@return self
|
3122
3135
|
*/
|
3123
3136
|
Ember.setProperties = function(self, hash) {
|
3124
3137
|
changeProperties(function(){
|
@@ -4758,7 +4771,7 @@ define("backburner",
|
|
4758
4771
|
},
|
4759
4772
|
|
4760
4773
|
cancel: function(timer) {
|
4761
|
-
if (typeof timer === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce
|
4774
|
+
if (timer && typeof timer === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce
|
4762
4775
|
return timer.queue.cancel(timer);
|
4763
4776
|
} else if (typeof timer === 'function') { // we're cancelling a setTimeout
|
4764
4777
|
for (var i = 0, l = timers.length; i < l; i += 2) {
|
@@ -4767,6 +4780,8 @@ define("backburner",
|
|
4767
4780
|
return true;
|
4768
4781
|
}
|
4769
4782
|
}
|
4783
|
+
} else {
|
4784
|
+
return; // timer was null or not a timer
|
4770
4785
|
}
|
4771
4786
|
}
|
4772
4787
|
};
|
@@ -4859,7 +4874,7 @@ define("backburner/deferred_action_queues",
|
|
4859
4874
|
while (queueNameIndex < numberOfQueues) {
|
4860
4875
|
queueName = queueNames[queueNameIndex];
|
4861
4876
|
queue = queues[queueName];
|
4862
|
-
queueItems = queue._queue.slice();
|
4877
|
+
queueItems = queue._queueBeingFlushed = queue._queue.slice();
|
4863
4878
|
queue._queue = [];
|
4864
4879
|
|
4865
4880
|
var options = queue.options,
|
@@ -4877,15 +4892,19 @@ define("backburner/deferred_action_queues",
|
|
4877
4892
|
|
4878
4893
|
if (typeof method === 'string') { method = target[method]; }
|
4879
4894
|
|
4880
|
-
//
|
4881
|
-
if (
|
4882
|
-
|
4883
|
-
|
4884
|
-
|
4895
|
+
// method could have been nullified / canceled during flush
|
4896
|
+
if (method) {
|
4897
|
+
// TODO: error handling
|
4898
|
+
if (args && args.length > 0) {
|
4899
|
+
method.apply(target, args);
|
4900
|
+
} else {
|
4901
|
+
method.call(target);
|
4902
|
+
}
|
4885
4903
|
}
|
4886
4904
|
|
4887
4905
|
queueIndex += 4;
|
4888
4906
|
}
|
4907
|
+
queue._queueBeingFlushed = null;
|
4889
4908
|
if (numberOfQueueItems && after) { after(); }
|
4890
4909
|
|
4891
4910
|
if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) {
|
@@ -4910,6 +4929,7 @@ define("backburner/deferred_action_queues",
|
|
4910
4929
|
return -1;
|
4911
4930
|
}
|
4912
4931
|
|
4932
|
+
|
4913
4933
|
__exports__.DeferredActionQueues = DeferredActionQueues;
|
4914
4934
|
});
|
4915
4935
|
|
@@ -4999,12 +5019,30 @@ define("backburner/queue",
|
|
4999
5019
|
return true;
|
5000
5020
|
}
|
5001
5021
|
}
|
5022
|
+
|
5023
|
+
// if not found in current queue
|
5024
|
+
// could be in the queue that is being flushed
|
5025
|
+
queue = this._queueBeingFlushed;
|
5026
|
+
if (!queue) {
|
5027
|
+
return;
|
5028
|
+
}
|
5029
|
+
for (i = 0, l = queue.length; i < l; i += 4) {
|
5030
|
+
currentTarget = queue[i];
|
5031
|
+
currentMethod = queue[i+1];
|
5032
|
+
|
5033
|
+
if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) {
|
5034
|
+
// don't mess with array during flush
|
5035
|
+
// just nullify the method
|
5036
|
+
queue[i+1] = null;
|
5037
|
+
return true;
|
5038
|
+
}
|
5039
|
+
}
|
5002
5040
|
}
|
5003
5041
|
};
|
5004
5042
|
|
5043
|
+
|
5005
5044
|
__exports__.Queue = Queue;
|
5006
5045
|
});
|
5007
|
-
|
5008
5046
|
})();
|
5009
5047
|
|
5010
5048
|
|
@@ -5112,7 +5150,7 @@ Ember.run = function(target, method) {
|
|
5112
5150
|
May be a function or a string. If you pass a string
|
5113
5151
|
then it will be looked up on the passed target.
|
5114
5152
|
@param {Object} [args*] Any additional arguments you wish to pass to the method.
|
5115
|
-
@return {Object} return value from invoking the passed function. Please note,
|
5153
|
+
@return {Object} return value from invoking the passed function. Please note,
|
5116
5154
|
when called within an existing loop, no return value is possible.
|
5117
5155
|
*/
|
5118
5156
|
Ember.run.join = function(target, method) {
|
@@ -5248,7 +5286,9 @@ Ember.run.cancelTimers = function () {
|
|
5248
5286
|
@return {void}
|
5249
5287
|
*/
|
5250
5288
|
Ember.run.sync = function() {
|
5251
|
-
backburner.currentInstance
|
5289
|
+
if (backburner.currentInstance) {
|
5290
|
+
backburner.currentInstance.queues.sync.flush();
|
5291
|
+
}
|
5252
5292
|
};
|
5253
5293
|
|
5254
5294
|
/**
|
@@ -5441,6 +5481,38 @@ Ember.run.cancel = function(timer) {
|
|
5441
5481
|
return backburner.cancel(timer);
|
5442
5482
|
};
|
5443
5483
|
|
5484
|
+
/**
|
5485
|
+
Execute the passed method in a specified amount of time, reset timer
|
5486
|
+
upon additional calls.
|
5487
|
+
|
5488
|
+
```javascript
|
5489
|
+
var myFunc = function() { console.log(this.name + ' ran.'); };
|
5490
|
+
var myContext = {name: 'debounce'};
|
5491
|
+
|
5492
|
+
Ember.run.debounce(myContext, myFunc, 150);
|
5493
|
+
|
5494
|
+
// less than 150ms passes
|
5495
|
+
|
5496
|
+
Ember.run.debounce(myContext, myFunc, 150);
|
5497
|
+
|
5498
|
+
// 150ms passes
|
5499
|
+
// myFunc is invoked with context myContext
|
5500
|
+
// console logs 'debounce ran.' one time.
|
5501
|
+
```
|
5502
|
+
|
5503
|
+
@method debounce
|
5504
|
+
@param {Object} [target] target of method to invoke
|
5505
|
+
@param {Function|String} method The method to invoke.
|
5506
|
+
May be a function or a string. If you pass a string
|
5507
|
+
then it will be looked up on the passed target.
|
5508
|
+
@param {Object} [args*] Optional arguments to pass to the timeout.
|
5509
|
+
@param {Number} wait Number of milliseconds to wait.
|
5510
|
+
@return {void}
|
5511
|
+
*/
|
5512
|
+
Ember.run.debounce = function() {
|
5513
|
+
return backburner.debounce.apply(backburner, arguments);
|
5514
|
+
};
|
5515
|
+
|
5444
5516
|
// Make sure it's not an autorun during testing
|
5445
5517
|
function checkAutoRun() {
|
5446
5518
|
if (!Ember.run.currentRunLoop) {
|
@@ -7230,6 +7302,8 @@ define("rsvp",
|
|
7230
7302
|
__exports__.reject = reject;
|
7231
7303
|
});
|
7232
7304
|
|
7305
|
+
|
7306
|
+
|
7233
7307
|
})();
|
7234
7308
|
|
7235
7309
|
(function() {
|
@@ -7354,6 +7428,10 @@ define("container",
|
|
7354
7428
|
return value;
|
7355
7429
|
},
|
7356
7430
|
|
7431
|
+
lookupFactory: function(fullName) {
|
7432
|
+
return factoryFor(this, fullName);
|
7433
|
+
},
|
7434
|
+
|
7357
7435
|
has: function(fullName) {
|
7358
7436
|
if (this.cache.has(fullName)) {
|
7359
7437
|
return true;
|
@@ -8074,8 +8152,8 @@ Ember.String = {
|
|
8074
8152
|
```
|
8075
8153
|
|
8076
8154
|
@method capitalize
|
8077
|
-
@param {String} str
|
8078
|
-
@return {String}
|
8155
|
+
@param {String} str The string to capitalize.
|
8156
|
+
@return {String} The capitalized string.
|
8079
8157
|
*/
|
8080
8158
|
capitalize: function(str) {
|
8081
8159
|
return str.charAt(0).toUpperCase() + str.substr(1);
|
@@ -9448,15 +9526,15 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
|
|
9448
9526
|
Adds an array observer to the receiving array. The array observer object
|
9449
9527
|
normally must implement two methods:
|
9450
9528
|
|
9451
|
-
* `arrayWillChange(start, removeCount, addCount)` - This method will be
|
9529
|
+
* `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be
|
9452
9530
|
called just before the array is modified.
|
9453
|
-
* `arrayDidChange(start, removeCount, addCount)` - This method will be
|
9531
|
+
* `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be
|
9454
9532
|
called just after the array is modified.
|
9455
9533
|
|
9456
|
-
Both callbacks will be passed the starting index of the
|
9457
|
-
a count of the items to be removed and added. You can use
|
9458
|
-
to optionally inspect the array during the change, clear
|
9459
|
-
any other bookkeeping necessary.
|
9534
|
+
Both callbacks will be passed the observed object, starting index of the
|
9535
|
+
change as well a a count of the items to be removed and added. You can use
|
9536
|
+
these callbacks to optionally inspect the array during the change, clear
|
9537
|
+
caches, or do any other bookkeeping necessary.
|
9460
9538
|
|
9461
9539
|
In addition to passing a target, you can also include an options hash
|
9462
9540
|
which you can use to override the method names that will be invoked on the
|
@@ -13464,17 +13542,40 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, {
|
|
13464
13542
|
@property {Boolean} sortAscending
|
13465
13543
|
*/
|
13466
13544
|
sortAscending: true,
|
13545
|
+
|
13546
|
+
/**
|
13547
|
+
The function used to compare two values. You can override this if you
|
13548
|
+
want to do custom comparisons.Functions must be of the type expected by
|
13549
|
+
Array#sort, i.e.
|
13550
|
+
return 0 if the two parameters are equal,
|
13551
|
+
return a negative value if the first parameter is smaller than the second or
|
13552
|
+
return a positive value otherwise:
|
13553
|
+
|
13554
|
+
```javascript
|
13555
|
+
function(x,y){ // These are assumed to be integers
|
13556
|
+
if(x === y)
|
13557
|
+
return 0;
|
13558
|
+
return x < y ? -1 : 1;
|
13559
|
+
}
|
13560
|
+
```
|
13467
13561
|
|
13562
|
+
@property sortFunction
|
13563
|
+
@type {Function}
|
13564
|
+
@default Ember.compare
|
13565
|
+
*/
|
13566
|
+
sortFunction: Ember.compare,
|
13567
|
+
|
13468
13568
|
orderBy: function(item1, item2) {
|
13469
13569
|
var result = 0,
|
13470
13570
|
sortProperties = get(this, 'sortProperties'),
|
13471
|
-
sortAscending = get(this, 'sortAscending')
|
13571
|
+
sortAscending = get(this, 'sortAscending'),
|
13572
|
+
sortFunction = get(this, 'sortFunction');
|
13472
13573
|
|
13473
13574
|
Ember.assert("you need to define `sortProperties`", !!sortProperties);
|
13474
13575
|
|
13475
13576
|
forEach(sortProperties, function(propertyName) {
|
13476
13577
|
if (result === 0) {
|
13477
|
-
result =
|
13578
|
+
result = sortFunction(get(item1, propertyName), get(item2, propertyName));
|
13478
13579
|
if ((result !== 0) && !sortAscending) {
|
13479
13580
|
result = (-1) * result;
|
13480
13581
|
}
|
@@ -13912,7 +14013,7 @@ Ember Runtime
|
|
13912
14013
|
*/
|
13913
14014
|
|
13914
14015
|
var jQuery = Ember.imports.jQuery;
|
13915
|
-
Ember.assert("Ember Views require jQuery 1.8, 1.9, 1.10, or 2.0", jQuery && (jQuery().jquery.match(/^((1\.(8|9|10))|2.0)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));
|
14016
|
+
Ember.assert("Ember Views require jQuery 1.7, 1.8, 1.9, 1.10, or 2.0", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10))|2.0)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY));
|
13916
14017
|
|
13917
14018
|
/**
|
13918
14019
|
Alias for jQuery
|
@@ -14610,6 +14711,47 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
|
|
14610
14711
|
*/
|
14611
14712
|
Ember.EventDispatcher = Ember.Object.extend(/** @scope Ember.EventDispatcher.prototype */{
|
14612
14713
|
|
14714
|
+
/**
|
14715
|
+
The set of events names (and associated handler function names) to be setup
|
14716
|
+
and dispatched by the `EventDispatcher`. Custom events can added to this list at setup
|
14717
|
+
time, generally via the `Ember.Application.customEvents` hash. Only override this
|
14718
|
+
default set to prevent the EventDispatcher from listening on some events all together.
|
14719
|
+
|
14720
|
+
This set will be modified by `setup` to also include any events added at that time.
|
14721
|
+
|
14722
|
+
@property events
|
14723
|
+
@type Object
|
14724
|
+
*/
|
14725
|
+
events: {
|
14726
|
+
touchstart : 'touchStart',
|
14727
|
+
touchmove : 'touchMove',
|
14728
|
+
touchend : 'touchEnd',
|
14729
|
+
touchcancel : 'touchCancel',
|
14730
|
+
keydown : 'keyDown',
|
14731
|
+
keyup : 'keyUp',
|
14732
|
+
keypress : 'keyPress',
|
14733
|
+
mousedown : 'mouseDown',
|
14734
|
+
mouseup : 'mouseUp',
|
14735
|
+
contextmenu : 'contextMenu',
|
14736
|
+
click : 'click',
|
14737
|
+
dblclick : 'doubleClick',
|
14738
|
+
mousemove : 'mouseMove',
|
14739
|
+
focusin : 'focusIn',
|
14740
|
+
focusout : 'focusOut',
|
14741
|
+
mouseenter : 'mouseEnter',
|
14742
|
+
mouseleave : 'mouseLeave',
|
14743
|
+
submit : 'submit',
|
14744
|
+
input : 'input',
|
14745
|
+
change : 'change',
|
14746
|
+
dragstart : 'dragStart',
|
14747
|
+
drag : 'drag',
|
14748
|
+
dragenter : 'dragEnter',
|
14749
|
+
dragleave : 'dragLeave',
|
14750
|
+
dragover : 'dragOver',
|
14751
|
+
drop : 'drop',
|
14752
|
+
dragend : 'dragEnd'
|
14753
|
+
},
|
14754
|
+
|
14613
14755
|
/**
|
14614
14756
|
@private
|
14615
14757
|
|
@@ -14641,35 +14783,7 @@ Ember.EventDispatcher = Ember.Object.extend(/** @scope Ember.EventDispatcher.pro
|
|
14641
14783
|
@param addedEvents {Hash}
|
14642
14784
|
*/
|
14643
14785
|
setup: function(addedEvents, rootElement) {
|
14644
|
-
var event, events =
|
14645
|
-
touchstart : 'touchStart',
|
14646
|
-
touchmove : 'touchMove',
|
14647
|
-
touchend : 'touchEnd',
|
14648
|
-
touchcancel : 'touchCancel',
|
14649
|
-
keydown : 'keyDown',
|
14650
|
-
keyup : 'keyUp',
|
14651
|
-
keypress : 'keyPress',
|
14652
|
-
mousedown : 'mouseDown',
|
14653
|
-
mouseup : 'mouseUp',
|
14654
|
-
contextmenu : 'contextMenu',
|
14655
|
-
click : 'click',
|
14656
|
-
dblclick : 'doubleClick',
|
14657
|
-
mousemove : 'mouseMove',
|
14658
|
-
focusin : 'focusIn',
|
14659
|
-
focusout : 'focusOut',
|
14660
|
-
mouseenter : 'mouseEnter',
|
14661
|
-
mouseleave : 'mouseLeave',
|
14662
|
-
submit : 'submit',
|
14663
|
-
input : 'input',
|
14664
|
-
change : 'change',
|
14665
|
-
dragstart : 'dragStart',
|
14666
|
-
drag : 'drag',
|
14667
|
-
dragenter : 'dragEnter',
|
14668
|
-
dragleave : 'dragLeave',
|
14669
|
-
dragover : 'dragOver',
|
14670
|
-
drop : 'drop',
|
14671
|
-
dragend : 'dragEnd'
|
14672
|
-
};
|
14786
|
+
var event, events = get(this, 'events');
|
14673
14787
|
|
14674
14788
|
Ember.$.extend(events, addedEvents || {});
|
14675
14789
|
|
@@ -14916,6 +15030,15 @@ Ember.warn("The VIEW_PRESERVES_CONTEXT flag has been removed and the functionali
|
|
14916
15030
|
*/
|
14917
15031
|
Ember.TEMPLATES = {};
|
14918
15032
|
|
15033
|
+
/**
|
15034
|
+
`Ember.CoreView` is
|
15035
|
+
|
15036
|
+
@class CoreView
|
15037
|
+
@namespace Ember
|
15038
|
+
@extends Ember.Object
|
15039
|
+
@uses Ember.Evented
|
15040
|
+
*/
|
15041
|
+
|
14919
15042
|
Ember.CoreView = Ember.Object.extend(Ember.Evented, {
|
14920
15043
|
isView: true,
|
14921
15044
|
|
@@ -15619,8 +15742,10 @@ class:
|
|
15619
15742
|
|
15620
15743
|
### Event Names
|
15621
15744
|
|
15622
|
-
|
15623
|
-
are
|
15745
|
+
All of the event handling approaches described above respond to the same set
|
15746
|
+
of events. The names of the built-in events are listed below. (The hash of
|
15747
|
+
built-in events exists in `Ember.EventDispatcher`.) Additional, custom events
|
15748
|
+
can be registered by using `Ember.Application.customEvents`.
|
15624
15749
|
|
15625
15750
|
Touch events:
|
15626
15751
|
|
@@ -15673,8 +15798,7 @@ class:
|
|
15673
15798
|
|
15674
15799
|
@class View
|
15675
15800
|
@namespace Ember
|
15676
|
-
@extends Ember.
|
15677
|
-
@uses Ember.Evented
|
15801
|
+
@extends Ember.CoreView
|
15678
15802
|
*/
|
15679
15803
|
Ember.View = Ember.CoreView.extend(
|
15680
15804
|
/** @scope Ember.View.prototype */ {
|
@@ -15855,7 +15979,7 @@ Ember.View = Ember.CoreView.extend(
|
|
15855
15979
|
If a value that affects template rendering changes, the view should be
|
15856
15980
|
re-rendered to reflect the new value.
|
15857
15981
|
|
15858
|
-
@method
|
15982
|
+
@method _contextDidChange
|
15859
15983
|
*/
|
15860
15984
|
_contextDidChange: Ember.observer(function() {
|
15861
15985
|
this.rerender();
|
@@ -15985,6 +16109,8 @@ Ember.View = Ember.CoreView.extend(
|
|
15985
16109
|
_parentViewDidChange: Ember.observer(function() {
|
15986
16110
|
if (this.isDestroying) { return; }
|
15987
16111
|
|
16112
|
+
this.trigger('parentViewDidChange');
|
16113
|
+
|
15988
16114
|
if (get(this, 'parentView.controller') && !get(this, 'controller')) {
|
15989
16115
|
this.notifyPropertyChange('controller');
|
15990
16116
|
}
|
@@ -16256,9 +16382,9 @@ Ember.View = Ember.CoreView.extend(
|
|
16256
16382
|
For example, calling `view.$('li')` will return a jQuery object containing
|
16257
16383
|
all of the `li` elements inside the DOM element of this view.
|
16258
16384
|
|
16259
|
-
@
|
16385
|
+
@method $
|
16260
16386
|
@param {String} [selector] a jQuery-compatible selector string
|
16261
|
-
@return {jQuery} the
|
16387
|
+
@return {jQuery} the jQuery object for the DOM node
|
16262
16388
|
*/
|
16263
16389
|
$: function(sel) {
|
16264
16390
|
return this.currentState.$(this, sel);
|
@@ -16939,31 +17065,32 @@ Ember.View = Ember.CoreView.extend(
|
|
16939
17065
|
@return {Ember.View} new instance
|
16940
17066
|
*/
|
16941
17067
|
createChildView: function(view, attrs) {
|
16942
|
-
if (view.isView && view._parentView === this
|
17068
|
+
if (view.isView && view._parentView === this && view.container === this.container) {
|
17069
|
+
return view;
|
17070
|
+
}
|
17071
|
+
|
17072
|
+
attrs = attrs || {};
|
17073
|
+
attrs._parentView = this;
|
17074
|
+
attrs.container = this.container;
|
16943
17075
|
|
16944
17076
|
if (Ember.CoreView.detect(view)) {
|
16945
|
-
attrs = attrs || {};
|
16946
|
-
attrs._parentView = this;
|
16947
|
-
attrs.container = this.container;
|
16948
17077
|
attrs.templateData = attrs.templateData || get(this, 'templateData');
|
16949
17078
|
|
16950
17079
|
view = view.create(attrs);
|
16951
17080
|
|
16952
17081
|
// don't set the property on a virtual view, as they are invisible to
|
16953
17082
|
// consumers of the view API
|
16954
|
-
if (view.viewName) {
|
17083
|
+
if (view.viewName) {
|
17084
|
+
set(get(this, 'concreteView'), view.viewName, view);
|
17085
|
+
}
|
16955
17086
|
} else {
|
16956
17087
|
Ember.assert('You must pass instance or subclass of View', view.isView);
|
16957
17088
|
|
16958
|
-
|
16959
|
-
view.setProperties(attrs);
|
16960
|
-
}
|
17089
|
+
Ember.setProperties(view, attrs);
|
16961
17090
|
|
16962
17091
|
if (!get(view, 'templateData')) {
|
16963
17092
|
set(view, 'templateData', get(this, 'templateData'));
|
16964
17093
|
}
|
16965
|
-
|
16966
|
-
set(view, '_parentView', this);
|
16967
17094
|
}
|
16968
17095
|
|
16969
17096
|
return view;
|
@@ -17310,8 +17437,8 @@ Ember.View.applyAttributeBindings = function(elem, name, value) {
|
|
17310
17437
|
elem.attr(name, value);
|
17311
17438
|
}
|
17312
17439
|
} else if (name === 'value' || type === 'boolean') {
|
17313
|
-
// We can't set properties to undefined
|
17314
|
-
if (value
|
17440
|
+
// We can't set properties to undefined or null
|
17441
|
+
if (!value) { value = ''; }
|
17315
17442
|
|
17316
17443
|
if (value !== elem.prop(name)) {
|
17317
17444
|
// value and booleans should always be properties
|
@@ -18011,6 +18138,7 @@ Ember.ContainerView = Ember.View.extend(Ember.MutableArray, {
|
|
18011
18138
|
initializeViews: function(views, parentView, templateData) {
|
18012
18139
|
forEach(views, function(view) {
|
18013
18140
|
set(view, '_parentView', parentView);
|
18141
|
+
set(view, 'container', parentView && parentView.container);
|
18014
18142
|
|
18015
18143
|
if (!get(view, 'templateData')) {
|
18016
18144
|
set(view, 'templateData', templateData);
|
@@ -18476,6 +18604,103 @@ Ember.CollectionView.CONTAINER_MAP = {
|
|
18476
18604
|
|
18477
18605
|
|
18478
18606
|
|
18607
|
+
(function() {
|
18608
|
+
/**
|
18609
|
+
@module ember
|
18610
|
+
@submodule ember-views
|
18611
|
+
*/
|
18612
|
+
|
18613
|
+
/**
|
18614
|
+
An `Ember.Component` is a view that is completely
|
18615
|
+
isolated. Property access in its templates go
|
18616
|
+
to the view object and actions are targeted at
|
18617
|
+
the view object. There is no access to the
|
18618
|
+
surrounding context or outer controller; all
|
18619
|
+
contextual information is passed in.
|
18620
|
+
|
18621
|
+
The easiest way to create an `Ember.Component` is via
|
18622
|
+
a template. If you name a template
|
18623
|
+
`controls/my-foo`, you will be able to use
|
18624
|
+
`{{my-foo}}` in other templates, which will make
|
18625
|
+
an instance of the isolated control.
|
18626
|
+
|
18627
|
+
```html
|
18628
|
+
{{app-profile person=currentUser}}
|
18629
|
+
```
|
18630
|
+
|
18631
|
+
```html
|
18632
|
+
<!-- app-profile template -->
|
18633
|
+
<h1>{{person.title}}</h1>
|
18634
|
+
<img {{bindAttr src=person.avatar}}>
|
18635
|
+
<p class='signature'>{{person.signature}}</p>
|
18636
|
+
```
|
18637
|
+
|
18638
|
+
You can also use `yield` inside a template to
|
18639
|
+
include the **contents** of the custom tag:
|
18640
|
+
|
18641
|
+
```html
|
18642
|
+
{{#my-profile person=currentUser}}
|
18643
|
+
<p>Admin mode</p>
|
18644
|
+
{{/my-profile}}
|
18645
|
+
```
|
18646
|
+
|
18647
|
+
```html
|
18648
|
+
<!-- app-profile template -->
|
18649
|
+
|
18650
|
+
<h1>{{person.title}}</h1>
|
18651
|
+
{{yield}} <!-- block contents -->
|
18652
|
+
```
|
18653
|
+
|
18654
|
+
If you want to customize the control, in order to
|
18655
|
+
handle events or actions, you implement a subclass
|
18656
|
+
of `Ember.Component` named after the name of the
|
18657
|
+
control.
|
18658
|
+
|
18659
|
+
For example, you could implement the action
|
18660
|
+
`hello` for the `app-profile` control:
|
18661
|
+
|
18662
|
+
```js
|
18663
|
+
App.AppProfileComponent = Ember.Component.extend({
|
18664
|
+
hello: function(name) {
|
18665
|
+
console.log("Hello", name)
|
18666
|
+
}
|
18667
|
+
});
|
18668
|
+
```
|
18669
|
+
|
18670
|
+
And then use it in the control's template:
|
18671
|
+
|
18672
|
+
```html
|
18673
|
+
<!-- app-profile template -->
|
18674
|
+
|
18675
|
+
<h1>{{person.title}}</h1>
|
18676
|
+
{{yield}} <!-- block contents -->
|
18677
|
+
|
18678
|
+
<button {{action 'hello' person.name}}>
|
18679
|
+
Say Hello to {{person.name}}
|
18680
|
+
</button>
|
18681
|
+
```
|
18682
|
+
|
18683
|
+
Components must have a `-` in their name to avoid
|
18684
|
+
conflicts with built-in controls that wrap HTML
|
18685
|
+
elements. This is consistent with the same
|
18686
|
+
requirement in web components.
|
18687
|
+
|
18688
|
+
@class Component
|
18689
|
+
@namespace Ember
|
18690
|
+
@extends Ember.View
|
18691
|
+
*/
|
18692
|
+
Ember.Component = Ember.View.extend({
|
18693
|
+
init: function() {
|
18694
|
+
this._super();
|
18695
|
+
this.set('context', this);
|
18696
|
+
this.set('controller', this);
|
18697
|
+
}
|
18698
|
+
});
|
18699
|
+
|
18700
|
+
})();
|
18701
|
+
|
18702
|
+
|
18703
|
+
|
18479
18704
|
(function() {
|
18480
18705
|
|
18481
18706
|
})();
|
@@ -18546,7 +18771,6 @@ Ember.ViewTargetActionSupport = Ember.Mixin.create(Ember.TargetActionSupport, {
|
|
18546
18771
|
|
18547
18772
|
|
18548
18773
|
(function() {
|
18549
|
-
/*globals jQuery*/
|
18550
18774
|
/**
|
18551
18775
|
Ember Views
|
18552
18776
|
|
@@ -19071,7 +19295,71 @@ function makeBindings(options) {
|
|
19071
19295
|
}
|
19072
19296
|
}
|
19073
19297
|
|
19298
|
+
/**
|
19299
|
+
Register a bound helper or custom view helper.
|
19300
|
+
|
19301
|
+
## Simple bound helper example
|
19302
|
+
|
19303
|
+
```javascript
|
19304
|
+
Ember.Handlebars.helper('capitalize', function(value) {
|
19305
|
+
return value.toUpperCase();
|
19306
|
+
});
|
19307
|
+
```
|
19308
|
+
|
19309
|
+
The above bound helper can be used inside of templates as follows:
|
19310
|
+
|
19311
|
+
```handlebars
|
19312
|
+
{{capitalize name}}
|
19313
|
+
```
|
19314
|
+
|
19315
|
+
In this case, when the `name` property of the template's context changes,
|
19316
|
+
the rendered value of the helper will update to reflect this change.
|
19317
|
+
|
19318
|
+
For more examples of bound helpers, see documentation for
|
19319
|
+
`Ember.Handlebars.registerBoundHelper`.
|
19320
|
+
|
19321
|
+
## Custom view helper example
|
19322
|
+
|
19323
|
+
Assuming a view subclass named `App.CalenderView` were defined, a helper
|
19324
|
+
for rendering instances of this view could be registered as follows:
|
19325
|
+
|
19326
|
+
```javascript
|
19327
|
+
Ember.Handlebars.helper('calendar', App.CalendarView):
|
19328
|
+
```
|
19329
|
+
|
19330
|
+
The above bound helper can be used inside of templates as follows:
|
19331
|
+
|
19332
|
+
```handlebars
|
19333
|
+
{{calendar}}
|
19334
|
+
```
|
19335
|
+
|
19336
|
+
Which is functionally equivalent to:
|
19337
|
+
|
19338
|
+
```handlebars
|
19339
|
+
{{view App.CalendarView}}
|
19340
|
+
```
|
19341
|
+
|
19342
|
+
Options in the helper will be passed to the view in exactly the same
|
19343
|
+
manner as with the `view` helper.
|
19344
|
+
|
19345
|
+
@method helper
|
19346
|
+
@for Ember.Handlebars
|
19347
|
+
@param {String} name
|
19348
|
+
@param {Function|Ember.View} function or view class constructor
|
19349
|
+
@param {String} dependentKeys*
|
19350
|
+
*/
|
19074
19351
|
Ember.Handlebars.helper = function(name, value) {
|
19352
|
+
if (Ember.Component.detect(value)) {
|
19353
|
+
Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", name.match(/-/));
|
19354
|
+
|
19355
|
+
var proto = value.proto();
|
19356
|
+
if (!proto.layoutName && !proto.templateName) {
|
19357
|
+
value.reopen({
|
19358
|
+
layoutName: 'components/' + name
|
19359
|
+
});
|
19360
|
+
}
|
19361
|
+
}
|
19362
|
+
|
19075
19363
|
if (Ember.View.detect(value)) {
|
19076
19364
|
Ember.Handlebars.registerHelper(name, function(options) {
|
19077
19365
|
Ember.assert("You can only pass attributes as parameters (not values) to a application-defined helper", arguments.length < 2);
|
@@ -19832,7 +20120,7 @@ Ember._MetamorphView = Ember.View.extend(Ember._Metamorph);
|
|
19832
20120
|
/**
|
19833
20121
|
@class _SimpleMetamorphView
|
19834
20122
|
@namespace Ember
|
19835
|
-
@extends Ember.
|
20123
|
+
@extends Ember.CoreView
|
19836
20124
|
@uses Ember._Metamorph
|
19837
20125
|
@private
|
19838
20126
|
*/
|
@@ -22648,7 +22936,6 @@ Ember.SelectOption = Ember.View.extend({
|
|
22648
22936
|
|
22649
22937
|
```html
|
22650
22938
|
<select class="ember-select">
|
22651
|
-
<option value>Please Select</option>
|
22652
22939
|
<option value="1">Yehuda</option>
|
22653
22940
|
<option value="2">Tom</option>
|
22654
22941
|
</select>
|
@@ -22681,7 +22968,6 @@ Ember.SelectOption = Ember.View.extend({
|
|
22681
22968
|
|
22682
22969
|
```html
|
22683
22970
|
<select class="ember-select">
|
22684
|
-
<option value>Please Select</option>
|
22685
22971
|
<option value="1">Yehuda</option>
|
22686
22972
|
<option value="2" selected="selected">Tom</option>
|
22687
22973
|
</select>
|
@@ -22719,7 +23005,6 @@ Ember.SelectOption = Ember.View.extend({
|
|
22719
23005
|
|
22720
23006
|
```html
|
22721
23007
|
<select class="ember-select">
|
22722
|
-
<option value>Please Select</option>
|
22723
23008
|
<option value="1">Yehuda</option>
|
22724
23009
|
<option value="2" selected="selected">Tom</option>
|
22725
23010
|
</select>
|
@@ -22987,8 +23272,8 @@ function program3(depth0,data) {
|
|
22987
23272
|
var selection = get(this, 'selection');
|
22988
23273
|
var value = get(this, 'value');
|
22989
23274
|
|
22990
|
-
if (selection) { this.selectionDidChange(); }
|
22991
|
-
if (value) { this.valueDidChange(); }
|
23275
|
+
if (!Ember.isNone(selection)) { this.selectionDidChange(); }
|
23276
|
+
if (!Ember.isNone(value)) { this.valueDidChange(); }
|
22992
23277
|
|
22993
23278
|
this._change();
|
22994
23279
|
},
|
@@ -23185,6 +23470,31 @@ function bootstrap() {
|
|
23185
23470
|
Ember.Handlebars.bootstrap( Ember.$(document) );
|
23186
23471
|
}
|
23187
23472
|
|
23473
|
+
function registerComponents(container) {
|
23474
|
+
var templates = Ember.TEMPLATES, match;
|
23475
|
+
if (!templates) { return; }
|
23476
|
+
|
23477
|
+
for (var prop in templates) {
|
23478
|
+
if (match = prop.match(/^components\/(.*)$/)) {
|
23479
|
+
registerComponent(container, match[1]);
|
23480
|
+
}
|
23481
|
+
}
|
23482
|
+
}
|
23483
|
+
|
23484
|
+
function registerComponent(container, name) {
|
23485
|
+
Ember.assert("You provided a template named 'components/" + name + "', but custom components must include a '-'", name.match(/-/));
|
23486
|
+
|
23487
|
+
var className = name.replace(/-/g, '_');
|
23488
|
+
var Component = container.lookupFactory('component:' + className) || container.lookupFactory('component:' + name);
|
23489
|
+
var View = Component || Ember.Component.extend();
|
23490
|
+
|
23491
|
+
View.reopen({
|
23492
|
+
layoutName: 'components/' + name
|
23493
|
+
});
|
23494
|
+
|
23495
|
+
Ember.Handlebars.helper(name, View);
|
23496
|
+
}
|
23497
|
+
|
23188
23498
|
/*
|
23189
23499
|
We tie this to application.load to ensure that we've at least
|
23190
23500
|
attempted to bootstrap at the point that the application is loaded.
|
@@ -23196,7 +23506,23 @@ function bootstrap() {
|
|
23196
23506
|
from the DOM after processing.
|
23197
23507
|
*/
|
23198
23508
|
|
23199
|
-
Ember.onLoad('
|
23509
|
+
Ember.onLoad('Ember.Application', function(Application) {
|
23510
|
+
if (Application.initializer) {
|
23511
|
+
Application.initializer({
|
23512
|
+
name: 'domTemplates',
|
23513
|
+
initialize: bootstrap
|
23514
|
+
});
|
23515
|
+
|
23516
|
+
Application.initializer({
|
23517
|
+
name: 'registerComponents',
|
23518
|
+
after: 'domTemplates',
|
23519
|
+
initialize: registerComponents
|
23520
|
+
});
|
23521
|
+
} else {
|
23522
|
+
// for ember-old-router
|
23523
|
+
Ember.onLoad('application', bootstrap);
|
23524
|
+
}
|
23525
|
+
});
|
23200
23526
|
|
23201
23527
|
})();
|
23202
23528
|
|
@@ -23731,8 +24057,8 @@ define("route-recognizer",
|
|
23731
24057
|
|
23732
24058
|
(function() {
|
23733
24059
|
define("router",
|
23734
|
-
["route-recognizer"],
|
23735
|
-
function(RouteRecognizer) {
|
24060
|
+
["route-recognizer", "rsvp"],
|
24061
|
+
function(RouteRecognizer, RSVP) {
|
23736
24062
|
"use strict";
|
23737
24063
|
/**
|
23738
24064
|
@private
|
@@ -23753,34 +24079,171 @@ define("router",
|
|
23753
24079
|
*/
|
23754
24080
|
|
23755
24081
|
|
23756
|
-
|
23757
|
-
this.recognizer = new RouteRecognizer();
|
23758
|
-
}
|
23759
|
-
|
24082
|
+
var slice = Array.prototype.slice;
|
23760
24083
|
|
23761
|
-
Router.prototype = {
|
23762
|
-
/**
|
23763
|
-
The main entry point into the router. The API is essentially
|
23764
|
-
the same as the `map` method in `route-recognizer`.
|
23765
24084
|
|
23766
|
-
This method extracts the String handler at the last `.to()`
|
23767
|
-
call and uses it as the name of the whole route.
|
23768
24085
|
|
23769
|
-
|
23770
|
-
|
23771
|
-
map: function(callback) {
|
23772
|
-
this.recognizer.delegate = this.delegate;
|
24086
|
+
/**
|
24087
|
+
@private
|
23773
24088
|
|
23774
|
-
|
23775
|
-
|
23776
|
-
|
23777
|
-
|
23778
|
-
|
23779
|
-
|
24089
|
+
A Transition is a thennable (a promise-like object) that represents
|
24090
|
+
an attempt to transition to another route. It can be aborted, either
|
24091
|
+
explicitly via `abort` or by attempting another transition while a
|
24092
|
+
previous one is still underway. An aborted transition can also
|
24093
|
+
be `retry()`d later.
|
24094
|
+
*/
|
24095
|
+
|
24096
|
+
function Transition(router, promise) {
|
24097
|
+
this.router = router;
|
24098
|
+
this.promise = promise;
|
24099
|
+
this.data = {};
|
24100
|
+
this.resolvedModels = {};
|
24101
|
+
this.providedModels = {};
|
24102
|
+
this.providedModelsArray = [];
|
24103
|
+
this.sequence = ++Transition.currentSequence;
|
24104
|
+
this.params = {};
|
24105
|
+
}
|
24106
|
+
|
24107
|
+
Transition.currentSequence = 0;
|
24108
|
+
|
24109
|
+
Transition.prototype = {
|
24110
|
+
targetName: null,
|
24111
|
+
urlMethod: 'update',
|
24112
|
+
providedModels: null,
|
24113
|
+
resolvedModels: null,
|
24114
|
+
params: null,
|
23780
24115
|
|
23781
|
-
|
23782
|
-
|
23783
|
-
|
24116
|
+
/**
|
24117
|
+
The Transition's internal promise. Calling `.then` on this property
|
24118
|
+
is that same as calling `.then` on the Transition object itself, but
|
24119
|
+
this property is exposed for when you want to pass around a
|
24120
|
+
Transition's promise, but not the Transition object itself, since
|
24121
|
+
Transition object can be externally `abort`ed, while the promise
|
24122
|
+
cannot.
|
24123
|
+
*/
|
24124
|
+
promise: null,
|
24125
|
+
|
24126
|
+
/**
|
24127
|
+
Custom state can be stored on a Transition's `data` object.
|
24128
|
+
This can be useful for decorating a Transition within an earlier
|
24129
|
+
hook and shared with a later hook. Properties set on `data` will
|
24130
|
+
be copied to new transitions generated by calling `retry` on this
|
24131
|
+
transition.
|
24132
|
+
*/
|
24133
|
+
data: null,
|
24134
|
+
|
24135
|
+
/**
|
24136
|
+
A standard promise hook that resolves if the transition
|
24137
|
+
succeeds and rejects if it fails/redirects/aborts.
|
24138
|
+
|
24139
|
+
Forwards to the internal `promise` property which you can
|
24140
|
+
use in situations where you want to pass around a thennable,
|
24141
|
+
but not the Transition itself.
|
24142
|
+
|
24143
|
+
@param {Function} success
|
24144
|
+
@param {Function} failure
|
24145
|
+
*/
|
24146
|
+
then: function(success, failure) {
|
24147
|
+
return this.promise.then(success, failure);
|
24148
|
+
},
|
24149
|
+
|
24150
|
+
/**
|
24151
|
+
Aborts the Transition. Note you can also implicitly abort a transition
|
24152
|
+
by initiating another transition while a previous one is underway.
|
24153
|
+
*/
|
24154
|
+
abort: function() {
|
24155
|
+
if (this.isAborted) { return this; }
|
24156
|
+
log(this.router, this.sequence, this.targetName + ": transition was aborted");
|
24157
|
+
this.isAborted = true;
|
24158
|
+
this.router.activeTransition = null;
|
24159
|
+
return this;
|
24160
|
+
},
|
24161
|
+
|
24162
|
+
/**
|
24163
|
+
Retries a previously-aborted transition (making sure to abort the
|
24164
|
+
transition if it's still active). Returns a new transition that
|
24165
|
+
represents the new attempt to transition.
|
24166
|
+
*/
|
24167
|
+
retry: function() {
|
24168
|
+
this.abort();
|
24169
|
+
|
24170
|
+
var recogHandlers = this.router.recognizer.handlersFor(this.targetName),
|
24171
|
+
newTransition = performTransition(this.router, recogHandlers, this.providedModelsArray, this.params, this.data);
|
24172
|
+
|
24173
|
+
return newTransition;
|
24174
|
+
},
|
24175
|
+
|
24176
|
+
/**
|
24177
|
+
Sets the URL-changing method to be employed at the end of a
|
24178
|
+
successful transition. By default, a new Transition will just
|
24179
|
+
use `updateURL`, but passing 'replace' to this method will
|
24180
|
+
cause the URL to update using 'replaceWith' instead. Omitting
|
24181
|
+
a parameter will disable the URL change, allowing for transitions
|
24182
|
+
that don't update the URL at completion (this is also used for
|
24183
|
+
handleURL, since the URL has already changed before the
|
24184
|
+
transition took place).
|
24185
|
+
|
24186
|
+
@param {String} method the type of URL-changing method to use
|
24187
|
+
at the end of a transition. Accepted values are 'replace',
|
24188
|
+
falsy values, or any other non-falsy value (which is
|
24189
|
+
interpreted as an updateURL transition).
|
24190
|
+
|
24191
|
+
@return {Transition} this transition
|
24192
|
+
*/
|
24193
|
+
method: function(method) {
|
24194
|
+
this.urlMethod = method;
|
24195
|
+
return this;
|
24196
|
+
}
|
24197
|
+
};
|
24198
|
+
|
24199
|
+
function Router() {
|
24200
|
+
this.recognizer = new RouteRecognizer();
|
24201
|
+
}
|
24202
|
+
|
24203
|
+
|
24204
|
+
|
24205
|
+
/**
|
24206
|
+
Promise reject reasons passed to promise rejection
|
24207
|
+
handlers for failed transitions.
|
24208
|
+
*/
|
24209
|
+
Router.UnrecognizedURLError = function(message) {
|
24210
|
+
this.message = (message || "UnrecognizedURLError");
|
24211
|
+
this.name = "UnrecognizedURLError";
|
24212
|
+
};
|
24213
|
+
|
24214
|
+
Router.TransitionAborted = function(message) {
|
24215
|
+
this.message = (message || "TransitionAborted");
|
24216
|
+
this.name = "TransitionAborted";
|
24217
|
+
};
|
24218
|
+
|
24219
|
+
function errorTransition(router, reason) {
|
24220
|
+
return new Transition(router, RSVP.reject(reason));
|
24221
|
+
}
|
24222
|
+
|
24223
|
+
|
24224
|
+
Router.prototype = {
|
24225
|
+
/**
|
24226
|
+
The main entry point into the router. The API is essentially
|
24227
|
+
the same as the `map` method in `route-recognizer`.
|
24228
|
+
|
24229
|
+
This method extracts the String handler at the last `.to()`
|
24230
|
+
call and uses it as the name of the whole route.
|
24231
|
+
|
24232
|
+
@param {Function} callback
|
24233
|
+
*/
|
24234
|
+
map: function(callback) {
|
24235
|
+
this.recognizer.delegate = this.delegate;
|
24236
|
+
|
24237
|
+
this.recognizer.map(callback, function(recognizer, route) {
|
24238
|
+
var lastHandler = route[route.length - 1].handler;
|
24239
|
+
var args = [route, { as: lastHandler }];
|
24240
|
+
recognizer.add.apply(recognizer, args);
|
24241
|
+
});
|
24242
|
+
},
|
24243
|
+
|
24244
|
+
hasRoute: function(route) {
|
24245
|
+
return this.recognizer.hasRoute(route);
|
24246
|
+
},
|
23784
24247
|
|
23785
24248
|
/**
|
23786
24249
|
Clears the current and target route handlers and triggers exit
|
@@ -23788,7 +24251,8 @@ define("router",
|
|
23788
24251
|
its ancestors.
|
23789
24252
|
*/
|
23790
24253
|
reset: function() {
|
23791
|
-
eachHandler(this.currentHandlerInfos || [], function(
|
24254
|
+
eachHandler(this.currentHandlerInfos || [], function(handlerInfo) {
|
24255
|
+
var handler = handlerInfo.handler;
|
23792
24256
|
if (handler.exit) {
|
23793
24257
|
handler.exit();
|
23794
24258
|
}
|
@@ -23797,7 +24261,10 @@ define("router",
|
|
23797
24261
|
this.targetHandlerInfos = null;
|
23798
24262
|
},
|
23799
24263
|
|
24264
|
+
activeTransition: null,
|
24265
|
+
|
23800
24266
|
/**
|
24267
|
+
var handler = handlerInfo.handler;
|
23801
24268
|
The entry point for handling a change to the URL (usually
|
23802
24269
|
via the back and forward button).
|
23803
24270
|
|
@@ -23809,13 +24276,9 @@ define("router",
|
|
23809
24276
|
@return {Array} an Array of `[handler, parameter]` tuples
|
23810
24277
|
*/
|
23811
24278
|
handleURL: function(url) {
|
23812
|
-
|
23813
|
-
|
23814
|
-
|
23815
|
-
throw new Error("No route matched the URL '" + url + "'");
|
23816
|
-
}
|
23817
|
-
|
23818
|
-
collectObjects(this, results, 0, []);
|
24279
|
+
// Perform a URL-based transition, but don't change
|
24280
|
+
// the URL afterward, since it already happened.
|
24281
|
+
return doTransition(this, arguments).method(null);
|
23819
24282
|
},
|
23820
24283
|
|
23821
24284
|
/**
|
@@ -23847,8 +24310,7 @@ define("router",
|
|
23847
24310
|
@param {String} name the name of the route
|
23848
24311
|
*/
|
23849
24312
|
transitionTo: function(name) {
|
23850
|
-
|
23851
|
-
doTransition(this, name, this.updateURL, args);
|
24313
|
+
return doTransition(this, arguments);
|
23852
24314
|
},
|
23853
24315
|
|
23854
24316
|
/**
|
@@ -23860,8 +24322,7 @@ define("router",
|
|
23860
24322
|
@param {String} name the name of the route
|
23861
24323
|
*/
|
23862
24324
|
replaceWith: function(name) {
|
23863
|
-
|
23864
|
-
doTransition(this, name, this.replaceURL, args);
|
24325
|
+
return doTransition(this, arguments).method('replace');
|
23865
24326
|
},
|
23866
24327
|
|
23867
24328
|
/**
|
@@ -23875,8 +24336,7 @@ define("router",
|
|
23875
24336
|
@return {Object} a serialized parameter hash
|
23876
24337
|
*/
|
23877
24338
|
paramsForHandler: function(handlerName, callback) {
|
23878
|
-
|
23879
|
-
return output.params;
|
24339
|
+
return paramsForHandler(this, handlerName, slice.call(arguments, 1));
|
23880
24340
|
},
|
23881
24341
|
|
23882
24342
|
/**
|
@@ -23890,109 +24350,17 @@ define("router",
|
|
23890
24350
|
@return {String} a URL
|
23891
24351
|
*/
|
23892
24352
|
generate: function(handlerName) {
|
23893
|
-
var params =
|
24353
|
+
var params = paramsForHandler(this, handlerName, slice.call(arguments, 1));
|
23894
24354
|
return this.recognizer.generate(handlerName, params);
|
23895
24355
|
},
|
23896
24356
|
|
23897
|
-
/**
|
23898
|
-
@private
|
23899
|
-
|
23900
|
-
Used internally by `generate` and `transitionTo`.
|
23901
|
-
*/
|
23902
|
-
_paramsForHandler: function(handlerName, objects, doUpdate) {
|
23903
|
-
var handlers = this.recognizer.handlersFor(handlerName),
|
23904
|
-
params = {},
|
23905
|
-
toSetup = [],
|
23906
|
-
startIdx = handlers.length,
|
23907
|
-
objectsToMatch = objects.length,
|
23908
|
-
object, objectChanged, handlerObj, handler, names, i;
|
23909
|
-
|
23910
|
-
// Find out which handler to start matching at
|
23911
|
-
for (i=handlers.length-1; i>=0 && objectsToMatch>0; i--) {
|
23912
|
-
if (handlers[i].names.length) {
|
23913
|
-
objectsToMatch--;
|
23914
|
-
startIdx = i;
|
23915
|
-
}
|
23916
|
-
}
|
23917
|
-
|
23918
|
-
if (objectsToMatch > 0) {
|
23919
|
-
throw "More context objects were passed than there are dynamic segments for the route: "+handlerName;
|
23920
|
-
}
|
23921
|
-
|
23922
|
-
// Connect the objects to the routes
|
23923
|
-
for (i=0; i<handlers.length; i++) {
|
23924
|
-
handlerObj = handlers[i];
|
23925
|
-
handler = this.getHandler(handlerObj.handler);
|
23926
|
-
names = handlerObj.names;
|
23927
|
-
objectChanged = false;
|
23928
|
-
|
23929
|
-
// If it's a dynamic segment
|
23930
|
-
if (names.length) {
|
23931
|
-
// If we have objects, use them
|
23932
|
-
if (i >= startIdx) {
|
23933
|
-
object = objects.shift();
|
23934
|
-
objectChanged = true;
|
23935
|
-
// Otherwise use existing context
|
23936
|
-
} else {
|
23937
|
-
object = handler.context;
|
23938
|
-
}
|
23939
|
-
|
23940
|
-
// Serialize to generate params
|
23941
|
-
if (handler.serialize) {
|
23942
|
-
merge(params, handler.serialize(object, names));
|
23943
|
-
}
|
23944
|
-
// If it's not a dynamic segment and we're updating
|
23945
|
-
} else if (doUpdate) {
|
23946
|
-
// If we've passed the match point we need to deserialize again
|
23947
|
-
// or if we never had a context
|
23948
|
-
if (i > startIdx || !handler.hasOwnProperty('context')) {
|
23949
|
-
if (handler.deserialize) {
|
23950
|
-
object = handler.deserialize({});
|
23951
|
-
objectChanged = true;
|
23952
|
-
}
|
23953
|
-
// Otherwise use existing context
|
23954
|
-
} else {
|
23955
|
-
object = handler.context;
|
23956
|
-
}
|
23957
|
-
}
|
23958
|
-
|
23959
|
-
// Make sure that we update the context here so it's available to
|
23960
|
-
// subsequent deserialize calls
|
23961
|
-
if (doUpdate && objectChanged) {
|
23962
|
-
// TODO: It's a bit awkward to set the context twice, see if we can DRY things up
|
23963
|
-
setContext(handler, object);
|
23964
|
-
}
|
23965
|
-
|
23966
|
-
toSetup.push({
|
23967
|
-
isDynamic: !!handlerObj.names.length,
|
23968
|
-
name: handlerObj.handler,
|
23969
|
-
handler: handler,
|
23970
|
-
context: object
|
23971
|
-
});
|
23972
|
-
|
23973
|
-
if (i === handlers.length - 1) {
|
23974
|
-
var lastHandler = toSetup[toSetup.length - 1],
|
23975
|
-
additionalHandler;
|
23976
|
-
|
23977
|
-
if (additionalHandler = lastHandler.handler.additionalHandler) {
|
23978
|
-
handlers.push({
|
23979
|
-
handler: additionalHandler.call(lastHandler.handler),
|
23980
|
-
names: []
|
23981
|
-
});
|
23982
|
-
}
|
23983
|
-
}
|
23984
|
-
}
|
23985
|
-
|
23986
|
-
return { params: params, toSetup: toSetup };
|
23987
|
-
},
|
23988
|
-
|
23989
24357
|
isActive: function(handlerName) {
|
23990
|
-
var contexts =
|
24358
|
+
var contexts = slice.call(arguments, 1);
|
23991
24359
|
|
23992
24360
|
var targetHandlerInfos = this.targetHandlerInfos,
|
23993
24361
|
found = false, names, object, handlerInfo, handlerObj;
|
23994
24362
|
|
23995
|
-
if (!targetHandlerInfos) { return; }
|
24363
|
+
if (!targetHandlerInfos) { return false; }
|
23996
24364
|
|
23997
24365
|
for (var i=targetHandlerInfos.length-1; i>=0; i--) {
|
23998
24366
|
handlerInfo = targetHandlerInfos[i];
|
@@ -24012,165 +24380,169 @@ define("router",
|
|
24012
24380
|
},
|
24013
24381
|
|
24014
24382
|
trigger: function(name) {
|
24015
|
-
var args =
|
24016
|
-
trigger(this, args);
|
24017
|
-
}
|
24018
|
-
};
|
24383
|
+
var args = slice.call(arguments);
|
24384
|
+
trigger(this.currentHandlerInfos, false, args);
|
24385
|
+
},
|
24019
24386
|
|
24020
|
-
|
24021
|
-
|
24022
|
-
if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; }
|
24023
|
-
}
|
24024
|
-
}
|
24387
|
+
/**
|
24388
|
+
Hook point for logging transition status updates.
|
24025
24389
|
|
24026
|
-
|
24027
|
-
|
24028
|
-
|
24390
|
+
@param {String} message The message to log.
|
24391
|
+
*/
|
24392
|
+
log: null
|
24393
|
+
};
|
24029
24394
|
|
24030
24395
|
/**
|
24031
24396
|
@private
|
24032
24397
|
|
24033
|
-
|
24034
|
-
|
24035
|
-
|
24398
|
+
Used internally for both URL and named transition to determine
|
24399
|
+
a shared pivot parent route and other data necessary to perform
|
24400
|
+
a transition.
|
24401
|
+
*/
|
24402
|
+
function getMatchPoint(router, handlers, objects, inputParams) {
|
24403
|
+
|
24404
|
+
var objectsToMatch = objects.length,
|
24405
|
+
matchPoint = handlers.length,
|
24406
|
+
providedModels = {}, i,
|
24407
|
+
currentHandlerInfos = router.currentHandlerInfos || [],
|
24408
|
+
params = {},
|
24409
|
+
oldParams = router.currentParams || {},
|
24410
|
+
activeTransition = router.activeTransition,
|
24411
|
+
handlerParams = {};
|
24412
|
+
|
24413
|
+
merge(params, inputParams);
|
24414
|
+
|
24415
|
+
for (i = handlers.length - 1; i >= 0; i--) {
|
24416
|
+
var handlerObj = handlers[i],
|
24417
|
+
handlerName = handlerObj.handler,
|
24418
|
+
oldHandlerInfo = currentHandlerInfos[i],
|
24419
|
+
hasChanged = false;
|
24036
24420
|
|
24037
|
-
|
24038
|
-
|
24421
|
+
// Check if handler names have changed.
|
24422
|
+
if (!oldHandlerInfo || oldHandlerInfo.name !== handlerObj.handler) { hasChanged = true; }
|
24039
24423
|
|
24040
|
-
|
24041
|
-
|
24042
|
-
function loading(router) {
|
24043
|
-
if (!router.isLoading) {
|
24044
|
-
router.isLoading = true;
|
24045
|
-
var handler = router.getHandler('loading');
|
24046
|
-
|
24047
|
-
if (handler) {
|
24048
|
-
if (handler.enter) { handler.enter(); }
|
24049
|
-
if (handler.setup) { handler.setup(); }
|
24050
|
-
}
|
24051
|
-
}
|
24052
|
-
}
|
24424
|
+
if (handlerObj.isDynamic) {
|
24425
|
+
// URL transition.
|
24053
24426
|
|
24054
|
-
|
24055
|
-
|
24427
|
+
if (objectsToMatch > 0) {
|
24428
|
+
hasChanged = true;
|
24429
|
+
providedModels[handlerName] = objects[--objectsToMatch];
|
24430
|
+
} else {
|
24431
|
+
handlerParams[handlerName] = {};
|
24432
|
+
for (var prop in handlerObj.params) {
|
24433
|
+
if (!handlerObj.params.hasOwnProperty(prop)) { continue; }
|
24434
|
+
var newParam = handlerObj.params[prop];
|
24435
|
+
if (oldParams[prop] !== newParam) { hasChanged = true; }
|
24436
|
+
handlerParams[handlerName][prop] = params[prop] = newParam;
|
24437
|
+
}
|
24438
|
+
}
|
24439
|
+
} else if (handlerObj.hasOwnProperty('names') && handlerObj.names.length) {
|
24440
|
+
// Named transition.
|
24441
|
+
|
24442
|
+
if (objectsToMatch > 0) {
|
24443
|
+
hasChanged = true;
|
24444
|
+
providedModels[handlerName] = objects[--objectsToMatch];
|
24445
|
+
} else if (activeTransition && activeTransition.providedModels[handlerName]) {
|
24446
|
+
|
24447
|
+
// Use model from previous transition attempt, preferably the resolved one.
|
24448
|
+
hasChanged = true;
|
24449
|
+
providedModels[handlerName] = activeTransition.providedModels[handlerName] ||
|
24450
|
+
activeTransition.resolvedModels[handlerName];
|
24451
|
+
} else {
|
24452
|
+
var names = handlerObj.names;
|
24453
|
+
handlerParams[handlerName] = {};
|
24454
|
+
for (var j = 0, len = names.length; j < len; ++j) {
|
24455
|
+
var name = names[j];
|
24456
|
+
handlerParams[handlerName][name] = params[name] = oldParams[name];
|
24457
|
+
}
|
24458
|
+
}
|
24459
|
+
}
|
24056
24460
|
|
24057
|
-
|
24058
|
-
|
24461
|
+
if (hasChanged) { matchPoint = i; }
|
24462
|
+
}
|
24059
24463
|
|
24060
|
-
|
24464
|
+
if (objectsToMatch > 0) {
|
24465
|
+
throw "More context objects were passed than there are dynamic segments for the route: " + handlers[handlers.length - 1].handler;
|
24466
|
+
}
|
24061
24467
|
|
24062
|
-
|
24063
|
-
*/
|
24064
|
-
function loaded(router) {
|
24065
|
-
router.isLoading = false;
|
24066
|
-
var handler = router.getHandler('loading');
|
24067
|
-
if (handler && handler.exit) { handler.exit(); }
|
24468
|
+
return { matchPoint: matchPoint, providedModels: providedModels, params: params, handlerParams: handlerParams };
|
24068
24469
|
}
|
24069
24470
|
|
24070
24471
|
/**
|
24071
24472
|
@private
|
24072
24473
|
|
24073
|
-
This
|
24074
|
-
|
24075
|
-
|
24076
|
-
It triggers the `exit` method on the `loading` handler,
|
24077
|
-
the `enter` method on the `failure` handler, and the
|
24078
|
-
`setup` method on the `failure` handler with the
|
24079
|
-
`error`.
|
24474
|
+
This method takes a handler name and a list of contexts and returns
|
24475
|
+
a serialized parameter hash suitable to pass to `recognizer.generate()`.
|
24080
24476
|
|
24081
24477
|
@param {Router} router
|
24082
|
-
@param {
|
24083
|
-
|
24084
|
-
|
24478
|
+
@param {String} handlerName
|
24479
|
+
@param {Array[Object]} objects
|
24480
|
+
@return {Object} a serialized parameter hash
|
24085
24481
|
*/
|
24086
|
-
function
|
24087
|
-
|
24088
|
-
var
|
24089
|
-
|
24090
|
-
|
24091
|
-
|
24482
|
+
function paramsForHandler(router, handlerName, objects) {
|
24483
|
+
|
24484
|
+
var handlers = router.recognizer.handlersFor(handlerName),
|
24485
|
+
params = {},
|
24486
|
+
matchPoint = getMatchPoint(router, handlers, objects).matchPoint,
|
24487
|
+
object, handlerObj, handler, names, i;
|
24488
|
+
|
24489
|
+
for (i=0; i<handlers.length; i++) {
|
24490
|
+
handlerObj = handlers[i];
|
24491
|
+
handler = router.getHandler(handlerObj.handler);
|
24492
|
+
names = handlerObj.names;
|
24493
|
+
|
24494
|
+
// If it's a dynamic segment
|
24495
|
+
if (names.length) {
|
24496
|
+
// If we have objects, use them
|
24497
|
+
if (i >= matchPoint) {
|
24498
|
+
object = objects.shift();
|
24499
|
+
// Otherwise use existing context
|
24500
|
+
} else {
|
24501
|
+
object = handler.context;
|
24502
|
+
}
|
24503
|
+
|
24504
|
+
// Serialize to generate params
|
24505
|
+
merge(params, serialize(handler, object, names));
|
24506
|
+
}
|
24507
|
+
}
|
24508
|
+
return params;
|
24509
|
+
}
|
24510
|
+
|
24511
|
+
function merge(hash, other) {
|
24512
|
+
for (var prop in other) {
|
24513
|
+
if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; }
|
24092
24514
|
}
|
24093
24515
|
}
|
24094
24516
|
|
24095
24517
|
/**
|
24096
24518
|
@private
|
24097
24519
|
*/
|
24098
|
-
function
|
24099
|
-
var
|
24100
|
-
var params = output.params, toSetup = output.toSetup;
|
24520
|
+
function createNamedTransition(router, args) {
|
24521
|
+
var handlers = router.recognizer.handlersFor(args[0]);
|
24101
24522
|
|
24102
|
-
|
24103
|
-
method.call(router, url);
|
24523
|
+
log(router, "Attempting transition to " + args[0]);
|
24104
24524
|
|
24105
|
-
|
24525
|
+
return performTransition(router, handlers, slice.call(args, 1), router.currentParams);
|
24106
24526
|
}
|
24107
24527
|
|
24108
24528
|
/**
|
24109
24529
|
@private
|
24110
|
-
|
24111
|
-
This function is called after a URL change has been handled
|
24112
|
-
by `router.handleURL`.
|
24113
|
-
|
24114
|
-
Takes an Array of `RecognizedHandler`s, and converts the raw
|
24115
|
-
params hashes into deserialized objects by calling deserialize
|
24116
|
-
on the handlers. This process builds up an Array of
|
24117
|
-
`HandlerInfo`s. It then calls `setupContexts` with the Array.
|
24118
|
-
|
24119
|
-
If the `deserialize` method on a handler returns a promise
|
24120
|
-
(i.e. has a method called `then`), this function will pause
|
24121
|
-
building up the `HandlerInfo` Array until the promise is
|
24122
|
-
resolved. It will use the resolved value as the context of
|
24123
|
-
`HandlerInfo`.
|
24124
24530
|
*/
|
24125
|
-
function
|
24126
|
-
if (results.length === index) {
|
24127
|
-
var lastObject = objects[objects.length - 1],
|
24128
|
-
lastHandler = lastObject && lastObject.handler;
|
24129
|
-
|
24130
|
-
if (lastHandler && lastHandler.additionalHandler) {
|
24131
|
-
var additionalResult = {
|
24132
|
-
handler: lastHandler.additionalHandler(),
|
24133
|
-
params: {},
|
24134
|
-
isDynamic: false
|
24135
|
-
};
|
24136
|
-
results.push(additionalResult);
|
24137
|
-
} else {
|
24138
|
-
loaded(router);
|
24139
|
-
setupContexts(router, objects);
|
24140
|
-
return;
|
24141
|
-
}
|
24142
|
-
}
|
24531
|
+
function createURLTransition(router, url) {
|
24143
24532
|
|
24144
|
-
var
|
24145
|
-
|
24146
|
-
var object = handler.deserialize && handler.deserialize(result.params);
|
24533
|
+
var results = router.recognizer.recognize(url),
|
24534
|
+
currentHandlerInfos = router.currentHandlerInfos;
|
24147
24535
|
|
24148
|
-
|
24149
|
-
loading(router);
|
24536
|
+
log(router, "Attempting URL transition to " + url);
|
24150
24537
|
|
24151
|
-
|
24152
|
-
|
24153
|
-
failure(router, error);
|
24154
|
-
});
|
24155
|
-
} else {
|
24156
|
-
proceed(object);
|
24538
|
+
if (!results) {
|
24539
|
+
return errorTransition(router, new Router.UnrecognizedURLError(url));
|
24157
24540
|
}
|
24158
24541
|
|
24159
|
-
|
24160
|
-
if (handler.context !== object) {
|
24161
|
-
setContext(handler, object);
|
24162
|
-
}
|
24163
|
-
|
24164
|
-
var updatedObjects = objects.concat([{
|
24165
|
-
context: value,
|
24166
|
-
name: result.handler,
|
24167
|
-
handler: router.getHandler(result.handler),
|
24168
|
-
isDynamic: result.isDynamic
|
24169
|
-
}]);
|
24170
|
-
collectObjects(router, results, index + 1, updatedObjects);
|
24171
|
-
}
|
24542
|
+
return performTransition(router, results, [], {});
|
24172
24543
|
}
|
24173
24544
|
|
24545
|
+
|
24174
24546
|
/**
|
24175
24547
|
@private
|
24176
24548
|
|
@@ -24193,7 +24565,7 @@ define("router",
|
|
24193
24565
|
Consider the following transitions:
|
24194
24566
|
|
24195
24567
|
1. A URL transition to `/posts/1`.
|
24196
|
-
1. Triggers the `
|
24568
|
+
1. Triggers the `*model` callbacks on the
|
24197
24569
|
`index`, `posts`, and `showPost` handlers
|
24198
24570
|
2. Triggers the `enter` callback on the same
|
24199
24571
|
3. Triggers the `setup` callback on the same
|
@@ -24209,16 +24581,17 @@ define("router",
|
|
24209
24581
|
3. Triggers the `enter` callback on `about`
|
24210
24582
|
4. Triggers the `setup` callback on `about`
|
24211
24583
|
|
24212
|
-
@param {
|
24584
|
+
@param {Transition} transition
|
24213
24585
|
@param {Array[HandlerInfo]} handlerInfos
|
24214
24586
|
*/
|
24215
|
-
function setupContexts(
|
24216
|
-
var
|
24217
|
-
|
24587
|
+
function setupContexts(transition, handlerInfos) {
|
24588
|
+
var router = transition.router,
|
24589
|
+
partition = partitionHandlers(router.currentHandlerInfos || [], handlerInfos);
|
24218
24590
|
|
24219
24591
|
router.targetHandlerInfos = handlerInfos;
|
24220
24592
|
|
24221
|
-
eachHandler(partition.exited, function(
|
24593
|
+
eachHandler(partition.exited, function(handlerInfo) {
|
24594
|
+
var handler = handlerInfo.handler;
|
24222
24595
|
delete handler.context;
|
24223
24596
|
if (handler.exit) { handler.exit(); }
|
24224
24597
|
});
|
@@ -24226,33 +24599,51 @@ define("router",
|
|
24226
24599
|
var currentHandlerInfos = partition.unchanged.slice();
|
24227
24600
|
router.currentHandlerInfos = currentHandlerInfos;
|
24228
24601
|
|
24229
|
-
eachHandler(partition.updatedContext, function(
|
24230
|
-
|
24231
|
-
|
24232
|
-
|
24602
|
+
eachHandler(partition.updatedContext, function(handlerInfo) {
|
24603
|
+
handlerEnteredOrUpdated(transition, currentHandlerInfos, handlerInfo, false);
|
24604
|
+
});
|
24605
|
+
|
24606
|
+
eachHandler(partition.entered, function(handlerInfo) {
|
24607
|
+
handlerEnteredOrUpdated(transition, currentHandlerInfos, handlerInfo, true);
|
24233
24608
|
});
|
24234
24609
|
|
24235
|
-
|
24236
|
-
|
24237
|
-
|
24238
|
-
|
24610
|
+
if (router.didTransition) {
|
24611
|
+
router.didTransition(handlerInfos);
|
24612
|
+
}
|
24613
|
+
}
|
24614
|
+
|
24615
|
+
/**
|
24616
|
+
@private
|
24617
|
+
|
24618
|
+
Helper method used by setupContexts. Handles errors or redirects
|
24619
|
+
that may happen in enter/setup.
|
24620
|
+
*/
|
24621
|
+
function handlerEnteredOrUpdated(transition, currentHandlerInfos, handlerInfo, enter) {
|
24622
|
+
var handler = handlerInfo.handler,
|
24623
|
+
context = handlerInfo.context;
|
24624
|
+
|
24625
|
+
try {
|
24626
|
+
if (enter && handler.enter) { handler.enter(); }
|
24627
|
+
checkAbort(transition);
|
24628
|
+
|
24239
24629
|
setContext(handler, context);
|
24240
|
-
if (handler.setup) {
|
24241
|
-
if (false === handler.setup(context)) {
|
24242
|
-
aborted = true;
|
24243
|
-
}
|
24244
|
-
}
|
24245
24630
|
|
24246
|
-
if (
|
24247
|
-
|
24631
|
+
if (handler.setup) { handler.setup(context); }
|
24632
|
+
checkAbort(transition);
|
24633
|
+
} catch(e) {
|
24634
|
+
if (!(e instanceof Router.TransitionAborted)) {
|
24635
|
+
// Trigger the `error` event starting from this failed handler.
|
24636
|
+
trigger(currentHandlerInfos.concat(handlerInfo), true, ['error', e, transition]);
|
24248
24637
|
}
|
24249
|
-
});
|
24250
24638
|
|
24251
|
-
|
24252
|
-
|
24639
|
+
// Propagate the error so that the transition promise will reject.
|
24640
|
+
throw e;
|
24253
24641
|
}
|
24642
|
+
|
24643
|
+
currentHandlerInfos.push(handlerInfo);
|
24254
24644
|
}
|
24255
24645
|
|
24646
|
+
|
24256
24647
|
/**
|
24257
24648
|
@private
|
24258
24649
|
|
@@ -24264,11 +24655,7 @@ define("router",
|
|
24264
24655
|
*/
|
24265
24656
|
function eachHandler(handlerInfos, callback) {
|
24266
24657
|
for (var i=0, l=handlerInfos.length; i<l; i++) {
|
24267
|
-
|
24268
|
-
handler = handlerInfo.handler,
|
24269
|
-
context = handlerInfo.context;
|
24270
|
-
|
24271
|
-
callback(handler, context, handlerInfo);
|
24658
|
+
callback(handlerInfos[i]);
|
24272
24659
|
}
|
24273
24660
|
}
|
24274
24661
|
|
@@ -24348,19 +24735,19 @@ define("router",
|
|
24348
24735
|
return handlers;
|
24349
24736
|
}
|
24350
24737
|
|
24351
|
-
function trigger(
|
24352
|
-
var currentHandlerInfos = router.currentHandlerInfos;
|
24738
|
+
function trigger(handlerInfos, ignoreFailure, args) {
|
24353
24739
|
|
24354
24740
|
var name = args.shift();
|
24355
24741
|
|
24356
|
-
if (!
|
24742
|
+
if (!handlerInfos) {
|
24743
|
+
if (ignoreFailure) { return; }
|
24357
24744
|
throw new Error("Could not trigger event '" + name + "'. There are no active handlers");
|
24358
24745
|
}
|
24359
24746
|
|
24360
24747
|
var eventWasHandled = false;
|
24361
24748
|
|
24362
|
-
for (var i=
|
24363
|
-
var handlerInfo =
|
24749
|
+
for (var i=handlerInfos.length-1; i>=0; i--) {
|
24750
|
+
var handlerInfo = handlerInfos[i],
|
24364
24751
|
handler = handlerInfo.handler;
|
24365
24752
|
|
24366
24753
|
if (handler.events && handler.events[name]) {
|
@@ -24372,7 +24759,7 @@ define("router",
|
|
24372
24759
|
}
|
24373
24760
|
}
|
24374
24761
|
|
24375
|
-
if (!eventWasHandled) {
|
24762
|
+
if (!eventWasHandled && !ignoreFailure) {
|
24376
24763
|
throw new Error("Nothing handled the event '" + name + "'.");
|
24377
24764
|
}
|
24378
24765
|
}
|
@@ -24381,10 +24768,372 @@ define("router",
|
|
24381
24768
|
handler.context = context;
|
24382
24769
|
if (handler.contextDidChange) { handler.contextDidChange(); }
|
24383
24770
|
}
|
24771
|
+
|
24772
|
+
/**
|
24773
|
+
@private
|
24774
|
+
|
24775
|
+
Creates, begins, and returns a Transition.
|
24776
|
+
*/
|
24777
|
+
function performTransition(router, recogHandlers, providedModelsArray, params, data) {
|
24778
|
+
|
24779
|
+
var matchPointResults = getMatchPoint(router, recogHandlers, providedModelsArray, params),
|
24780
|
+
targetName = recogHandlers[recogHandlers.length - 1].handler,
|
24781
|
+
wasTransitioning = false;
|
24782
|
+
|
24783
|
+
// Check if there's already a transition underway.
|
24784
|
+
if (router.activeTransition) {
|
24785
|
+
if (transitionsIdentical(router.activeTransition, targetName, providedModelsArray)) {
|
24786
|
+
return router.activeTransition;
|
24787
|
+
}
|
24788
|
+
router.activeTransition.abort();
|
24789
|
+
wasTransitioning = true;
|
24790
|
+
}
|
24791
|
+
|
24792
|
+
var deferred = RSVP.defer(),
|
24793
|
+
transition = new Transition(router, deferred.promise);
|
24794
|
+
|
24795
|
+
transition.targetName = targetName;
|
24796
|
+
transition.providedModels = matchPointResults.providedModels;
|
24797
|
+
transition.providedModelsArray = providedModelsArray;
|
24798
|
+
transition.params = matchPointResults.params;
|
24799
|
+
transition.data = data || {};
|
24800
|
+
router.activeTransition = transition;
|
24801
|
+
|
24802
|
+
var handlerInfos = generateHandlerInfos(router, recogHandlers);
|
24803
|
+
|
24804
|
+
// Fire 'willTransition' event on current handlers, but don't fire it
|
24805
|
+
// if a transition was already underway.
|
24806
|
+
if (!wasTransitioning) {
|
24807
|
+
trigger(router.currentHandlerInfos, true, ['willTransition', transition]);
|
24808
|
+
}
|
24809
|
+
|
24810
|
+
log(router, transition.sequence, "Beginning validation for transition to " + transition.targetName);
|
24811
|
+
validateEntry(transition, handlerInfos, 0, matchPointResults.matchPoint, matchPointResults.handlerParams)
|
24812
|
+
.then(transitionSuccess, transitionFailure);
|
24813
|
+
|
24814
|
+
return transition;
|
24815
|
+
|
24816
|
+
function transitionSuccess() {
|
24817
|
+
checkAbort(transition);
|
24818
|
+
|
24819
|
+
try {
|
24820
|
+
finalizeTransition(transition, handlerInfos);
|
24821
|
+
|
24822
|
+
// Resolve with the final handler.
|
24823
|
+
deferred.resolve(handlerInfos[handlerInfos.length - 1].handler);
|
24824
|
+
} catch(e) {
|
24825
|
+
deferred.reject(e);
|
24826
|
+
}
|
24827
|
+
|
24828
|
+
// Don't nullify if another transition is underway (meaning
|
24829
|
+
// there was a transition initiated with enter/setup).
|
24830
|
+
if (!transition.isAborted) {
|
24831
|
+
router.activeTransition = null;
|
24832
|
+
}
|
24833
|
+
}
|
24834
|
+
|
24835
|
+
function transitionFailure(reason) {
|
24836
|
+
deferred.reject(reason);
|
24837
|
+
}
|
24838
|
+
}
|
24839
|
+
|
24840
|
+
/**
|
24841
|
+
@private
|
24842
|
+
|
24843
|
+
Accepts handlers in Recognizer format, either returned from
|
24844
|
+
recognize() or handlersFor(), and returns unified
|
24845
|
+
`HandlerInfo`s.
|
24846
|
+
*/
|
24847
|
+
function generateHandlerInfos(router, recogHandlers) {
|
24848
|
+
var handlerInfos = [];
|
24849
|
+
for (var i = 0, len = recogHandlers.length; i < len; ++i) {
|
24850
|
+
var handlerObj = recogHandlers[i],
|
24851
|
+
isDynamic = handlerObj.isDynamic || (handlerObj.names && handlerObj.names.length);
|
24852
|
+
|
24853
|
+
handlerInfos.push({
|
24854
|
+
isDynamic: !!isDynamic,
|
24855
|
+
name: handlerObj.handler,
|
24856
|
+
handler: router.getHandler(handlerObj.handler)
|
24857
|
+
});
|
24858
|
+
}
|
24859
|
+
return handlerInfos;
|
24860
|
+
}
|
24861
|
+
|
24862
|
+
/**
|
24863
|
+
@private
|
24864
|
+
*/
|
24865
|
+
function transitionsIdentical(oldTransition, targetName, providedModelsArray) {
|
24866
|
+
|
24867
|
+
if (oldTransition.targetName !== targetName) { return false; }
|
24868
|
+
|
24869
|
+
var oldModels = oldTransition.providedModelsArray;
|
24870
|
+
if (oldModels.length !== providedModelsArray.length) { return false; }
|
24871
|
+
|
24872
|
+
for (var i = 0, len = oldModels.length; i < len; ++i) {
|
24873
|
+
if (oldModels[i] !== providedModelsArray[i]) { return false; }
|
24874
|
+
}
|
24875
|
+
return true;
|
24876
|
+
}
|
24877
|
+
|
24878
|
+
/**
|
24879
|
+
@private
|
24880
|
+
|
24881
|
+
Updates the URL (if necessary) and calls `setupContexts`
|
24882
|
+
to update the router's array of `currentHandlerInfos`.
|
24883
|
+
*/
|
24884
|
+
function finalizeTransition(transition, handlerInfos) {
|
24885
|
+
|
24886
|
+
var router = transition.router,
|
24887
|
+
seq = transition.sequence,
|
24888
|
+
handlerName = handlerInfos[handlerInfos.length - 1].name;
|
24889
|
+
|
24890
|
+
log(router, seq, "Validation succeeded, finalizing transition;");
|
24891
|
+
|
24892
|
+
// Collect params for URL.
|
24893
|
+
var objects = [];
|
24894
|
+
for (var i = 0, len = handlerInfos.length; i < len; ++i) {
|
24895
|
+
var handlerInfo = handlerInfos[i];
|
24896
|
+
if (handlerInfo.isDynamic) {
|
24897
|
+
objects.push(handlerInfo.context);
|
24898
|
+
}
|
24899
|
+
}
|
24900
|
+
|
24901
|
+
var params = paramsForHandler(router, handlerName, objects);
|
24902
|
+
|
24903
|
+
transition.providedModelsArray = [];
|
24904
|
+
transition.providedContexts = {};
|
24905
|
+
router.currentParams = params;
|
24906
|
+
|
24907
|
+
var urlMethod = transition.urlMethod;
|
24908
|
+
if (urlMethod) {
|
24909
|
+
var url = router.recognizer.generate(handlerName, params);
|
24910
|
+
|
24911
|
+
if (urlMethod === 'replace') {
|
24912
|
+
router.replaceURL(url);
|
24913
|
+
} else {
|
24914
|
+
// Assume everything else is just a URL update for now.
|
24915
|
+
router.updateURL(url);
|
24916
|
+
}
|
24917
|
+
}
|
24918
|
+
|
24919
|
+
setupContexts(transition, handlerInfos);
|
24920
|
+
log(router, seq, "TRANSITION COMPLETE.");
|
24921
|
+
}
|
24922
|
+
|
24923
|
+
/**
|
24924
|
+
@private
|
24925
|
+
|
24926
|
+
Internal function used to construct the chain of promises used
|
24927
|
+
to validate a transition. Wraps calls to `beforeModel`, `model`,
|
24928
|
+
and `afterModel` in promises, and checks for redirects/aborts
|
24929
|
+
between each.
|
24930
|
+
*/
|
24931
|
+
function validateEntry(transition, handlerInfos, index, matchPoint, handlerParams) {
|
24932
|
+
|
24933
|
+
if (index === handlerInfos.length) {
|
24934
|
+
// No more contexts to resolve.
|
24935
|
+
return RSVP.resolve(transition.resolvedModels);
|
24936
|
+
}
|
24937
|
+
|
24938
|
+
var router = transition.router,
|
24939
|
+
handlerInfo = handlerInfos[index],
|
24940
|
+
handler = handlerInfo.handler,
|
24941
|
+
handlerName = handlerInfo.name,
|
24942
|
+
seq = transition.sequence,
|
24943
|
+
errorAlreadyHandled = false,
|
24944
|
+
resolvedModel;
|
24945
|
+
|
24946
|
+
if (index < matchPoint) {
|
24947
|
+
log(router, seq, handlerName + ": using context from already-active handler");
|
24948
|
+
|
24949
|
+
// We're before the match point, so don't run any hooks,
|
24950
|
+
// just use the already resolved context from the handler.
|
24951
|
+
resolvedModel = handlerInfo.handler.context;
|
24952
|
+
return proceed();
|
24953
|
+
}
|
24954
|
+
|
24955
|
+
return RSVP.resolve().then(handleAbort)
|
24956
|
+
.then(beforeModel)
|
24957
|
+
.then(null, handleError)
|
24958
|
+
.then(handleAbort)
|
24959
|
+
.then(model)
|
24960
|
+
.then(null, handleError)
|
24961
|
+
.then(handleAbort)
|
24962
|
+
.then(afterModel)
|
24963
|
+
.then(null, handleError)
|
24964
|
+
.then(handleAbort)
|
24965
|
+
.then(proceed);
|
24966
|
+
|
24967
|
+
function handleAbort(result) {
|
24968
|
+
|
24969
|
+
if (transition.isAborted) {
|
24970
|
+
log(transition.router, transition.sequence, "detected abort.");
|
24971
|
+
errorAlreadyHandled = true;
|
24972
|
+
return RSVP.reject(new Router.TransitionAborted());
|
24973
|
+
}
|
24974
|
+
|
24975
|
+
return result;
|
24976
|
+
}
|
24977
|
+
|
24978
|
+
function handleError(reason) {
|
24979
|
+
|
24980
|
+
if (errorAlreadyHandled) { return RSVP.reject(reason); }
|
24981
|
+
errorAlreadyHandled = true;
|
24982
|
+
transition.abort();
|
24983
|
+
|
24984
|
+
log(router, seq, handlerName + ": handling error: " + reason);
|
24985
|
+
|
24986
|
+
// An error was thrown / promise rejected, so fire an
|
24987
|
+
// `error` event from this handler info up to root.
|
24988
|
+
trigger(handlerInfos.slice(0, index + 1), true, ['error', reason, transition]);
|
24989
|
+
|
24990
|
+
if (handler.error) {
|
24991
|
+
handler.error(reason, transition); }
|
24992
|
+
|
24993
|
+
|
24994
|
+
// Propagate the original error.
|
24995
|
+
return RSVP.reject(reason);
|
24996
|
+
}
|
24997
|
+
|
24998
|
+
function beforeModel() {
|
24999
|
+
|
25000
|
+
log(router, seq, handlerName + ": calling beforeModel hook");
|
25001
|
+
|
25002
|
+
return handler.beforeModel && handler.beforeModel(transition);
|
25003
|
+
}
|
25004
|
+
|
25005
|
+
function model() {
|
25006
|
+
log(router, seq, handlerName + ": resolving model");
|
25007
|
+
|
25008
|
+
return getModel(handlerInfo, transition, handlerParams[handlerName], index >= matchPoint);
|
25009
|
+
}
|
25010
|
+
|
25011
|
+
function afterModel(context) {
|
25012
|
+
|
25013
|
+
log(router, seq, handlerName + ": calling afterModel hook");
|
25014
|
+
|
25015
|
+
// Pass the context and resolved parent contexts to afterModel, but we don't
|
25016
|
+
// want to use the value returned from `afterModel` in any way, but rather
|
25017
|
+
// always resolve with the original `context` object.
|
25018
|
+
|
25019
|
+
resolvedModel = context;
|
25020
|
+
return handler.afterModel && handler.afterModel(resolvedModel, transition);
|
25021
|
+
}
|
25022
|
+
|
25023
|
+
function proceed() {
|
25024
|
+
log(router, seq, handlerName + ": validation succeeded, proceeding");
|
25025
|
+
|
25026
|
+
handlerInfo.context = transition.resolvedModels[handlerInfo.name] = resolvedModel;
|
25027
|
+
return validateEntry(transition, handlerInfos, index + 1, matchPoint, handlerParams);
|
25028
|
+
}
|
25029
|
+
}
|
25030
|
+
|
25031
|
+
/**
|
25032
|
+
@private
|
25033
|
+
|
25034
|
+
Throws a TransitionAborted if the provided transition has been aborted.
|
25035
|
+
*/
|
25036
|
+
function checkAbort(transition) {
|
25037
|
+
if (transition.isAborted) {
|
25038
|
+
log(transition.router, transition.sequence, "detected abort.");
|
25039
|
+
throw new Router.TransitionAborted();
|
25040
|
+
}
|
25041
|
+
}
|
25042
|
+
|
25043
|
+
/**
|
25044
|
+
@private
|
25045
|
+
|
25046
|
+
Encapsulates the logic for whether to call `model` on a route,
|
25047
|
+
or use one of the models provided to `transitionTo`.
|
25048
|
+
*/
|
25049
|
+
function getModel(handlerInfo, transition, handlerParams, needsUpdate) {
|
25050
|
+
|
25051
|
+
var handler = handlerInfo.handler,
|
25052
|
+
handlerName = handlerInfo.name;
|
25053
|
+
|
25054
|
+
if (!needsUpdate && handler.hasOwnProperty('context')) {
|
25055
|
+
return handler.context;
|
25056
|
+
}
|
25057
|
+
|
25058
|
+
if (handlerInfo.isDynamic && transition.providedModels.hasOwnProperty(handlerName)) {
|
25059
|
+
var providedModel = transition.providedModels[handlerName];
|
25060
|
+
return typeof providedModel === 'function' ? providedModel() : providedModel;
|
25061
|
+
}
|
25062
|
+
|
25063
|
+
return handler.model && handler.model(handlerParams || {}, transition);
|
25064
|
+
}
|
25065
|
+
|
25066
|
+
/**
|
25067
|
+
@private
|
25068
|
+
*/
|
25069
|
+
function log(router, sequence, msg) {
|
25070
|
+
|
25071
|
+
if (!router.log) { return; }
|
25072
|
+
|
25073
|
+
if (arguments.length === 3) {
|
25074
|
+
router.log("Transition #" + sequence + ": " + msg);
|
25075
|
+
} else {
|
25076
|
+
msg = sequence;
|
25077
|
+
router.log(msg);
|
25078
|
+
}
|
25079
|
+
}
|
25080
|
+
|
25081
|
+
/**
|
25082
|
+
@private
|
25083
|
+
|
25084
|
+
Begins and returns a Transition based on the provided
|
25085
|
+
arguments. Accepts arguments in the form of both URL
|
25086
|
+
transitions and named transitions.
|
25087
|
+
|
25088
|
+
@param {Router} router
|
25089
|
+
@param {Array[Object]} args arguments passed to transitionTo,
|
25090
|
+
replaceWith, or handleURL
|
25091
|
+
*/
|
25092
|
+
function doTransition(router, args) {
|
25093
|
+
// Normalize blank transitions to root URL transitions.
|
25094
|
+
var name = args[0] || '/';
|
25095
|
+
|
25096
|
+
if (name.charAt(0) === '/') {
|
25097
|
+
return createURLTransition(router, name);
|
25098
|
+
} else {
|
25099
|
+
return createNamedTransition(router, args);
|
25100
|
+
}
|
25101
|
+
}
|
25102
|
+
|
25103
|
+
/**
|
25104
|
+
@private
|
25105
|
+
|
25106
|
+
Serializes a handler using its custom `serialize` method or
|
25107
|
+
by a default that looks up the expected property name from
|
25108
|
+
the dynamic segment.
|
25109
|
+
|
25110
|
+
@param {Object} handler a router handler
|
25111
|
+
@param {Object} model the model to be serialized for this handler
|
25112
|
+
@param {Array[Object]} names the names array attached to an
|
25113
|
+
handler object returned from router.recognizer.handlersFor()
|
25114
|
+
*/
|
25115
|
+
function serialize(handler, model, names) {
|
25116
|
+
|
25117
|
+
// Use custom serialize if it exists.
|
25118
|
+
if (handler.serialize) {
|
25119
|
+
return handler.serialize(model, names);
|
25120
|
+
}
|
25121
|
+
|
25122
|
+
if (names.length !== 1) { return; }
|
25123
|
+
|
25124
|
+
var name = names[0], object = {};
|
25125
|
+
|
25126
|
+
if (/_id$/.test(name)) {
|
25127
|
+
object[name] = model.id;
|
25128
|
+
} else {
|
25129
|
+
object[name] = model;
|
25130
|
+
}
|
25131
|
+
return object;
|
25132
|
+
}
|
25133
|
+
|
24384
25134
|
return Router;
|
24385
25135
|
});
|
24386
25136
|
|
24387
|
-
|
24388
25137
|
})();
|
24389
25138
|
|
24390
25139
|
|
@@ -24570,7 +25319,7 @@ Ember.Router = Ember.Object.extend({
|
|
24570
25319
|
location: 'hash',
|
24571
25320
|
|
24572
25321
|
init: function() {
|
24573
|
-
this.router = this.constructor.router;
|
25322
|
+
this.router = this.constructor.router || this.constructor.map(Ember.K);
|
24574
25323
|
this._activeViews = {};
|
24575
25324
|
setupLocation(this);
|
24576
25325
|
},
|
@@ -24615,34 +25364,21 @@ Ember.Router = Ember.Object.extend({
|
|
24615
25364
|
},
|
24616
25365
|
|
24617
25366
|
handleURL: function(url) {
|
24618
|
-
this
|
24619
|
-
this.notifyPropertyChange('url');
|
24620
|
-
},
|
24621
|
-
|
24622
|
-
/**
|
24623
|
-
Transition to another route via the `routeTo` event which
|
24624
|
-
will by default be handled by ApplicationRoute.
|
25367
|
+
scheduleLoadingStateEntry(this);
|
24625
25368
|
|
24626
|
-
|
24627
|
-
@param {TransitionEvent} transitionEvent
|
24628
|
-
*/
|
24629
|
-
routeTo: function(transitionEvent) {
|
24630
|
-
var handlerInfos = this.router.currentHandlerInfos;
|
24631
|
-
if (handlerInfos) {
|
24632
|
-
transitionEvent.sourceRoute = handlerInfos[handlerInfos.length - 1].handler;
|
24633
|
-
}
|
25369
|
+
var self = this;
|
24634
25370
|
|
24635
|
-
this.
|
25371
|
+
return this.router.handleURL(url).then(function() {
|
25372
|
+
transitionCompleted(self);
|
25373
|
+
});
|
24636
25374
|
},
|
24637
25375
|
|
24638
|
-
transitionTo: function(
|
24639
|
-
|
24640
|
-
doTransition(this, 'transitionTo', args);
|
25376
|
+
transitionTo: function() {
|
25377
|
+
return doTransition(this, 'transitionTo', arguments);
|
24641
25378
|
},
|
24642
25379
|
|
24643
25380
|
replaceWith: function() {
|
24644
|
-
|
24645
|
-
doTransition(this, 'replaceWith', args);
|
25381
|
+
return doTransition(this, 'replaceWith', arguments);
|
24646
25382
|
},
|
24647
25383
|
|
24648
25384
|
generate: function() {
|
@@ -24696,17 +25432,6 @@ Ember.Router = Ember.Object.extend({
|
|
24696
25432
|
}
|
24697
25433
|
});
|
24698
25434
|
|
24699
|
-
Ember.Router.reopenClass({
|
24700
|
-
defaultFailureHandler: {
|
24701
|
-
setup: function(error) {
|
24702
|
-
Ember.Logger.error('Error while loading route:', error);
|
24703
|
-
|
24704
|
-
// Using setTimeout allows us to escape from the Promise's try/catch block
|
24705
|
-
setTimeout(function() { throw error; });
|
24706
|
-
}
|
24707
|
-
}
|
24708
|
-
});
|
24709
|
-
|
24710
25435
|
function getHandlerFunction(router) {
|
24711
25436
|
var seen = {}, container = router.container,
|
24712
25437
|
DefaultRoute = container.resolve('route:basic');
|
@@ -24721,7 +25446,6 @@ function getHandlerFunction(router) {
|
|
24721
25446
|
|
24722
25447
|
if (!handler) {
|
24723
25448
|
if (name === 'loading') { return {}; }
|
24724
|
-
if (name === 'failure') { return router.constructor.defaultFailureHandler; }
|
24725
25449
|
|
24726
25450
|
container.register(routeName, DefaultRoute.extend());
|
24727
25451
|
handler = container.lookup(routeName);
|
@@ -24732,9 +25456,9 @@ function getHandlerFunction(router) {
|
|
24732
25456
|
}
|
24733
25457
|
|
24734
25458
|
if (name === 'application') {
|
24735
|
-
// Inject default `
|
25459
|
+
// Inject default `error` handler.
|
24736
25460
|
handler.events = handler.events || {};
|
24737
|
-
handler.events.
|
25461
|
+
handler.events.error = handler.events.error || defaultErrorHandler;
|
24738
25462
|
}
|
24739
25463
|
|
24740
25464
|
handler.routeName = name;
|
@@ -24742,6 +25466,14 @@ function getHandlerFunction(router) {
|
|
24742
25466
|
};
|
24743
25467
|
}
|
24744
25468
|
|
25469
|
+
function defaultErrorHandler(error, transition) {
|
25470
|
+
Ember.Logger.error('Error while loading route:', error);
|
25471
|
+
|
25472
|
+
// Using setTimeout allows us to escape from the Promise's try/catch block
|
25473
|
+
setTimeout(function() { throw error; });
|
25474
|
+
}
|
25475
|
+
|
25476
|
+
|
24745
25477
|
function routePath(handlerInfos) {
|
24746
25478
|
var path = [];
|
24747
25479
|
|
@@ -24786,24 +25518,76 @@ function setupRouter(emberRouter, router, location) {
|
|
24786
25518
|
}
|
24787
25519
|
|
24788
25520
|
function doTransition(router, method, args) {
|
25521
|
+
// Normalize blank route to root URL.
|
25522
|
+
args = [].slice.call(args);
|
25523
|
+
args[0] = args[0] || '/';
|
25524
|
+
|
24789
25525
|
var passedName = args[0], name;
|
24790
25526
|
|
24791
|
-
if (
|
24792
|
-
name = args[0] = passedName + '.index';
|
24793
|
-
} else {
|
25527
|
+
if (passedName.charAt(0) === '/') {
|
24794
25528
|
name = passedName;
|
25529
|
+
} else {
|
25530
|
+
if (!router.router.hasRoute(passedName)) {
|
25531
|
+
name = args[0] = passedName + '.index';
|
25532
|
+
} else {
|
25533
|
+
name = passedName;
|
25534
|
+
}
|
25535
|
+
|
25536
|
+
Ember.assert("The route " + passedName + " was not found", router.router.hasRoute(name));
|
25537
|
+
}
|
25538
|
+
|
25539
|
+
scheduleLoadingStateEntry(router);
|
25540
|
+
|
25541
|
+
var transitionPromise = router.router[method].apply(router.router, args);
|
25542
|
+
transitionPromise.then(function() {
|
25543
|
+
transitionCompleted(router);
|
25544
|
+
});
|
25545
|
+
|
25546
|
+
// We want to return the configurable promise object
|
25547
|
+
// so that callers of this function can use `.method()` on it,
|
25548
|
+
// which obviously doesn't exist for normal RSVP promises.
|
25549
|
+
return transitionPromise;
|
25550
|
+
}
|
25551
|
+
|
25552
|
+
function scheduleLoadingStateEntry(router) {
|
25553
|
+
if (router._loadingStateActive) { return; }
|
25554
|
+
router._shouldEnterLoadingState = true;
|
25555
|
+
Ember.run.scheduleOnce('routerTransitions', null, enterLoadingState, router);
|
25556
|
+
}
|
25557
|
+
|
25558
|
+
function enterLoadingState(router) {
|
25559
|
+
if (router._loadingStateActive || !router._shouldEnterLoadingState) { return; }
|
25560
|
+
|
25561
|
+
var loadingRoute = router.router.getHandler('loading');
|
25562
|
+
if (loadingRoute) {
|
25563
|
+
if (loadingRoute.enter) { loadingRoute.enter(); }
|
25564
|
+
if (loadingRoute.setup) { loadingRoute.setup(); }
|
25565
|
+
router._loadingStateActive = true;
|
24795
25566
|
}
|
25567
|
+
}
|
25568
|
+
|
25569
|
+
function exitLoadingState(router) {
|
25570
|
+
router._shouldEnterLoadingState = false;
|
25571
|
+
if (!router._loadingStateActive) { return; }
|
24796
25572
|
|
24797
|
-
|
25573
|
+
var loadingRoute = router.router.getHandler('loading');
|
25574
|
+
if (loadingRoute && loadingRoute.exit) { loadingRoute.exit(); }
|
25575
|
+
router._loadingStateActive = false;
|
25576
|
+
}
|
24798
25577
|
|
24799
|
-
|
25578
|
+
function transitionCompleted(router) {
|
24800
25579
|
router.notifyPropertyChange('url');
|
25580
|
+
exitLoadingState(router);
|
24801
25581
|
}
|
24802
25582
|
|
24803
25583
|
Ember.Router.reopenClass({
|
24804
25584
|
map: function(callback) {
|
24805
25585
|
var router = this.router = new Router();
|
24806
25586
|
|
25587
|
+
if (get(this, 'namespace.LOG_TRANSITIONS_INTERNAL')) {
|
25588
|
+
router.log = Ember.Logger.debug;
|
25589
|
+
}
|
25590
|
+
|
24807
25591
|
var dsl = Ember.RouterDSL.map(function() {
|
24808
25592
|
this.resource('application', { path: "/" }, function() {
|
24809
25593
|
callback.call(this);
|
@@ -24815,6 +25599,7 @@ Ember.Router.reopenClass({
|
|
24815
25599
|
}
|
24816
25600
|
});
|
24817
25601
|
|
25602
|
+
|
24818
25603
|
})();
|
24819
25604
|
|
24820
25605
|
|
@@ -24827,7 +25612,9 @@ Ember.Router.reopenClass({
|
|
24827
25612
|
|
24828
25613
|
var get = Ember.get, set = Ember.set,
|
24829
25614
|
classify = Ember.String.classify,
|
24830
|
-
fmt = Ember.String.fmt
|
25615
|
+
fmt = Ember.String.fmt,
|
25616
|
+
a_forEach = Ember.EnumerableUtils.forEach,
|
25617
|
+
a_replace = Ember.EnumerableUtils.replace;
|
24831
25618
|
|
24832
25619
|
/**
|
24833
25620
|
The `Ember.Route` class is used to define individual routes. Refer to
|
@@ -24845,7 +25632,7 @@ Ember.Route = Ember.Object.extend({
|
|
24845
25632
|
*/
|
24846
25633
|
exit: function() {
|
24847
25634
|
this.deactivate();
|
24848
|
-
|
25635
|
+
this.teardownViews();
|
24849
25636
|
},
|
24850
25637
|
|
24851
25638
|
/**
|
@@ -24869,6 +25656,104 @@ Ember.Route = Ember.Object.extend({
|
|
24869
25656
|
|
24870
25657
|
The context of the event will be this route.
|
24871
25658
|
|
25659
|
+
## Bubbling
|
25660
|
+
|
25661
|
+
By default, an event will stop bubbling once a handler defined
|
25662
|
+
on the `events` hash handles it. To continue bubbling the event,
|
25663
|
+
you must return `true` from the handler.
|
25664
|
+
|
25665
|
+
## Built-in events
|
25666
|
+
|
25667
|
+
There are a few built-in events pertaining to transitions that you
|
25668
|
+
can use to customize transition behavior: `willTransition` and
|
25669
|
+
`error`.
|
25670
|
+
|
25671
|
+
### `willTransition`
|
25672
|
+
|
25673
|
+
The `willTransition` event is fired at the beginning of any
|
25674
|
+
attempted transition with a `Transition` object as the sole
|
25675
|
+
argument. This event can be used for aborting, redirecting,
|
25676
|
+
or decorating the transition from the currently active routes.
|
25677
|
+
|
25678
|
+
A good example is preventing navigation when a form is
|
25679
|
+
half-filled out:
|
25680
|
+
|
25681
|
+
```js
|
25682
|
+
App.ContactFormRoute = Ember.Route.extend({
|
25683
|
+
events: {
|
25684
|
+
willTransition: function(transition) {
|
25685
|
+
if (this.controller.get('userHasEnteredData')) {
|
25686
|
+
this.controller.displayNavigationConfirm();
|
25687
|
+
transition.abort();
|
25688
|
+
}
|
25689
|
+
}
|
25690
|
+
}
|
25691
|
+
});
|
25692
|
+
```
|
25693
|
+
|
25694
|
+
You can also redirect elsewhere by calling
|
25695
|
+
`this.transitionTo('elsewhere')` from within `willTransition`.
|
25696
|
+
Note that `willTransition` will not be fired for the
|
25697
|
+
redirecting `transitionTo`, since `willTransition` doesn't
|
25698
|
+
fire when there is already a transition underway. If you want
|
25699
|
+
subsequent `willTransition` events to fire for the redirecting
|
25700
|
+
transition, you must first explicitly call
|
25701
|
+
`transition.abort()`.
|
25702
|
+
|
25703
|
+
### `error`
|
25704
|
+
|
25705
|
+
When attempting to transition into a route, any of the hooks
|
25706
|
+
may throw an error, or return a promise that rejects, at which
|
25707
|
+
point an `error` event will be fired on the partially-entered
|
25708
|
+
routes, allowing for per-route error handling logic, or shared
|
25709
|
+
error handling logic defined on a parent route.
|
25710
|
+
|
25711
|
+
Here is an example of an error handler that will be invoked
|
25712
|
+
for rejected promises / thrown errors from the various hooks
|
25713
|
+
on the route, as well as any unhandled errors from child
|
25714
|
+
routes:
|
25715
|
+
|
25716
|
+
```js
|
25717
|
+
App.AdminRoute = Ember.Route.extend({
|
25718
|
+
beforeModel: function() {
|
25719
|
+
throw "bad things!";
|
25720
|
+
// ...or, equivalently:
|
25721
|
+
return Ember.RSVP.reject("bad things!");
|
25722
|
+
},
|
25723
|
+
|
25724
|
+
events: {
|
25725
|
+
error: function(error, transition) {
|
25726
|
+
// Assuming we got here due to the error in `beforeModel`,
|
25727
|
+
// we can expect that error === "bad things!",
|
25728
|
+
// but a promise model rejecting would also
|
25729
|
+
// call this hook, as would any errors encountered
|
25730
|
+
// in `afterModel`.
|
25731
|
+
|
25732
|
+
// The `error` hook is also provided the failed
|
25733
|
+
// `transition`, which can be stored and later
|
25734
|
+
// `.retry()`d if desired.
|
25735
|
+
|
25736
|
+
this.transitionTo('login');
|
25737
|
+
}
|
25738
|
+
}
|
25739
|
+
});
|
25740
|
+
```
|
25741
|
+
|
25742
|
+
`error` events that bubble up all the way to `ApplicationRoute`
|
25743
|
+
will fire a default error handler that logs the error. You can
|
25744
|
+
specify your own global default error handler by overriding the
|
25745
|
+
`error` handler on `ApplicationRoute`:
|
25746
|
+
|
25747
|
+
```js
|
25748
|
+
App.ApplicationRoute = Ember.Route.extend({
|
25749
|
+
events: {
|
25750
|
+
error: function(error, transition) {
|
25751
|
+
this.controllerFor('banner').displayError(error.message);
|
25752
|
+
}
|
25753
|
+
}
|
25754
|
+
});
|
25755
|
+
```
|
25756
|
+
|
24872
25757
|
@see {Ember.Route#send}
|
24873
25758
|
@see {Handlebars.helpers.action}
|
24874
25759
|
|
@@ -24894,17 +25779,6 @@ Ember.Route = Ember.Object.extend({
|
|
24894
25779
|
*/
|
24895
25780
|
activate: Ember.K,
|
24896
25781
|
|
24897
|
-
/**
|
24898
|
-
Transition to another route via the `routeTo` event which
|
24899
|
-
will by default be handled by ApplicationRoute.
|
24900
|
-
|
24901
|
-
@method routeTo
|
24902
|
-
@param {TransitionEvent} transitionEvent
|
24903
|
-
*/
|
24904
|
-
routeTo: function(transitionEvent) {
|
24905
|
-
this.router.routeTo(transitionEvent);
|
24906
|
-
},
|
24907
|
-
|
24908
25782
|
/**
|
24909
25783
|
Transition into another route. Optionally supply a model for the
|
24910
25784
|
route in question. The model will be serialized into the URL
|
@@ -24916,13 +25790,6 @@ Ember.Route = Ember.Object.extend({
|
|
24916
25790
|
*/
|
24917
25791
|
transitionTo: function(name, context) {
|
24918
25792
|
var router = this.router;
|
24919
|
-
|
24920
|
-
// If the transition is a no-op, just bail.
|
24921
|
-
if (router.isActive.apply(router, arguments)) {
|
24922
|
-
return;
|
24923
|
-
}
|
24924
|
-
|
24925
|
-
if (this._checkingRedirect) { this._redirected[this._redirectDepth] = true; }
|
24926
25793
|
return router.transitionTo.apply(router, arguments);
|
24927
25794
|
},
|
24928
25795
|
|
@@ -24939,13 +25806,6 @@ Ember.Route = Ember.Object.extend({
|
|
24939
25806
|
*/
|
24940
25807
|
replaceWith: function() {
|
24941
25808
|
var router = this.router;
|
24942
|
-
|
24943
|
-
// If the transition is a no-op, just bail.
|
24944
|
-
if (router.isActive.apply(router, arguments)) {
|
24945
|
-
return;
|
24946
|
-
}
|
24947
|
-
|
24948
|
-
if (this._checkingRedirect) { this._redirected[this._redirectDepth] = true; }
|
24949
25809
|
return this.router.replaceWith.apply(this.router, arguments);
|
24950
25810
|
},
|
24951
25811
|
|
@@ -24953,15 +25813,6 @@ Ember.Route = Ember.Object.extend({
|
|
24953
25813
|
return this.router.send.apply(this.router, arguments);
|
24954
25814
|
},
|
24955
25815
|
|
24956
|
-
/**
|
24957
|
-
@private
|
24958
|
-
|
24959
|
-
Internal counter for tracking whether a route handler has
|
24960
|
-
called transitionTo or replaceWith inside its redirect hook.
|
24961
|
-
|
24962
|
-
*/
|
24963
|
-
_redirectDepth: 0,
|
24964
|
-
|
24965
25816
|
/**
|
24966
25817
|
@private
|
24967
25818
|
|
@@ -24970,58 +25821,6 @@ Ember.Route = Ember.Object.extend({
|
|
24970
25821
|
@method setup
|
24971
25822
|
*/
|
24972
25823
|
setup: function(context) {
|
24973
|
-
// Determine if this is the top-most transition.
|
24974
|
-
// If so, we'll set up a data structure to track
|
24975
|
-
// whether `transitionTo` or replaceWith gets called
|
24976
|
-
// inside our `redirect` hook.
|
24977
|
-
//
|
24978
|
-
// This is necessary because we set a flag on the route
|
24979
|
-
// inside transitionTo/replaceWith to determine afterwards
|
24980
|
-
// if they were called, but `setup` can be called
|
24981
|
-
// recursively and we need to disambiguate where in the
|
24982
|
-
// call stack the redirect happened.
|
24983
|
-
|
24984
|
-
// Are we the first call to setup? If so, set up the
|
24985
|
-
// redirect tracking data structure, and remember that
|
24986
|
-
// we're the top-most so we can clean it up later.
|
24987
|
-
var isTop;
|
24988
|
-
if (!this._redirected) {
|
24989
|
-
isTop = true;
|
24990
|
-
this._redirected = [];
|
24991
|
-
}
|
24992
|
-
|
24993
|
-
// Set a flag on this route saying that we are interested in
|
24994
|
-
// tracking redirects, and increment the depth count.
|
24995
|
-
this._checkingRedirect = true;
|
24996
|
-
var depth = ++this._redirectDepth;
|
24997
|
-
|
24998
|
-
// Check to see if context is set. This check preserves
|
24999
|
-
// the correct arguments.length inside the `redirect` hook.
|
25000
|
-
if (context === undefined) {
|
25001
|
-
this.redirect();
|
25002
|
-
} else {
|
25003
|
-
this.redirect(context);
|
25004
|
-
}
|
25005
|
-
|
25006
|
-
// After the call to `redirect` returns, decrement the depth count.
|
25007
|
-
this._redirectDepth--;
|
25008
|
-
this._checkingRedirect = false;
|
25009
|
-
|
25010
|
-
// Save off the data structure so we can reset it on the route but
|
25011
|
-
// still reference it later in this method.
|
25012
|
-
var redirected = this._redirected;
|
25013
|
-
|
25014
|
-
// If this is the top `setup` call in the call stack, clear the
|
25015
|
-
// redirect tracking data structure.
|
25016
|
-
if (isTop) { this._redirected = null; }
|
25017
|
-
|
25018
|
-
// If we were redirected, there is nothing left for us to do.
|
25019
|
-
// Returning false tells router.js not to continue calling setup
|
25020
|
-
// on any children route handlers.
|
25021
|
-
if (redirected[depth]) {
|
25022
|
-
return false;
|
25023
|
-
}
|
25024
|
-
|
25025
25824
|
var controller = this.controllerFor(this.routeName, context);
|
25026
25825
|
|
25027
25826
|
// Assign the route's controller so that it can more easily be
|
@@ -25044,29 +25843,131 @@ Ember.Route = Ember.Object.extend({
|
|
25044
25843
|
},
|
25045
25844
|
|
25046
25845
|
/**
|
25846
|
+
@deprecated
|
25847
|
+
|
25047
25848
|
A hook you can implement to optionally redirect to another route.
|
25048
25849
|
|
25049
25850
|
If you call `this.transitionTo` from inside of this hook, this route
|
25050
25851
|
will not be entered in favor of the other hook.
|
25051
25852
|
|
25853
|
+
This hook is deprecated in favor of using the `afterModel` hook
|
25854
|
+
for performing redirects after the model has resolved.
|
25855
|
+
|
25052
25856
|
@method redirect
|
25053
25857
|
@param {Object} model the model for this route
|
25054
25858
|
*/
|
25055
25859
|
redirect: Ember.K,
|
25056
25860
|
|
25057
25861
|
/**
|
25058
|
-
|
25862
|
+
This hook is the first of the route entry validation hooks
|
25863
|
+
called when an attempt is made to transition into a route
|
25864
|
+
or one of its children. It is called before `model` and
|
25865
|
+
`afterModel`, and is appropriate for cases when:
|
25866
|
+
|
25867
|
+
1) A decision can be made to redirect elsewhere without
|
25868
|
+
needing to resolve the model first.
|
25869
|
+
2) Any async operations need to occur first before the
|
25870
|
+
model is attempted to be resolved.
|
25871
|
+
|
25872
|
+
This hook is provided the current `transition` attempt
|
25873
|
+
as a parameter, which can be used to `.abort()` the transition,
|
25874
|
+
save it for a later `.retry()`, or retrieve values set
|
25875
|
+
on it from a previous hook. You can also just call
|
25876
|
+
`this.transitionTo` to another route to implicitly
|
25877
|
+
abort the `transition`.
|
25878
|
+
|
25879
|
+
You can return a promise from this hook to pause the
|
25880
|
+
transition until the promise resolves (or rejects). This could
|
25881
|
+
be useful, for instance, for retrieving async code from
|
25882
|
+
the server that is required to enter a route.
|
25883
|
+
|
25884
|
+
```js
|
25885
|
+
App.PostRoute = Ember.Route.extend({
|
25886
|
+
beforeModel: function(transition) {
|
25887
|
+
if (!App.Post) {
|
25888
|
+
return Ember.$.getScript('/models/post.js');
|
25889
|
+
}
|
25890
|
+
}
|
25891
|
+
});
|
25892
|
+
```
|
25893
|
+
|
25894
|
+
If `App.Post` doesn't exist in the above example,
|
25895
|
+
`beforeModel` will use jQuery's `getScript`, which
|
25896
|
+
returns a promise that resolves after the server has
|
25897
|
+
successfully retrieved and executed the code from the
|
25898
|
+
server. Note that if an error were to occur, it would
|
25899
|
+
be passed to the `error` hook on `Ember.Route`, but
|
25900
|
+
it's also possible to handle errors specific to
|
25901
|
+
`beforeModel` right from within the hook (to distinguish
|
25902
|
+
from the shared error handling behavior of the `error`
|
25903
|
+
hook):
|
25059
25904
|
|
25060
|
-
|
25061
|
-
|
25905
|
+
```js
|
25906
|
+
App.PostRoute = Ember.Route.extend({
|
25907
|
+
beforeModel: function(transition) {
|
25908
|
+
if (!App.Post) {
|
25909
|
+
var self = this;
|
25910
|
+
return Ember.$.getScript('post.js').then(null, function(e) {
|
25911
|
+
self.transitionTo('help');
|
25912
|
+
|
25913
|
+
// Note that the above transitionTo will implicitly
|
25914
|
+
// halt the transition. If you were to return
|
25915
|
+
// nothing from this promise reject handler,
|
25916
|
+
// according to promise semantics, that would
|
25917
|
+
// convert the reject into a resolve and the
|
25918
|
+
// transition would continue. To propagate the
|
25919
|
+
// error so that it'd be handled by the `error`
|
25920
|
+
// hook, you would have to either
|
25921
|
+
return Ember.RSVP.reject(e);
|
25922
|
+
// or
|
25923
|
+
throw e;
|
25924
|
+
});
|
25925
|
+
}
|
25926
|
+
}
|
25927
|
+
});
|
25928
|
+
```
|
25062
25929
|
|
25063
|
-
@
|
25930
|
+
@param {Transition} transition
|
25931
|
+
@return {Promise} if the value returned from this hook is
|
25932
|
+
a promise, the transition will pause until the transition
|
25933
|
+
resolves. Otherwise, non-promise return values are not
|
25934
|
+
utilized in any way.
|
25064
25935
|
*/
|
25065
|
-
|
25066
|
-
|
25067
|
-
|
25936
|
+
beforeModel: Ember.K,
|
25937
|
+
|
25938
|
+
/**
|
25939
|
+
This hook is called after this route's model has resolved.
|
25940
|
+
It follows identical async/promise semantics to `beforeModel`
|
25941
|
+
but is provided the route's resolved model in addition to
|
25942
|
+
the `transition`, and is therefore suited to performing
|
25943
|
+
logic that can only take place after the model has already
|
25944
|
+
resolved.
|
25945
|
+
|
25946
|
+
```js
|
25947
|
+
App.PostRoute = Ember.Route.extend({
|
25948
|
+
afterModel: function(posts, transition) {
|
25949
|
+
if (posts.length === 1) {
|
25950
|
+
this.transitionTo('post.show', posts[0]);
|
25951
|
+
}
|
25952
|
+
}
|
25953
|
+
});
|
25954
|
+
```
|
25955
|
+
|
25956
|
+
Refer to documentation for `beforeModel` for a description
|
25957
|
+
of transition-pausing semantics when a promise is returned
|
25958
|
+
from this hook.
|
25959
|
+
|
25960
|
+
@param {Transition} transition
|
25961
|
+
@return {Promise} if the value returned from this hook is
|
25962
|
+
a promise, the transition will pause until the transition
|
25963
|
+
resolves. Otherwise, non-promise return values are not
|
25964
|
+
utilized in any way.
|
25965
|
+
*/
|
25966
|
+
afterModel: function(resolvedModel, transition) {
|
25967
|
+
this.redirect(resolvedModel, transition);
|
25068
25968
|
},
|
25069
25969
|
|
25970
|
+
|
25070
25971
|
/**
|
25071
25972
|
@private
|
25072
25973
|
|
@@ -25104,10 +26005,15 @@ Ember.Route = Ember.Object.extend({
|
|
25104
26005
|
is not called. Routes without dynamic segments will always
|
25105
26006
|
execute the model hook.
|
25106
26007
|
|
26008
|
+
This hook follows the asynchronous/promise semantics
|
26009
|
+
described in the documentation for `beforeModel`. In particular,
|
26010
|
+
if a promise returned from `model` fails, the error will be
|
26011
|
+
handled by the `error` hook on `Ember.Route`.
|
26012
|
+
|
25107
26013
|
@method model
|
25108
26014
|
@param {Object} params the parameters extracted from the URL
|
25109
26015
|
*/
|
25110
|
-
model: function(params) {
|
26016
|
+
model: function(params, resolvedParentModels) {
|
25111
26017
|
var match, name, sawParams, value;
|
25112
26018
|
|
25113
26019
|
for (var prop in params) {
|
@@ -25265,7 +26171,19 @@ Ember.Route = Ember.Object.extend({
|
|
25265
26171
|
@return {Object} the model object
|
25266
26172
|
*/
|
25267
26173
|
modelFor: function(name) {
|
25268
|
-
|
26174
|
+
|
26175
|
+
var route = this.container.lookup('route:' + name),
|
26176
|
+
transition = this.router.router.activeTransition;
|
26177
|
+
|
26178
|
+
// If we are mid-transition, we want to try and look up
|
26179
|
+
// resolved parent contexts on the current transitionEvent.
|
26180
|
+
if (transition) {
|
26181
|
+
var modelLookupName = (route && route.routeName) || name;
|
26182
|
+
if (transition.resolvedModels.hasOwnProperty(modelLookupName)) {
|
26183
|
+
return transition.resolvedModels[modelLookupName];
|
26184
|
+
}
|
26185
|
+
}
|
26186
|
+
|
25269
26187
|
return route && route.currentModel;
|
25270
26188
|
},
|
25271
26189
|
|
@@ -25368,7 +26286,22 @@ Ember.Route = Ember.Object.extend({
|
|
25368
26286
|
},
|
25369
26287
|
|
25370
26288
|
willDestroy: function() {
|
25371
|
-
|
26289
|
+
this.teardownViews();
|
26290
|
+
},
|
26291
|
+
|
26292
|
+
teardownViews: function() {
|
26293
|
+
// Tear down the top level view
|
26294
|
+
if (this.teardownTopLevelView) { this.teardownTopLevelView(); }
|
26295
|
+
|
26296
|
+
// Tear down any outlets rendered with 'into'
|
26297
|
+
var teardownOutletViews = this.teardownOutletViews || [];
|
26298
|
+
a_forEach(teardownOutletViews, function(teardownOutletView) {
|
26299
|
+
teardownOutletView();
|
26300
|
+
});
|
26301
|
+
|
26302
|
+
delete this.teardownTopLevelView;
|
26303
|
+
delete this.teardownOutletViews;
|
26304
|
+
delete this.lastRenderedTemplate;
|
25372
26305
|
}
|
25373
26306
|
});
|
25374
26307
|
|
@@ -25457,94 +26390,30 @@ function setupView(view, container, options) {
|
|
25457
26390
|
function appendView(route, view, options) {
|
25458
26391
|
if (options.into) {
|
25459
26392
|
var parentView = route.router._lookupActiveView(options.into);
|
25460
|
-
|
26393
|
+
var teardownOutletView = generateOutletTeardown(parentView, options.outlet);
|
26394
|
+
if (!route.teardownOutletViews) { route.teardownOutletViews = []; }
|
26395
|
+
a_replace(route.teardownOutletViews, 0, 0, [teardownOutletView]);
|
25461
26396
|
parentView.connectOutlet(options.outlet, view);
|
25462
26397
|
} else {
|
25463
26398
|
var rootElement = get(route, 'router.namespace.rootElement');
|
25464
26399
|
// tear down view if one is already rendered
|
25465
|
-
if (route.
|
25466
|
-
route.
|
26400
|
+
if (route.teardownTopLevelView) {
|
26401
|
+
route.teardownTopLevelView();
|
25467
26402
|
}
|
25468
26403
|
route.router._connectActiveView(options.name, view);
|
25469
|
-
route.
|
26404
|
+
route.teardownTopLevelView = generateTopLevelTeardown(view);
|
25470
26405
|
view.appendTo(rootElement);
|
25471
26406
|
}
|
25472
26407
|
}
|
25473
26408
|
|
25474
|
-
function
|
26409
|
+
function generateTopLevelTeardown(view) {
|
25475
26410
|
return function() { view.destroy(); };
|
25476
26411
|
}
|
25477
26412
|
|
25478
|
-
function
|
26413
|
+
function generateOutletTeardown(parentView, outlet) {
|
25479
26414
|
return function() { parentView.disconnectOutlet(outlet); };
|
25480
26415
|
}
|
25481
26416
|
|
25482
|
-
function teardownView(route) {
|
25483
|
-
if (route.teardownView) { route.teardownView(); }
|
25484
|
-
|
25485
|
-
delete route.teardownView;
|
25486
|
-
delete route.lastRenderedTemplate;
|
25487
|
-
}
|
25488
|
-
|
25489
|
-
})();
|
25490
|
-
|
25491
|
-
|
25492
|
-
|
25493
|
-
(function() {
|
25494
|
-
/**
|
25495
|
-
@module ember
|
25496
|
-
@submodule ember-routing
|
25497
|
-
*/
|
25498
|
-
|
25499
|
-
|
25500
|
-
/*
|
25501
|
-
A TransitionEvent is passed as the argument for `transitionTo`
|
25502
|
-
events and contains information about an attempted transition
|
25503
|
-
that can be modified or decorated by leafier `transitionTo` event
|
25504
|
-
handlers before the actual transition is committed by ApplicationRoute.
|
25505
|
-
|
25506
|
-
@class TransitionEvent
|
25507
|
-
@namespace Ember
|
25508
|
-
@extends Ember.Deferred
|
25509
|
-
*/
|
25510
|
-
Ember.TransitionEvent = Ember.Object.extend({
|
25511
|
-
|
25512
|
-
/*
|
25513
|
-
The Ember.Route method used to perform the transition. Presently,
|
25514
|
-
the only valid values are 'transitionTo' and 'replaceWith'.
|
25515
|
-
*/
|
25516
|
-
transitionMethod: 'transitionTo',
|
25517
|
-
destinationRouteName: null,
|
25518
|
-
sourceRoute: null,
|
25519
|
-
contexts: null,
|
25520
|
-
|
25521
|
-
init: function() {
|
25522
|
-
this._super();
|
25523
|
-
this.contexts = this.contexts || [];
|
25524
|
-
},
|
25525
|
-
|
25526
|
-
/*
|
25527
|
-
Convenience method that returns an array that can be used for
|
25528
|
-
legacy `transitionTo` and `replaceWith`.
|
25529
|
-
*/
|
25530
|
-
transitionToArgs: function() {
|
25531
|
-
return [this.destinationRouteName].concat(this.contexts);
|
25532
|
-
}
|
25533
|
-
});
|
25534
|
-
|
25535
|
-
|
25536
|
-
Ember.TransitionEvent.reopenClass({
|
25537
|
-
/*
|
25538
|
-
This is the default transition event handler that will be injected
|
25539
|
-
into ApplicationRoute. The context, like all route event handlers in
|
25540
|
-
the events hash, will be an `Ember.Route`.
|
25541
|
-
*/
|
25542
|
-
defaultHandler: function(transitionEvent) {
|
25543
|
-
var router = this.router;
|
25544
|
-
router[transitionEvent.transitionMethod].apply(router, transitionEvent.transitionToArgs());
|
25545
|
-
}
|
25546
|
-
});
|
25547
|
-
|
25548
26417
|
})();
|
25549
26418
|
|
25550
26419
|
|
@@ -25622,34 +26491,133 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
|
|
25622
26491
|
}
|
25623
26492
|
|
25624
26493
|
/**
|
26494
|
+
`Ember.LinkView` renders an element whose `click` event triggers a
|
26495
|
+
transition of the application's instance of `Ember.Router` to
|
26496
|
+
a supplied route by name.
|
26497
|
+
|
26498
|
+
Instances of `LinkView` will most likely be created through
|
26499
|
+
the `linkTo` Handlebars helper, but properties of this class
|
26500
|
+
can be overridden to customize application-wide behavior.
|
26501
|
+
|
25625
26502
|
@class LinkView
|
25626
26503
|
@namespace Ember
|
25627
26504
|
@extends Ember.View
|
26505
|
+
@see {Handlebars.helpers.linkTo}
|
25628
26506
|
**/
|
25629
26507
|
var LinkView = Ember.LinkView = Ember.View.extend({
|
25630
26508
|
tagName: 'a',
|
25631
26509
|
namedRoute: null,
|
25632
26510
|
currentWhen: null,
|
26511
|
+
|
26512
|
+
/**
|
26513
|
+
Sets the `title` attribute of the `LinkView`'s HTML element.
|
26514
|
+
|
26515
|
+
@property title
|
26516
|
+
@default null
|
26517
|
+
**/
|
25633
26518
|
title: null,
|
26519
|
+
|
26520
|
+
/**
|
26521
|
+
The CSS class to apply to `LinkView`'s element when its `active`
|
26522
|
+
property is `true`.
|
26523
|
+
|
26524
|
+
@property activeClass
|
26525
|
+
@type String
|
26526
|
+
@default active
|
26527
|
+
**/
|
25634
26528
|
activeClass: 'active',
|
26529
|
+
|
26530
|
+
/**
|
26531
|
+
The CSS class to apply to a `LinkView`'s element when its `disabled`
|
26532
|
+
property is `true`.
|
26533
|
+
|
26534
|
+
@property disabledClass
|
26535
|
+
@type String
|
26536
|
+
@default disabled
|
26537
|
+
**/
|
25635
26538
|
disabledClass: 'disabled',
|
25636
26539
|
_isDisabled: false,
|
26540
|
+
|
26541
|
+
/**
|
26542
|
+
Determines whether the `LinkView` will trigger routing via
|
26543
|
+
the `replaceWith` routing strategy.
|
26544
|
+
|
26545
|
+
@type Boolean
|
26546
|
+
@default false
|
26547
|
+
**/
|
25637
26548
|
replace: false,
|
25638
26549
|
attributeBindings: ['href', 'title'],
|
25639
26550
|
classNameBindings: ['active', 'disabled'],
|
25640
26551
|
|
25641
|
-
|
25642
|
-
|
26552
|
+
/**
|
26553
|
+
By default the `{{linkTo}}` helper responds to the `click` event. You
|
26554
|
+
can override this globally by setting this property to your custom
|
26555
|
+
event name.
|
26556
|
+
|
26557
|
+
This is particularly useful on mobile when one wants to avoid the 300ms
|
26558
|
+
click delay using some sort of custom `tap` event.
|
26559
|
+
|
26560
|
+
@property eventName
|
26561
|
+
@type String
|
26562
|
+
@default click
|
26563
|
+
*/
|
26564
|
+
eventName: 'click',
|
26565
|
+
|
26566
|
+
// this is doc'ed here so it shows up in the events
|
26567
|
+
// section of the API documentation, which is where
|
26568
|
+
// people will likely go looking for it.
|
26569
|
+
/**
|
26570
|
+
Triggers the `LinkView`'s routing behavior. If
|
26571
|
+
`eventName` is changed to a value other than `click`
|
26572
|
+
the routing behavior will trigger on that custom event
|
26573
|
+
instead.
|
26574
|
+
|
26575
|
+
@event click
|
26576
|
+
**/
|
26577
|
+
|
26578
|
+
init: function() {
|
26579
|
+
this._super();
|
26580
|
+
// Map desired event name to invoke function
|
26581
|
+
var eventName = get(this, 'eventName');
|
26582
|
+
this.on(eventName, this, this._invoke);
|
26583
|
+
},
|
26584
|
+
|
26585
|
+
/**
|
26586
|
+
@private
|
26587
|
+
|
26588
|
+
Even though this isn't a virtual view, we want to treat it as if it is
|
26589
|
+
so that you can access the parent with {{view.prop}}
|
26590
|
+
|
26591
|
+
@method concreteView
|
26592
|
+
**/
|
25643
26593
|
concreteView: Ember.computed(function() {
|
25644
26594
|
return get(this, 'parentView');
|
25645
26595
|
}).property('parentView'),
|
25646
26596
|
|
26597
|
+
/**
|
26598
|
+
|
26599
|
+
Accessed as a classname binding to apply the `LinkView`'s `disabledClass`
|
26600
|
+
CSS `class` to the element when the link is disabled.
|
26601
|
+
|
26602
|
+
When `true` interactions with the element will not trigger route changes.
|
26603
|
+
@property disabled
|
26604
|
+
*/
|
25647
26605
|
disabled: Ember.computed(function(key, value) {
|
25648
26606
|
if (value !== undefined) { this.set('_isDisabled', value); }
|
25649
26607
|
|
25650
26608
|
return value ? this.get('disabledClass') : false;
|
25651
26609
|
}),
|
25652
26610
|
|
26611
|
+
/**
|
26612
|
+
Accessed as a classname binding to apply the `LinkView`'s `activeClass`
|
26613
|
+
CSS `class` to the element when the link is active.
|
26614
|
+
|
26615
|
+
A `LinkView` is considered active when its `currentWhen` property is `true`
|
26616
|
+
or the application's current route is the route the `LinkView` would trigger
|
26617
|
+
transitions into.
|
26618
|
+
|
26619
|
+
@property active
|
26620
|
+
**/
|
25653
26621
|
active: Ember.computed(function() {
|
25654
26622
|
var router = this.get('router'),
|
25655
26623
|
params = resolvedPaths(this.parameters),
|
@@ -25664,7 +26632,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
|
|
25664
26632
|
return this.get('controller').container.lookup('router:main');
|
25665
26633
|
}),
|
25666
26634
|
|
25667
|
-
|
26635
|
+
/**
|
26636
|
+
@private
|
26637
|
+
|
26638
|
+
Event handler that invokes the link, activating the associated route.
|
26639
|
+
|
26640
|
+
@method _invoke
|
26641
|
+
@param {Event} event
|
26642
|
+
*/
|
26643
|
+
_invoke: function(event) {
|
25668
26644
|
if (!isSimpleClick(event)) { return true; }
|
25669
26645
|
|
25670
26646
|
event.preventDefault();
|
@@ -25672,26 +26648,25 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
|
|
25672
26648
|
|
25673
26649
|
if (get(this, '_isDisabled')) { return false; }
|
25674
26650
|
|
25675
|
-
var router = this.get('router')
|
25676
|
-
|
25677
|
-
if (Ember.ENV.ENABLE_ROUTE_TO) {
|
25678
|
-
|
25679
|
-
var routeArgs = args(this, router);
|
26651
|
+
var router = this.get('router'),
|
26652
|
+
routeArgs = args(this, router);
|
25680
26653
|
|
25681
|
-
|
25682
|
-
|
25683
|
-
destinationRouteName: routeArgs[0],
|
25684
|
-
contexts: routeArgs.slice(1)
|
25685
|
-
}));
|
26654
|
+
if (this.get('replace')) {
|
26655
|
+
router.replaceWith.apply(router, routeArgs);
|
25686
26656
|
} else {
|
25687
|
-
|
25688
|
-
router.replaceWith.apply(router, args(this, router));
|
25689
|
-
} else {
|
25690
|
-
router.transitionTo.apply(router, args(this, router));
|
25691
|
-
}
|
26657
|
+
router.transitionTo.apply(router, routeArgs);
|
25692
26658
|
}
|
25693
26659
|
},
|
25694
26660
|
|
26661
|
+
/**
|
26662
|
+
Sets the element's `href` attribute to the url for
|
26663
|
+
the `LinkView`'s targeted route.
|
26664
|
+
|
26665
|
+
If the `LinkView`'s `tagName` is changed to a value other
|
26666
|
+
than `a`, this property will be ignored.
|
26667
|
+
|
26668
|
+
@property href
|
26669
|
+
**/
|
25695
26670
|
href: Ember.computed(function() {
|
25696
26671
|
if (this.get('tagName') !== 'a') { return false; }
|
25697
26672
|
|
@@ -25852,6 +26827,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
|
|
25852
26827
|
})
|
25853
26828
|
```
|
25854
26829
|
|
26830
|
+
It is also possible to override the default event in
|
26831
|
+
this manner:
|
26832
|
+
|
26833
|
+
``` javascript
|
26834
|
+
Ember.LinkView.reopen({
|
26835
|
+
eventName: 'customEventName'
|
26836
|
+
});
|
26837
|
+
```
|
26838
|
+
|
25855
26839
|
@method linkTo
|
25856
26840
|
@for Ember.Handlebars.helpers
|
25857
26841
|
@param {String} routeName
|
@@ -26043,8 +27027,12 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
|
|
26043
27027
|
|
26044
27028
|
view = container.lookup('view:' + name) || container.lookup('view:default');
|
26045
27029
|
|
26046
|
-
|
26047
|
-
|
27030
|
+
var controllerName = options.hash.controller;
|
27031
|
+
|
27032
|
+
// Look up the controller by name, if provided.
|
27033
|
+
if (controllerName) {
|
27034
|
+
controller = container.lookup('controller:' + controllerName, lookupOptions);
|
27035
|
+
Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", !!controller);
|
26048
27036
|
} else {
|
26049
27037
|
controller = Ember.controllerFor(container, name, context, lookupOptions);
|
26050
27038
|
}
|
@@ -26465,10 +27453,12 @@ if (Ember.ENV.EXPERIMENTAL_CONTROL_HELPER) {
|
|
26465
27453
|
childView.rerender();
|
26466
27454
|
}
|
26467
27455
|
|
26468
|
-
|
26469
|
-
|
26470
|
-
|
26471
|
-
|
27456
|
+
if (modelPath) {
|
27457
|
+
Ember.addObserver(this, modelPath, observer);
|
27458
|
+
childView.one('willDestroyElement', this, function() {
|
27459
|
+
Ember.removeObserver(this, modelPath, observer);
|
27460
|
+
});
|
27461
|
+
}
|
26472
27462
|
|
26473
27463
|
Ember.Handlebars.helpers.view.call(this, childView, options);
|
26474
27464
|
});
|
@@ -26593,7 +27583,7 @@ Ember.View.reopen({
|
|
26593
27583
|
_hasEquivalentView: function(outletName, view) {
|
26594
27584
|
var existingView = get(this, '_outlets.'+outletName);
|
26595
27585
|
return existingView &&
|
26596
|
-
existingView.
|
27586
|
+
existingView.constructor === view.constructor &&
|
26597
27587
|
existingView.get('template') === view.get('template') &&
|
26598
27588
|
existingView.get('context') === view.get('context');
|
26599
27589
|
},
|
@@ -26622,6 +27612,19 @@ Ember.View.reopen({
|
|
26622
27612
|
|
26623
27613
|
|
26624
27614
|
(function() {
|
27615
|
+
/**
|
27616
|
+
@module ember
|
27617
|
+
@submodule ember-views
|
27618
|
+
*/
|
27619
|
+
|
27620
|
+
// Add a new named queue after the 'actions' queue (where RSVP promises
|
27621
|
+
// resolve), which is used in router transitions to prevent unnecessary
|
27622
|
+
// loading state entry if all context promises resolve on the
|
27623
|
+
// 'actions' queue first.
|
27624
|
+
|
27625
|
+
var queues = Ember.run.queues,
|
27626
|
+
indexOf = Ember.ArrayPolyfills.indexOf;
|
27627
|
+
queues.splice(indexOf.call(queues, 'actions') + 1, 0, 'routerTransitions');
|
26625
27628
|
|
26626
27629
|
})();
|
26627
27630
|
|
@@ -27505,11 +28508,14 @@ DeprecatedContainer.prototype = {
|
|
27505
28508
|
|
27506
28509
|
In addition to creating your application's router, `Ember.Application` is
|
27507
28510
|
also responsible for telling the router when to start routing. Transitions
|
27508
|
-
between routes can be logged with the LOG_TRANSITIONS flag
|
28511
|
+
between routes can be logged with the LOG_TRANSITIONS flag, and more
|
28512
|
+
detailed intra-transition logging can be logged with
|
28513
|
+
the LOG_TRANSITIONS_INTERNAL flag:
|
27509
28514
|
|
27510
28515
|
```javascript
|
27511
28516
|
window.App = Ember.Application.create({
|
27512
|
-
LOG_TRANSITIONS: true
|
28517
|
+
LOG_TRANSITIONS: true, // basic logging of successful transitions
|
28518
|
+
LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps
|
27513
28519
|
});
|
27514
28520
|
```
|
27515
28521
|
|
@@ -28216,6 +29222,8 @@ Ember.ControllerMixin.reopen({
|
|
28216
29222
|
this.get('controllers.post'); // instance of App.PostController
|
28217
29223
|
```
|
28218
29224
|
|
29225
|
+
This is only available for singleton controllers.
|
29226
|
+
|
28219
29227
|
@property {Array} needs
|
28220
29228
|
@default []
|
28221
29229
|
*/
|
@@ -28278,8 +29286,6 @@ var get = Ember.get, set = Ember.set;
|
|
28278
29286
|
*/
|
28279
29287
|
Ember.State = Ember.Object.extend(Ember.Evented,
|
28280
29288
|
/** @scope Ember.State.prototype */{
|
28281
|
-
isState: true,
|
28282
|
-
|
28283
29289
|
/**
|
28284
29290
|
A reference to the parent state.
|
28285
29291
|
|
@@ -28389,20 +29395,24 @@ Ember.State = Ember.Object.extend(Ember.Evented,
|
|
28389
29395
|
|
28390
29396
|
setupChild: function(states, name, value) {
|
28391
29397
|
if (!value) { return false; }
|
29398
|
+
var instance;
|
28392
29399
|
|
28393
|
-
if (value.
|
29400
|
+
if (value instanceof Ember.State) {
|
28394
29401
|
set(value, 'name', name);
|
29402
|
+
instance = value;
|
29403
|
+
instance.container = this.container;
|
28395
29404
|
} else if (Ember.State.detect(value)) {
|
28396
|
-
|
28397
|
-
name: name
|
29405
|
+
instance = value.create({
|
29406
|
+
name: name,
|
29407
|
+
container: this.container
|
28398
29408
|
});
|
28399
29409
|
}
|
28400
29410
|
|
28401
|
-
if (
|
28402
|
-
set(
|
28403
|
-
get(this, 'childStates').pushObject(
|
28404
|
-
states[name] =
|
28405
|
-
return
|
29411
|
+
if (instance instanceof Ember.State) {
|
29412
|
+
set(instance, 'parentState', this);
|
29413
|
+
get(this, 'childStates').pushObject(instance);
|
29414
|
+
states[name] = instance;
|
29415
|
+
return instance;
|
28406
29416
|
}
|
28407
29417
|
},
|
28408
29418
|
|
@@ -29631,7 +30641,7 @@ Ember.Test = {
|
|
29631
30641
|
chained: false
|
29632
30642
|
};
|
29633
30643
|
thenable.then = function(onSuccess, onFailure) {
|
29634
|
-
var
|
30644
|
+
var thenPromise, nextPromise;
|
29635
30645
|
thenable.chained = true;
|
29636
30646
|
thenPromise = promise.then(onSuccess, onFailure);
|
29637
30647
|
// this is to ensure all downstream fulfillment
|
@@ -29804,33 +30814,32 @@ Test.QUnitAdapter = Test.Adapter.extend({
|
|
29804
30814
|
|
29805
30815
|
(function() {
|
29806
30816
|
var get = Ember.get,
|
29807
|
-
|
29808
|
-
|
30817
|
+
Test = Ember.Test,
|
30818
|
+
helper = Test.registerHelper,
|
29809
30819
|
countAsync = 0;
|
29810
30820
|
|
30821
|
+
Test.pendingAjaxRequests = 0;
|
29811
30822
|
|
29812
|
-
|
30823
|
+
Test.onInjectHelpers(function() {
|
29813
30824
|
Ember.$(document).ajaxStart(function() {
|
29814
|
-
pendingAjaxRequests++;
|
30825
|
+
Test.pendingAjaxRequests++;
|
29815
30826
|
});
|
29816
30827
|
|
29817
30828
|
Ember.$(document).ajaxStop(function() {
|
29818
|
-
pendingAjaxRequests--;
|
30829
|
+
Test.pendingAjaxRequests--;
|
29819
30830
|
});
|
29820
30831
|
});
|
29821
30832
|
|
29822
30833
|
|
29823
30834
|
function visit(app, url) {
|
29824
|
-
Ember.run(app, app.handleURL, url);
|
29825
30835
|
app.__container__.lookup('router:main').location.setURL(url);
|
30836
|
+
Ember.run(app, app.handleURL, url);
|
29826
30837
|
return wait(app);
|
29827
30838
|
}
|
29828
30839
|
|
29829
30840
|
function click(app, selector, context) {
|
29830
|
-
var $el =
|
29831
|
-
Ember.run(
|
29832
|
-
$el.click();
|
29833
|
-
});
|
30841
|
+
var $el = findWithAssert(app, selector, context);
|
30842
|
+
Ember.run($el, 'click');
|
29834
30843
|
return wait(app);
|
29835
30844
|
}
|
29836
30845
|
|
@@ -29840,42 +30849,49 @@ function fillIn(app, selector, context, text) {
|
|
29840
30849
|
text = context;
|
29841
30850
|
context = null;
|
29842
30851
|
}
|
29843
|
-
$el =
|
30852
|
+
$el = findWithAssert(app, selector, context);
|
29844
30853
|
Ember.run(function() {
|
29845
30854
|
$el.val(text).change();
|
29846
30855
|
});
|
29847
30856
|
return wait(app);
|
29848
30857
|
}
|
29849
30858
|
|
30859
|
+
function findWithAssert(app, selector, context) {
|
30860
|
+
var $el = find(app, selector, context);
|
30861
|
+
if ($el.length === 0) {
|
30862
|
+
throw("Element " + selector + " not found.");
|
30863
|
+
}
|
30864
|
+
return $el;
|
30865
|
+
}
|
30866
|
+
|
29850
30867
|
function find(app, selector, context) {
|
29851
30868
|
var $el;
|
29852
30869
|
context = context || get(app, 'rootElement');
|
29853
30870
|
$el = app.$(selector, context);
|
29854
|
-
|
29855
|
-
throw("Element " + selector + " not found.");
|
29856
|
-
}
|
30871
|
+
|
29857
30872
|
return $el;
|
29858
30873
|
}
|
29859
30874
|
|
29860
30875
|
function wait(app, value) {
|
29861
|
-
var promise
|
30876
|
+
var promise;
|
29862
30877
|
|
29863
|
-
promise =
|
30878
|
+
promise = Test.promise(function(resolve) {
|
29864
30879
|
if (++countAsync === 1) {
|
29865
|
-
|
30880
|
+
Test.adapter.asyncStart();
|
29866
30881
|
}
|
29867
30882
|
var watcher = setInterval(function() {
|
29868
30883
|
var routerIsLoading = app.__container__.lookup('router:main').router.isLoading;
|
29869
30884
|
if (routerIsLoading) { return; }
|
29870
|
-
if (pendingAjaxRequests) { return; }
|
30885
|
+
if (Test.pendingAjaxRequests) { return; }
|
29871
30886
|
if (Ember.run.hasScheduledTimers() || Ember.run.currentRunLoop) { return; }
|
30887
|
+
|
29872
30888
|
clearInterval(watcher);
|
30889
|
+
|
29873
30890
|
if (--countAsync === 0) {
|
29874
|
-
|
30891
|
+
Test.adapter.asyncEnd();
|
29875
30892
|
}
|
29876
|
-
|
29877
|
-
|
29878
|
-
});
|
30893
|
+
|
30894
|
+
Ember.run(null, resolve, value);
|
29879
30895
|
}, 10);
|
29880
30896
|
});
|
29881
30897
|
|
@@ -29930,6 +30946,7 @@ helper('visit', visit);
|
|
29930
30946
|
helper('click', click);
|
29931
30947
|
helper('fillIn', fillIn);
|
29932
30948
|
helper('find', find);
|
30949
|
+
helper('findWithAssert', findWithAssert);
|
29933
30950
|
helper('wait', wait);
|
29934
30951
|
|
29935
30952
|
})();
|