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.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
3
- * (c) 2010-2016 Google, Inc. http://angularjs.org
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
- // There are necessary for `shallowCopy()` (included via `src/shallowCopy.js`).
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
- * # ngRoute
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#example $route} for an example of configuring and using `ngRoute`.
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
- /* global -ngRouteModule */
58
- var ngRouteModule = angular.module('ngRoute', ['ng']).
59
- provider('$route', $RouteProvider),
60
- $routeMinErr = angular.$$minErr('ngRoute');
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#example $route} for an example of configuring and using `ngRoute`.
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|function()=}` – Controller fn that should be associated with
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=|function()=}` – html template as a string or a function that
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
- * - `templateUrl` `{string=|function()=}` path or function that returns a path to an html
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
- * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
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|function}`: If `string` then it is an alias for a service.
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|function())=}` – value to update
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.path()` and `$location.search()`.
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 url in the browser changes, then
185
- * `$routeUpdate` event is broadcasted on the root scope.
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
- path && pathRegExp(path, routeCopy)
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
- pathRegExp(redirectPath, routeCopy)
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
- function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
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 = "BookController";
490
+ * $scope.name = 'BookController';
392
491
  * $scope.params = $routeParams;
393
492
  * })
394
493
  *
395
494
  * .controller('ChapterController', function($scope, $routeParams) {
396
- * $scope.name = "ChapterController";
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\: ChapterController/);
430
- * expect(content).toMatch(/Book Id\: Moby/);
431
- * expect(content).toMatch(/Chapter Id\: 1/);
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\: BookController/);
437
- * expect(content).toMatch(/Book Id\: Scarlet/);
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 of the resolve promises are rejected.
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 Rejection of the promise. Usually the error of the failed promise.
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
- * The `reloadOnSearch` property has been set to false, and we are reusing the same
499
- * instance of the Controller.
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 when with no current 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 && lastRoute && preparedRoute.$$route === lastRoute.$$route
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.when(nextRoute).
644
- then(resolveLocals).
645
- then(function(locals) {
646
- // after route change
647
- if (nextRoute == $route.current) {
648
- if (nextRoute) {
649
- nextRoute.locals = locals;
650
- angular.copy(nextRoute.params, $routeParams);
651
- }
652
- $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
653
- }
654
- }, function(error) {
655
- if (nextRoute == $route.current) {
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 = "BookCtrl";
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 = "ChapterCtrl";
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\: ChapterCtrl/);
941
- expect(content).toMatch(/Book Id\: Moby/);
942
- expect(content).toMatch(/Chapter Id\: 1/);
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\: BookCtrl/);
948
- expect(content).toMatch(/Book Id\: Scarlet/);
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.then(function() {
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).then(function onNgViewEnter() {
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
  }