angularjs-rails 1.5.8 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/lib/angularjs-rails/engine.rb +1 -1
- data/lib/angularjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/angular-animate.js +426 -293
- data/vendor/assets/javascripts/angular-aria.js +64 -43
- data/vendor/assets/javascripts/angular-cookies.js +24 -93
- data/vendor/assets/javascripts/angular-loader.js +190 -36
- data/vendor/assets/javascripts/angular-message-format.js +72 -84
- data/vendor/assets/javascripts/angular-messages.js +158 -68
- data/vendor/assets/javascripts/angular-mocks.js +1033 -402
- data/vendor/assets/javascripts/angular-parse-ext.js +14 -10
- data/vendor/assets/javascripts/angular-resource.js +317 -269
- data/vendor/assets/javascripts/angular-route.js +329 -132
- data/vendor/assets/javascripts/angular-sanitize.js +268 -93
- data/vendor/assets/javascripts/angular-touch.js +46 -413
- data/vendor/assets/javascripts/angular.js +9213 -4485
- metadata +2 -3
- data/vendor/assets/javascripts/angular-scenario.js +0 -44134
@@ -1,6 +1,6 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
3
|
-
* (c) 2010-
|
2
|
+
* @license AngularJS v1.8.0
|
3
|
+
* (c) 2010-2020 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
6
6
|
(function(window, angular) {'use strict';
|
@@ -32,43 +32,96 @@ function shallowCopy(src, dst) {
|
|
32
32
|
return dst || src;
|
33
33
|
}
|
34
34
|
|
35
|
+
/* global routeToRegExp: true */
|
36
|
+
|
37
|
+
/**
|
38
|
+
* @param {string} path - The path to parse. (It is assumed to have query and hash stripped off.)
|
39
|
+
* @param {Object} opts - Options.
|
40
|
+
* @return {Object} - An object containing an array of path parameter names (`keys`) and a regular
|
41
|
+
* expression (`regexp`) that can be used to identify a matching URL and extract the path
|
42
|
+
* parameter values.
|
43
|
+
*
|
44
|
+
* @description
|
45
|
+
* Parses the given path, extracting path parameter names and a regular expression to match URLs.
|
46
|
+
*
|
47
|
+
* Originally inspired by `pathRexp` in `visionmedia/express/lib/utils.js`.
|
48
|
+
*/
|
49
|
+
function routeToRegExp(path, opts) {
|
50
|
+
var keys = [];
|
51
|
+
|
52
|
+
var pattern = path
|
53
|
+
.replace(/([().])/g, '\\$1')
|
54
|
+
.replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) {
|
55
|
+
var optional = option === '?' || option === '*?';
|
56
|
+
var star = option === '*' || option === '*?';
|
57
|
+
keys.push({name: key, optional: optional});
|
58
|
+
slash = slash || '';
|
59
|
+
return (
|
60
|
+
(optional ? '(?:' + slash : slash + '(?:') +
|
61
|
+
(star ? '(.+?)' : '([^/]+)') +
|
62
|
+
(optional ? '?)?' : ')')
|
63
|
+
);
|
64
|
+
})
|
65
|
+
.replace(/([/$*])/g, '\\$1');
|
66
|
+
|
67
|
+
if (opts.ignoreTrailingSlashes) {
|
68
|
+
pattern = pattern.replace(/\/+$/, '') + '/*';
|
69
|
+
}
|
70
|
+
|
71
|
+
return {
|
72
|
+
keys: keys,
|
73
|
+
regexp: new RegExp(
|
74
|
+
'^' + pattern + '(?:[?#]|$)',
|
75
|
+
opts.caseInsensitiveMatch ? 'i' : ''
|
76
|
+
)
|
77
|
+
};
|
78
|
+
}
|
79
|
+
|
80
|
+
/* global routeToRegExp: false */
|
35
81
|
/* global shallowCopy: false */
|
36
82
|
|
37
|
-
//
|
83
|
+
// `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`).
|
38
84
|
// They are initialized inside the `$RouteProvider`, to ensure `window.angular` is available.
|
39
85
|
var isArray;
|
40
86
|
var isObject;
|
87
|
+
var isDefined;
|
88
|
+
var noop;
|
41
89
|
|
42
90
|
/**
|
43
91
|
* @ngdoc module
|
44
92
|
* @name ngRoute
|
45
93
|
* @description
|
46
94
|
*
|
47
|
-
*
|
48
|
-
*
|
49
|
-
* The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
|
95
|
+
* The `ngRoute` module provides routing and deeplinking services and directives for AngularJS apps.
|
50
96
|
*
|
51
97
|
* ## Example
|
52
|
-
* See {@link ngRoute.$route#
|
98
|
+
* See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`.
|
53
99
|
*
|
54
|
-
*
|
55
|
-
* <div doc-module-components="ngRoute"></div>
|
56
100
|
*/
|
57
|
-
|
58
|
-
var ngRouteModule = angular.
|
59
|
-
|
60
|
-
|
101
|
+
/* global -ngRouteModule */
|
102
|
+
var ngRouteModule = angular.
|
103
|
+
module('ngRoute', []).
|
104
|
+
info({ angularVersion: '1.8.0' }).
|
105
|
+
provider('$route', $RouteProvider).
|
106
|
+
// Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess`
|
107
|
+
// event (unless explicitly disabled). This is necessary in case `ngView` is included in an
|
108
|
+
// asynchronously loaded template.
|
109
|
+
run(instantiateRoute);
|
110
|
+
var $routeMinErr = angular.$$minErr('ngRoute');
|
111
|
+
var isEagerInstantiationEnabled;
|
112
|
+
|
61
113
|
|
62
114
|
/**
|
63
115
|
* @ngdoc provider
|
64
116
|
* @name $routeProvider
|
117
|
+
* @this
|
65
118
|
*
|
66
119
|
* @description
|
67
120
|
*
|
68
121
|
* Used for configuring routes.
|
69
122
|
*
|
70
123
|
* ## Example
|
71
|
-
* See {@link ngRoute.$route#
|
124
|
+
* See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`.
|
72
125
|
*
|
73
126
|
* ## Dependencies
|
74
127
|
* Requires the {@link ngRoute `ngRoute`} module to be installed.
|
@@ -76,6 +129,8 @@ var ngRouteModule = angular.module('ngRoute', ['ng']).
|
|
76
129
|
function $RouteProvider() {
|
77
130
|
isArray = angular.isArray;
|
78
131
|
isObject = angular.isObject;
|
132
|
+
isDefined = angular.isDefined;
|
133
|
+
noop = angular.noop;
|
79
134
|
|
80
135
|
function inherit(parent, extra) {
|
81
136
|
return angular.extend(Object.create(parent), extra);
|
@@ -112,12 +167,12 @@ function $RouteProvider() {
|
|
112
167
|
*
|
113
168
|
* Object properties:
|
114
169
|
*
|
115
|
-
* - `controller` – `{(string|
|
170
|
+
* - `controller` – `{(string|Function)=}` – Controller fn that should be associated with
|
116
171
|
* newly created scope or the name of a {@link angular.Module#controller registered
|
117
172
|
* controller} if passed as a string.
|
118
173
|
* - `controllerAs` – `{string=}` – An identifier name for a reference to the controller.
|
119
174
|
* If present, the controller will be published to scope under the `controllerAs` name.
|
120
|
-
* - `template` – `{string
|
175
|
+
* - `template` – `{(string|Function)=}` – html template as a string or a function that
|
121
176
|
* returns an html template as a string which should be used by {@link
|
122
177
|
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
|
123
178
|
* This property takes precedence over `templateUrl`.
|
@@ -127,7 +182,9 @@ function $RouteProvider() {
|
|
127
182
|
* - `{Array.<Object>}` - route parameters extracted from the current
|
128
183
|
* `$location.path()` by applying the current route
|
129
184
|
*
|
130
|
-
*
|
185
|
+
* One of `template` or `templateUrl` is required.
|
186
|
+
*
|
187
|
+
* - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html
|
131
188
|
* template that should be used by {@link ngRoute.directive:ngView ngView}.
|
132
189
|
*
|
133
190
|
* If `templateUrl` is a function, it will be called with the following parameters:
|
@@ -135,7 +192,9 @@ function $RouteProvider() {
|
|
135
192
|
* - `{Array.<Object>}` - route parameters extracted from the current
|
136
193
|
* `$location.path()` by applying the current route
|
137
194
|
*
|
138
|
-
*
|
195
|
+
* One of `templateUrl` or `template` is required.
|
196
|
+
*
|
197
|
+
* - `resolve` - `{Object.<string, Function>=}` - An optional map of dependencies which should
|
139
198
|
* be injected into the controller. If any of these dependencies are promises, the router
|
140
199
|
* will wait for them all to be resolved or one to be rejected before the controller is
|
141
200
|
* instantiated.
|
@@ -155,7 +214,7 @@ function $RouteProvider() {
|
|
155
214
|
* The map object is:
|
156
215
|
*
|
157
216
|
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
158
|
-
* - `factory` - `{string|
|
217
|
+
* - `factory` - `{string|Function}`: If `string` then it is an alias for a service.
|
159
218
|
* Otherwise if function, then it is {@link auto.$injector#invoke injected}
|
160
219
|
* and the return value is treated as the dependency. If the result is a promise, it is
|
161
220
|
* resolved before its value is injected into the controller. Be aware that
|
@@ -165,7 +224,7 @@ function $RouteProvider() {
|
|
165
224
|
* - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on
|
166
225
|
* the scope of the route. If omitted, defaults to `$resolve`.
|
167
226
|
*
|
168
|
-
* - `redirectTo` – `{(string|
|
227
|
+
* - `redirectTo` – `{(string|Function)=}` – value to update
|
169
228
|
* {@link ng.$location $location} path with and trigger route redirection.
|
170
229
|
*
|
171
230
|
* If `redirectTo` is a function, it will be called with the following parameters:
|
@@ -176,13 +235,48 @@ function $RouteProvider() {
|
|
176
235
|
* - `{Object}` - current `$location.search()`
|
177
236
|
*
|
178
237
|
* The custom `redirectTo` function is expected to return a string which will be used
|
179
|
-
* to update `$location.
|
238
|
+
* to update `$location.url()`. If the function throws an error, no further processing will
|
239
|
+
* take place and the {@link ngRoute.$route#$routeChangeError $routeChangeError} event will
|
240
|
+
* be fired.
|
241
|
+
*
|
242
|
+
* Routes that specify `redirectTo` will not have their controllers, template functions
|
243
|
+
* or resolves called, the `$location` will be changed to the redirect url and route
|
244
|
+
* processing will stop. The exception to this is if the `redirectTo` is a function that
|
245
|
+
* returns `undefined`. In this case the route transition occurs as though there was no
|
246
|
+
* redirection.
|
247
|
+
*
|
248
|
+
* - `resolveRedirectTo` – `{Function=}` – a function that will (eventually) return the value
|
249
|
+
* to update {@link ng.$location $location} URL with and trigger route redirection. In
|
250
|
+
* contrast to `redirectTo`, dependencies can be injected into `resolveRedirectTo` and the
|
251
|
+
* return value can be either a string or a promise that will be resolved to a string.
|
252
|
+
*
|
253
|
+
* Similar to `redirectTo`, if the return value is `undefined` (or a promise that gets
|
254
|
+
* resolved to `undefined`), no redirection takes place and the route transition occurs as
|
255
|
+
* though there was no redirection.
|
256
|
+
*
|
257
|
+
* If the function throws an error or the returned promise gets rejected, no further
|
258
|
+
* processing will take place and the
|
259
|
+
* {@link ngRoute.$route#$routeChangeError $routeChangeError} event will be fired.
|
260
|
+
*
|
261
|
+
* `redirectTo` takes precedence over `resolveRedirectTo`, so specifying both on the same
|
262
|
+
* route definition, will cause the latter to be ignored.
|
263
|
+
*
|
264
|
+
* - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes
|
265
|
+
* (including the path) even if the new URL maps to the same route.
|
266
|
+
*
|
267
|
+
* If the option is set to `false` and the URL in the browser changes, but the new URL maps
|
268
|
+
* to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without
|
269
|
+
* reloading the route).
|
180
270
|
*
|
181
271
|
* - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()`
|
182
272
|
* or `$location.hash()` changes.
|
183
273
|
*
|
184
|
-
* If the option is set to `false` and
|
185
|
-
*
|
274
|
+
* If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate`
|
275
|
+
* event is broadcasted on the root scope (without reloading the route).
|
276
|
+
*
|
277
|
+
* <div class="alert alert-warning">
|
278
|
+
* **Note:** This option has no effect if `reloadOnUrl` is set to `false`.
|
279
|
+
* </div>
|
186
280
|
*
|
187
281
|
* - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive
|
188
282
|
*
|
@@ -197,6 +291,9 @@ function $RouteProvider() {
|
|
197
291
|
this.when = function(path, route) {
|
198
292
|
//copy original route object to preserve params inherited from proto chain
|
199
293
|
var routeCopy = shallowCopy(route);
|
294
|
+
if (angular.isUndefined(routeCopy.reloadOnUrl)) {
|
295
|
+
routeCopy.reloadOnUrl = true;
|
296
|
+
}
|
200
297
|
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
|
201
298
|
routeCopy.reloadOnSearch = true;
|
202
299
|
}
|
@@ -205,18 +302,19 @@ function $RouteProvider() {
|
|
205
302
|
}
|
206
303
|
routes[path] = angular.extend(
|
207
304
|
routeCopy,
|
208
|
-
|
305
|
+
{originalPath: path},
|
306
|
+
path && routeToRegExp(path, routeCopy)
|
209
307
|
);
|
210
308
|
|
211
309
|
// create redirection for trailing slashes
|
212
310
|
if (path) {
|
213
|
-
var redirectPath = (path[path.length - 1]
|
311
|
+
var redirectPath = (path[path.length - 1] === '/')
|
214
312
|
? path.substr(0, path.length - 1)
|
215
313
|
: path + '/';
|
216
314
|
|
217
315
|
routes[redirectPath] = angular.extend(
|
218
|
-
{redirectTo: path},
|
219
|
-
|
316
|
+
{originalPath: path, redirectTo: path},
|
317
|
+
routeToRegExp(redirectPath, routeCopy)
|
220
318
|
);
|
221
319
|
}
|
222
320
|
|
@@ -234,47 +332,6 @@ function $RouteProvider() {
|
|
234
332
|
*/
|
235
333
|
this.caseInsensitiveMatch = false;
|
236
334
|
|
237
|
-
/**
|
238
|
-
* @param path {string} path
|
239
|
-
* @param opts {Object} options
|
240
|
-
* @return {?Object}
|
241
|
-
*
|
242
|
-
* @description
|
243
|
-
* Normalizes the given path, returning a regular expression
|
244
|
-
* and the original path.
|
245
|
-
*
|
246
|
-
* Inspired by pathRexp in visionmedia/express/lib/utils.js.
|
247
|
-
*/
|
248
|
-
function pathRegExp(path, opts) {
|
249
|
-
var insensitive = opts.caseInsensitiveMatch,
|
250
|
-
ret = {
|
251
|
-
originalPath: path,
|
252
|
-
regexp: path
|
253
|
-
},
|
254
|
-
keys = ret.keys = [];
|
255
|
-
|
256
|
-
path = path
|
257
|
-
.replace(/([().])/g, '\\$1')
|
258
|
-
.replace(/(\/)?:(\w+)(\*\?|[\?\*])?/g, function(_, slash, key, option) {
|
259
|
-
var optional = (option === '?' || option === '*?') ? '?' : null;
|
260
|
-
var star = (option === '*' || option === '*?') ? '*' : null;
|
261
|
-
keys.push({ name: key, optional: !!optional });
|
262
|
-
slash = slash || '';
|
263
|
-
return ''
|
264
|
-
+ (optional ? '' : slash)
|
265
|
-
+ '(?:'
|
266
|
-
+ (optional ? slash : '')
|
267
|
-
+ (star && '(.+?)' || '([^/]+)')
|
268
|
-
+ (optional || '')
|
269
|
-
+ ')'
|
270
|
-
+ (optional || '');
|
271
|
-
})
|
272
|
-
.replace(/([\/$\*])/g, '\\$1');
|
273
|
-
|
274
|
-
ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
|
275
|
-
return ret;
|
276
|
-
}
|
277
|
-
|
278
335
|
/**
|
279
336
|
* @ngdoc method
|
280
337
|
* @name $routeProvider#otherwise
|
@@ -295,6 +352,47 @@ function $RouteProvider() {
|
|
295
352
|
return this;
|
296
353
|
};
|
297
354
|
|
355
|
+
/**
|
356
|
+
* @ngdoc method
|
357
|
+
* @name $routeProvider#eagerInstantiationEnabled
|
358
|
+
* @kind function
|
359
|
+
*
|
360
|
+
* @description
|
361
|
+
* Call this method as a setter to enable/disable eager instantiation of the
|
362
|
+
* {@link ngRoute.$route $route} service upon application bootstrap. You can also call it as a
|
363
|
+
* getter (i.e. without any arguments) to get the current value of the
|
364
|
+
* `eagerInstantiationEnabled` flag.
|
365
|
+
*
|
366
|
+
* Instantiating `$route` early is necessary for capturing the initial
|
367
|
+
* {@link ng.$location#$locationChangeStart $locationChangeStart} event and navigating to the
|
368
|
+
* appropriate route. Usually, `$route` is instantiated in time by the
|
369
|
+
* {@link ngRoute.ngView ngView} directive. Yet, in cases where `ngView` is included in an
|
370
|
+
* asynchronously loaded template (e.g. in another directive's template), the directive factory
|
371
|
+
* might not be called soon enough for `$route` to be instantiated _before_ the initial
|
372
|
+
* `$locationChangeSuccess` event is fired. Eager instantiation ensures that `$route` is always
|
373
|
+
* instantiated in time, regardless of when `ngView` will be loaded.
|
374
|
+
*
|
375
|
+
* The default value is true.
|
376
|
+
*
|
377
|
+
* **Note**:<br />
|
378
|
+
* You may want to disable the default behavior when unit-testing modules that depend on
|
379
|
+
* `ngRoute`, in order to avoid an unexpected request for the default route's template.
|
380
|
+
*
|
381
|
+
* @param {boolean=} enabled - If provided, update the internal `eagerInstantiationEnabled` flag.
|
382
|
+
*
|
383
|
+
* @returns {*} The current value of the `eagerInstantiationEnabled` flag if used as a getter or
|
384
|
+
* itself (for chaining) if used as a setter.
|
385
|
+
*/
|
386
|
+
isEagerInstantiationEnabled = true;
|
387
|
+
this.eagerInstantiationEnabled = function eagerInstantiationEnabled(enabled) {
|
388
|
+
if (isDefined(enabled)) {
|
389
|
+
isEagerInstantiationEnabled = enabled;
|
390
|
+
return this;
|
391
|
+
}
|
392
|
+
|
393
|
+
return isEagerInstantiationEnabled;
|
394
|
+
};
|
395
|
+
|
298
396
|
|
299
397
|
this.$get = ['$rootScope',
|
300
398
|
'$location',
|
@@ -303,7 +401,8 @@ function $RouteProvider() {
|
|
303
401
|
'$injector',
|
304
402
|
'$templateRequest',
|
305
403
|
'$sce',
|
306
|
-
|
404
|
+
'$browser',
|
405
|
+
function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) {
|
307
406
|
|
308
407
|
/**
|
309
408
|
* @ngdoc service
|
@@ -388,12 +487,12 @@ function $RouteProvider() {
|
|
388
487
|
* })
|
389
488
|
*
|
390
489
|
* .controller('BookController', function($scope, $routeParams) {
|
391
|
-
* $scope.name =
|
490
|
+
* $scope.name = 'BookController';
|
392
491
|
* $scope.params = $routeParams;
|
393
492
|
* })
|
394
493
|
*
|
395
494
|
* .controller('ChapterController', function($scope, $routeParams) {
|
396
|
-
* $scope.name =
|
495
|
+
* $scope.name = 'ChapterController';
|
397
496
|
* $scope.params = $routeParams;
|
398
497
|
* })
|
399
498
|
*
|
@@ -426,15 +525,15 @@ function $RouteProvider() {
|
|
426
525
|
* it('should load and compile correct template', function() {
|
427
526
|
* element(by.linkText('Moby: Ch1')).click();
|
428
527
|
* var content = element(by.css('[ng-view]')).getText();
|
429
|
-
* expect(content).toMatch(/controller
|
430
|
-
* expect(content).toMatch(/Book Id
|
431
|
-
* expect(content).toMatch(/Chapter Id
|
528
|
+
* expect(content).toMatch(/controller: ChapterController/);
|
529
|
+
* expect(content).toMatch(/Book Id: Moby/);
|
530
|
+
* expect(content).toMatch(/Chapter Id: 1/);
|
432
531
|
*
|
433
532
|
* element(by.partialLinkText('Scarlet')).click();
|
434
533
|
*
|
435
534
|
* content = element(by.css('[ng-view]')).getText();
|
436
|
-
* expect(content).toMatch(/controller
|
437
|
-
* expect(content).toMatch(/Book Id
|
535
|
+
* expect(content).toMatch(/controller: BookController/);
|
536
|
+
* expect(content).toMatch(/Book Id: Scarlet/);
|
438
537
|
* });
|
439
538
|
* </file>
|
440
539
|
* </example>
|
@@ -482,12 +581,14 @@ function $RouteProvider() {
|
|
482
581
|
* @name $route#$routeChangeError
|
483
582
|
* @eventType broadcast on root scope
|
484
583
|
* @description
|
485
|
-
* Broadcasted if any
|
584
|
+
* Broadcasted if a redirection function fails or any redirection or resolve promises are
|
585
|
+
* rejected.
|
486
586
|
*
|
487
587
|
* @param {Object} angularEvent Synthetic event object
|
488
588
|
* @param {Route} current Current route information.
|
489
589
|
* @param {Route} previous Previous route information.
|
490
|
-
* @param {Route} rejection
|
590
|
+
* @param {Route} rejection The thrown error or the rejection reason of the promise. Usually
|
591
|
+
* the rejection reason is the error that caused the promise to get rejected.
|
491
592
|
*/
|
492
593
|
|
493
594
|
/**
|
@@ -495,8 +596,9 @@ function $RouteProvider() {
|
|
495
596
|
* @name $route#$routeUpdate
|
496
597
|
* @eventType broadcast on root scope
|
497
598
|
* @description
|
498
|
-
*
|
499
|
-
*
|
599
|
+
* Broadcasted if the same instance of a route (including template, controller instance,
|
600
|
+
* resolved dependencies, etc.) is being reused. This can happen if either `reloadOnSearch` or
|
601
|
+
* `reloadOnUrl` has been set to `false`.
|
500
602
|
*
|
501
603
|
* @param {Object} angularEvent Synthetic event object
|
502
604
|
* @param {Route} current Current/previous route information.
|
@@ -556,7 +658,7 @@ function $RouteProvider() {
|
|
556
658
|
// interpolate modifies newParams, only query params are left
|
557
659
|
$location.search(newParams);
|
558
660
|
} else {
|
559
|
-
throw $routeMinErr('norout', 'Tried updating route
|
661
|
+
throw $routeMinErr('norout', 'Tried updating route with no current route');
|
560
662
|
}
|
561
663
|
}
|
562
664
|
};
|
@@ -604,9 +706,7 @@ function $RouteProvider() {
|
|
604
706
|
var lastRoute = $route.current;
|
605
707
|
|
606
708
|
preparedRoute = parseRoute();
|
607
|
-
preparedRouteIsUpdateOnly = preparedRoute
|
608
|
-
&& angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
|
609
|
-
&& !preparedRoute.reloadOnSearch && !forceReload;
|
709
|
+
preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute);
|
610
710
|
|
611
711
|
if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
|
612
712
|
if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
|
@@ -628,37 +728,112 @@ function $RouteProvider() {
|
|
628
728
|
} else if (nextRoute || lastRoute) {
|
629
729
|
forceReload = false;
|
630
730
|
$route.current = nextRoute;
|
631
|
-
if (nextRoute) {
|
632
|
-
if (nextRoute.redirectTo) {
|
633
|
-
if (angular.isString(nextRoute.redirectTo)) {
|
634
|
-
$location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
|
635
|
-
.replace();
|
636
|
-
} else {
|
637
|
-
$location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
|
638
|
-
.replace();
|
639
|
-
}
|
640
|
-
}
|
641
|
-
}
|
642
731
|
|
643
|
-
$q.
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
732
|
+
var nextRoutePromise = $q.resolve(nextRoute);
|
733
|
+
|
734
|
+
$browser.$$incOutstandingRequestCount('$route');
|
735
|
+
|
736
|
+
nextRoutePromise.
|
737
|
+
then(getRedirectionData).
|
738
|
+
then(handlePossibleRedirection).
|
739
|
+
then(function(keepProcessingRoute) {
|
740
|
+
return keepProcessingRoute && nextRoutePromise.
|
741
|
+
then(resolveLocals).
|
742
|
+
then(function(locals) {
|
743
|
+
// after route change
|
744
|
+
if (nextRoute === $route.current) {
|
745
|
+
if (nextRoute) {
|
746
|
+
nextRoute.locals = locals;
|
747
|
+
angular.copy(nextRoute.params, $routeParams);
|
748
|
+
}
|
749
|
+
$rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
|
750
|
+
}
|
751
|
+
});
|
752
|
+
}).catch(function(error) {
|
753
|
+
if (nextRoute === $route.current) {
|
656
754
|
$rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
|
657
755
|
}
|
756
|
+
}).finally(function() {
|
757
|
+
// Because `commitRoute()` is called from a `$rootScope.$evalAsync` block (see
|
758
|
+
// `$locationWatch`), this `$$completeOutstandingRequest()` call will not cause
|
759
|
+
// `outstandingRequestCount` to hit zero. This is important in case we are redirecting
|
760
|
+
// to a new route which also requires some asynchronous work.
|
761
|
+
|
762
|
+
$browser.$$completeOutstandingRequest(noop, '$route');
|
658
763
|
});
|
659
764
|
}
|
660
765
|
}
|
661
766
|
|
767
|
+
function getRedirectionData(route) {
|
768
|
+
var data = {
|
769
|
+
route: route,
|
770
|
+
hasRedirection: false
|
771
|
+
};
|
772
|
+
|
773
|
+
if (route) {
|
774
|
+
if (route.redirectTo) {
|
775
|
+
if (angular.isString(route.redirectTo)) {
|
776
|
+
data.path = interpolate(route.redirectTo, route.params);
|
777
|
+
data.search = route.params;
|
778
|
+
data.hasRedirection = true;
|
779
|
+
} else {
|
780
|
+
var oldPath = $location.path();
|
781
|
+
var oldSearch = $location.search();
|
782
|
+
var newUrl = route.redirectTo(route.pathParams, oldPath, oldSearch);
|
783
|
+
|
784
|
+
if (angular.isDefined(newUrl)) {
|
785
|
+
data.url = newUrl;
|
786
|
+
data.hasRedirection = true;
|
787
|
+
}
|
788
|
+
}
|
789
|
+
} else if (route.resolveRedirectTo) {
|
790
|
+
return $q.
|
791
|
+
resolve($injector.invoke(route.resolveRedirectTo)).
|
792
|
+
then(function(newUrl) {
|
793
|
+
if (angular.isDefined(newUrl)) {
|
794
|
+
data.url = newUrl;
|
795
|
+
data.hasRedirection = true;
|
796
|
+
}
|
797
|
+
|
798
|
+
return data;
|
799
|
+
});
|
800
|
+
}
|
801
|
+
}
|
802
|
+
|
803
|
+
return data;
|
804
|
+
}
|
805
|
+
|
806
|
+
function handlePossibleRedirection(data) {
|
807
|
+
var keepProcessingRoute = true;
|
808
|
+
|
809
|
+
if (data.route !== $route.current) {
|
810
|
+
keepProcessingRoute = false;
|
811
|
+
} else if (data.hasRedirection) {
|
812
|
+
var oldUrl = $location.url();
|
813
|
+
var newUrl = data.url;
|
814
|
+
|
815
|
+
if (newUrl) {
|
816
|
+
$location.
|
817
|
+
url(newUrl).
|
818
|
+
replace();
|
819
|
+
} else {
|
820
|
+
newUrl = $location.
|
821
|
+
path(data.path).
|
822
|
+
search(data.search).
|
823
|
+
replace().
|
824
|
+
url();
|
825
|
+
}
|
826
|
+
|
827
|
+
if (newUrl !== oldUrl) {
|
828
|
+
// Exit out and don't process current next value,
|
829
|
+
// wait for next location change from redirect
|
830
|
+
keepProcessingRoute = false;
|
831
|
+
}
|
832
|
+
}
|
833
|
+
|
834
|
+
return keepProcessingRoute;
|
835
|
+
}
|
836
|
+
|
662
837
|
function resolveLocals(route) {
|
663
838
|
if (route) {
|
664
839
|
var locals = angular.extend({}, route.resolve);
|
@@ -675,7 +850,6 @@ function $RouteProvider() {
|
|
675
850
|
}
|
676
851
|
}
|
677
852
|
|
678
|
-
|
679
853
|
function getTemplateFor(route) {
|
680
854
|
var template, templateUrl;
|
681
855
|
if (angular.isDefined(template = route.template)) {
|
@@ -694,7 +868,6 @@ function $RouteProvider() {
|
|
694
868
|
return template;
|
695
869
|
}
|
696
870
|
|
697
|
-
|
698
871
|
/**
|
699
872
|
* @returns {Object} the current active route, by matching it against the URL
|
700
873
|
*/
|
@@ -713,6 +886,29 @@ function $RouteProvider() {
|
|
713
886
|
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
714
887
|
}
|
715
888
|
|
889
|
+
/**
|
890
|
+
* @param {Object} newRoute - The new route configuration (as returned by `parseRoute()`).
|
891
|
+
* @param {Object} oldRoute - The previous route configuration (as returned by `parseRoute()`).
|
892
|
+
* @returns {boolean} Whether this is an "update-only" navigation, i.e. the URL maps to the same
|
893
|
+
* route and it can be reused (based on the config and the type of change).
|
894
|
+
*/
|
895
|
+
function isNavigationUpdateOnly(newRoute, oldRoute) {
|
896
|
+
// IF this is not a forced reload
|
897
|
+
return !forceReload
|
898
|
+
// AND both `newRoute`/`oldRoute` are defined
|
899
|
+
&& newRoute && oldRoute
|
900
|
+
// AND they map to the same Route Definition Object
|
901
|
+
&& (newRoute.$$route === oldRoute.$$route)
|
902
|
+
// AND `reloadOnUrl` is disabled
|
903
|
+
&& (!newRoute.reloadOnUrl
|
904
|
+
// OR `reloadOnSearch` is disabled
|
905
|
+
|| (!newRoute.reloadOnSearch
|
906
|
+
// AND both routes have the same path params
|
907
|
+
&& angular.equals(newRoute.pathParams, oldRoute.pathParams)
|
908
|
+
)
|
909
|
+
);
|
910
|
+
}
|
911
|
+
|
716
912
|
/**
|
717
913
|
* @returns {string} interpolation of the redirect path with the parameters
|
718
914
|
*/
|
@@ -734,6 +930,14 @@ function $RouteProvider() {
|
|
734
930
|
}];
|
735
931
|
}
|
736
932
|
|
933
|
+
instantiateRoute.$inject = ['$injector'];
|
934
|
+
function instantiateRoute($injector) {
|
935
|
+
if (isEagerInstantiationEnabled) {
|
936
|
+
// Instantiate `$route`
|
937
|
+
$injector.get('$route');
|
938
|
+
}
|
939
|
+
}
|
940
|
+
|
737
941
|
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
738
942
|
|
739
943
|
|
@@ -741,6 +945,7 @@ ngRouteModule.provider('$routeParams', $RouteParamsProvider);
|
|
741
945
|
* @ngdoc service
|
742
946
|
* @name $routeParams
|
743
947
|
* @requires $route
|
948
|
+
* @this
|
744
949
|
*
|
745
950
|
* @description
|
746
951
|
* The `$routeParams` service allows you to retrieve the current set of route parameters.
|
@@ -784,7 +989,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
|
784
989
|
* @restrict ECA
|
785
990
|
*
|
786
991
|
* @description
|
787
|
-
* # Overview
|
788
992
|
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
|
789
993
|
* including the rendered template of the current route into the main layout (`index.html`) file.
|
790
994
|
* Every time the current route changes, the included view changes with it according to the
|
@@ -800,13 +1004,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
|
800
1004
|
*
|
801
1005
|
* The enter and leave animation occur concurrently.
|
802
1006
|
*
|
803
|
-
* @knownIssue If `ngView` is contained in an asynchronously loaded template (e.g. in another
|
804
|
-
* directive's templateUrl or in a template loaded using `ngInclude`), then you need to
|
805
|
-
* make sure that `$route` is instantiated in time to capture the initial
|
806
|
-
* `$locationChangeStart` event and load the appropriate view. One way to achieve this
|
807
|
-
* is to have it as a dependency in a `.run` block:
|
808
|
-
* `myModule.run(['$route', function() {}]);`
|
809
|
-
*
|
810
1007
|
* @scope
|
811
1008
|
* @priority 400
|
812
1009
|
* @param {string=} onload Expression to evaluate whenever the view updates.
|
@@ -917,17 +1114,17 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
|
917
1114
|
$locationProvider.html5Mode(true);
|
918
1115
|
}])
|
919
1116
|
.controller('MainCtrl', ['$route', '$routeParams', '$location',
|
920
|
-
function($route, $routeParams, $location) {
|
1117
|
+
function MainCtrl($route, $routeParams, $location) {
|
921
1118
|
this.$route = $route;
|
922
1119
|
this.$location = $location;
|
923
1120
|
this.$routeParams = $routeParams;
|
924
1121
|
}])
|
925
|
-
.controller('BookCtrl', ['$routeParams', function($routeParams) {
|
926
|
-
this.name =
|
1122
|
+
.controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) {
|
1123
|
+
this.name = 'BookCtrl';
|
927
1124
|
this.params = $routeParams;
|
928
1125
|
}])
|
929
|
-
.controller('ChapterCtrl', ['$routeParams', function($routeParams) {
|
930
|
-
this.name =
|
1126
|
+
.controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) {
|
1127
|
+
this.name = 'ChapterCtrl';
|
931
1128
|
this.params = $routeParams;
|
932
1129
|
}]);
|
933
1130
|
|
@@ -937,15 +1134,15 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
|
|
937
1134
|
it('should load and compile correct template', function() {
|
938
1135
|
element(by.linkText('Moby: Ch1')).click();
|
939
1136
|
var content = element(by.css('[ng-view]')).getText();
|
940
|
-
expect(content).toMatch(/controller
|
941
|
-
expect(content).toMatch(/Book Id
|
942
|
-
expect(content).toMatch(/Chapter Id
|
1137
|
+
expect(content).toMatch(/controller: ChapterCtrl/);
|
1138
|
+
expect(content).toMatch(/Book Id: Moby/);
|
1139
|
+
expect(content).toMatch(/Chapter Id: 1/);
|
943
1140
|
|
944
1141
|
element(by.partialLinkText('Scarlet')).click();
|
945
1142
|
|
946
1143
|
content = element(by.css('[ng-view]')).getText();
|
947
|
-
expect(content).toMatch(/controller
|
948
|
-
expect(content).toMatch(/Book Id
|
1144
|
+
expect(content).toMatch(/controller: BookCtrl/);
|
1145
|
+
expect(content).toMatch(/Book Id: Scarlet/);
|
949
1146
|
});
|
950
1147
|
</file>
|
951
1148
|
</example>
|
@@ -988,8 +1185,8 @@ function ngViewFactory($route, $anchorScroll, $animate) {
|
|
988
1185
|
}
|
989
1186
|
if (currentElement) {
|
990
1187
|
previousLeaveAnimation = $animate.leave(currentElement);
|
991
|
-
previousLeaveAnimation.
|
992
|
-
previousLeaveAnimation = null;
|
1188
|
+
previousLeaveAnimation.done(function(response) {
|
1189
|
+
if (response !== false) previousLeaveAnimation = null;
|
993
1190
|
});
|
994
1191
|
currentElement = null;
|
995
1192
|
}
|
@@ -1010,8 +1207,8 @@ function ngViewFactory($route, $anchorScroll, $animate) {
|
|
1010
1207
|
// function is called before linking the content, which would apply child
|
1011
1208
|
// directives to non existing elements.
|
1012
1209
|
var clone = $transclude(newScope, function(clone) {
|
1013
|
-
$animate.enter(clone, null, currentElement || $element).
|
1014
|
-
if (angular.isDefined(autoScrollExp)
|
1210
|
+
$animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) {
|
1211
|
+
if (response !== false && angular.isDefined(autoScrollExp)
|
1015
1212
|
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
1016
1213
|
$anchorScroll();
|
1017
1214
|
}
|