cadenero 0.0.2.a3 → 0.0.2.b1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
})();
|