Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / app / fusion / external / angular-1.5 / angular-route.js
1 /**
2  * @license AngularJS v1.5.0
3  * (c) 2010-2016 Google, Inc. http://angularjs.org
4  * License: MIT
5  */
6 (function(window, angular, undefined) {'use strict';
7
8 /**
9  * @ngdoc module
10  * @name ngRoute
11  * @description
12  *
13  * # ngRoute
14  *
15  * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
16  *
17  * ## Example
18  * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
19  *
20  *
21  * <div doc-module-components="ngRoute"></div>
22  */
23  /* global -ngRouteModule */
24 var ngRouteModule = angular.module('ngRoute', ['ng']).
25                         provider('$route', $RouteProvider),
26     $routeMinErr = angular.$$minErr('ngRoute');
27
28 /**
29  * @ngdoc provider
30  * @name $routeProvider
31  *
32  * @description
33  *
34  * Used for configuring routes.
35  *
36  * ## Example
37  * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
38  *
39  * ## Dependencies
40  * Requires the {@link ngRoute `ngRoute`} module to be installed.
41  */
42 function $RouteProvider() {
43   function inherit(parent, extra) {
44     return angular.extend(Object.create(parent), extra);
45   }
46
47   var routes = {};
48
49   /**
50    * @ngdoc method
51    * @name $routeProvider#when
52    *
53    * @param {string} path Route path (matched against `$location.path`). If `$location.path`
54    *    contains redundant trailing slash or is missing one, the route will still match and the
55    *    `$location.path` will be updated to add or drop the trailing slash to exactly match the
56    *    route definition.
57    *
58    *    * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
59    *        to the next slash are matched and stored in `$routeParams` under the given `name`
60    *        when the route matches.
61    *    * `path` can contain named groups starting with a colon and ending with a star:
62    *        e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
63    *        when the route matches.
64    *    * `path` can contain optional named groups with a question mark: e.g.`:name?`.
65    *
66    *    For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
67    *    `/color/brown/largecode/code/with/slashes/edit` and extract:
68    *
69    *    * `color: brown`
70    *    * `largecode: code/with/slashes`.
71    *
72    *
73    * @param {Object} route Mapping information to be assigned to `$route.current` on route
74    *    match.
75    *
76    *    Object properties:
77    *
78    *    - `controller` – `{(string|function()=}` – Controller fn that should be associated with
79    *      newly created scope or the name of a {@link angular.Module#controller registered
80    *      controller} if passed as a string.
81    *    - `controllerAs` – `{string=}` – An identifier name for a reference to the controller.
82    *      If present, the controller will be published to scope under the `controllerAs` name.
83    *    - `template` – `{string=|function()=}` – html template as a string or a function that
84    *      returns an html template as a string which should be used by {@link
85    *      ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
86    *      This property takes precedence over `templateUrl`.
87    *
88    *      If `template` is a function, it will be called with the following parameters:
89    *
90    *      - `{Array.<Object>}` - route parameters extracted from the current
91    *        `$location.path()` by applying the current route
92    *
93    *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
94    *      template that should be used by {@link ngRoute.directive:ngView ngView}.
95    *
96    *      If `templateUrl` is a function, it will be called with the following parameters:
97    *
98    *      - `{Array.<Object>}` - route parameters extracted from the current
99    *        `$location.path()` by applying the current route
100    *
101    *    - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
102    *      be injected into the controller. If any of these dependencies are promises, the router
103    *      will wait for them all to be resolved or one to be rejected before the controller is
104    *      instantiated.
105    *      If all the promises are resolved successfully, the values of the resolved promises are
106    *      injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
107    *      fired. If any of the promises are rejected the
108    *      {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired.
109    *      For easier access to the resolved dependencies from the template, the `resolve` map will
110    *      be available on the scope of the route, under `$resolve` (by default) or a custom name
111    *      specified by the `resolveAs` property (see below). This can be particularly useful, when
112    *      working with {@link angular.Module#component components} as route templates.<br />
113    *      <div class="alert alert-warning">
114    *        **Note:** If your scope already contains a property with this name, it will be hidden
115    *        or overwritten. Make sure, you specify an appropriate name for this property, that
116    *        does not collide with other properties on the scope.
117    *      </div>
118    *      The map object is:
119    *
120    *      - `key` – `{string}`: a name of a dependency to be injected into the controller.
121    *      - `factory` - `{string|function}`: If `string` then it is an alias for a service.
122    *        Otherwise if function, then it is {@link auto.$injector#invoke injected}
123    *        and the return value is treated as the dependency. If the result is a promise, it is
124    *        resolved before its value is injected into the controller. Be aware that
125    *        `ngRoute.$routeParams` will still refer to the previous route within these resolve
126    *        functions.  Use `$route.current.params` to access the new route parameters, instead.
127    *
128    *    - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on
129    *      the scope of the route. If omitted, defaults to `$resolve`.
130    *
131    *    - `redirectTo` – `{(string|function())=}` – value to update
132    *      {@link ng.$location $location} path with and trigger route redirection.
133    *
134    *      If `redirectTo` is a function, it will be called with the following parameters:
135    *
136    *      - `{Object.<string>}` - route parameters extracted from the current
137    *        `$location.path()` by applying the current route templateUrl.
138    *      - `{string}` - current `$location.path()`
139    *      - `{Object}` - current `$location.search()`
140    *
141    *      The custom `redirectTo` function is expected to return a string which will be used
142    *      to update `$location.path()` and `$location.search()`.
143    *
144    *    - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()`
145    *      or `$location.hash()` changes.
146    *
147    *      If the option is set to `false` and url in the browser changes, then
148    *      `$routeUpdate` event is broadcasted on the root scope.
149    *
150    *    - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive
151    *
152    *      If the option is set to `true`, then the particular route can be matched without being
153    *      case sensitive
154    *
155    * @returns {Object} self
156    *
157    * @description
158    * Adds a new route definition to the `$route` service.
159    */
160   this.when = function(path, route) {
161     //copy original route object to preserve params inherited from proto chain
162     var routeCopy = angular.copy(route);
163     if (angular.isUndefined(routeCopy.reloadOnSearch)) {
164       routeCopy.reloadOnSearch = true;
165     }
166     if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) {
167       routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch;
168     }
169     routes[path] = angular.extend(
170       routeCopy,
171       path && pathRegExp(path, routeCopy)
172     );
173
174     // create redirection for trailing slashes
175     if (path) {
176       var redirectPath = (path[path.length - 1] == '/')
177             ? path.substr(0, path.length - 1)
178             : path + '/';
179
180       routes[redirectPath] = angular.extend(
181         {redirectTo: path},
182         pathRegExp(redirectPath, routeCopy)
183       );
184     }
185
186     return this;
187   };
188
189   /**
190    * @ngdoc property
191    * @name $routeProvider#caseInsensitiveMatch
192    * @description
193    *
194    * A boolean property indicating if routes defined
195    * using this provider should be matched using a case insensitive
196    * algorithm. Defaults to `false`.
197    */
198   this.caseInsensitiveMatch = false;
199
200    /**
201     * @param path {string} path
202     * @param opts {Object} options
203     * @return {?Object}
204     *
205     * @description
206     * Normalizes the given path, returning a regular expression
207     * and the original path.
208     *
209     * Inspired by pathRexp in visionmedia/express/lib/utils.js.
210     */
211   function pathRegExp(path, opts) {
212     var insensitive = opts.caseInsensitiveMatch,
213         ret = {
214           originalPath: path,
215           regexp: path
216         },
217         keys = ret.keys = [];
218
219     path = path
220       .replace(/([().])/g, '\\$1')
221       .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option) {
222         var optional = option === '?' ? option : null;
223         var star = option === '*' ? option : null;
224         keys.push({ name: key, optional: !!optional });
225         slash = slash || '';
226         return ''
227           + (optional ? '' : slash)
228           + '(?:'
229           + (optional ? slash : '')
230           + (star && '(.+?)' || '([^/]+)')
231           + (optional || '')
232           + ')'
233           + (optional || '');
234       })
235       .replace(/([\/$\*])/g, '\\$1');
236
237     ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
238     return ret;
239   }
240
241   /**
242    * @ngdoc method
243    * @name $routeProvider#otherwise
244    *
245    * @description
246    * Sets route definition that will be used on route change when no other route definition
247    * is matched.
248    *
249    * @param {Object|string} params Mapping information to be assigned to `$route.current`.
250    * If called with a string, the value maps to `redirectTo`.
251    * @returns {Object} self
252    */
253   this.otherwise = function(params) {
254     if (typeof params === 'string') {
255       params = {redirectTo: params};
256     }
257     this.when(null, params);
258     return this;
259   };
260
261
262   this.$get = ['$rootScope',
263                '$location',
264                '$routeParams',
265                '$q',
266                '$injector',
267                '$templateRequest',
268                '$sce',
269       function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
270
271     /**
272      * @ngdoc service
273      * @name $route
274      * @requires $location
275      * @requires $routeParams
276      *
277      * @property {Object} current Reference to the current route definition.
278      * The route definition contains:
279      *
280      *   - `controller`: The controller constructor as defined in the route definition.
281      *   - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
282      *     controller instantiation. The `locals` contain
283      *     the resolved values of the `resolve` map. Additionally the `locals` also contain:
284      *
285      *     - `$scope` - The current route scope.
286      *     - `$template` - The current route template HTML.
287      *
288      *     The `locals` will be assigned to the route scope's `$resolve` property. You can override
289      *     the property name, using `resolveAs` in the route definition. See
290      *     {@link ngRoute.$routeProvider $routeProvider} for more info.
291      *
292      * @property {Object} routes Object with all route configuration Objects as its properties.
293      *
294      * @description
295      * `$route` is used for deep-linking URLs to controllers and views (HTML partials).
296      * It watches `$location.url()` and tries to map the path to an existing route definition.
297      *
298      * Requires the {@link ngRoute `ngRoute`} module to be installed.
299      *
300      * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
301      *
302      * The `$route` service is typically used in conjunction with the
303      * {@link ngRoute.directive:ngView `ngView`} directive and the
304      * {@link ngRoute.$routeParams `$routeParams`} service.
305      *
306      * @example
307      * This example shows how changing the URL hash causes the `$route` to match a route against the
308      * URL, and the `ngView` pulls in the partial.
309      *
310      * <example name="$route-service" module="ngRouteExample"
311      *          deps="angular-route.js" fixBase="true">
312      *   <file name="index.html">
313      *     <div ng-controller="MainController">
314      *       Choose:
315      *       <a href="Book/Moby">Moby</a> |
316      *       <a href="Book/Moby/ch/1">Moby: Ch1</a> |
317      *       <a href="Book/Gatsby">Gatsby</a> |
318      *       <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
319      *       <a href="Book/Scarlet">Scarlet Letter</a><br/>
320      *
321      *       <div ng-view></div>
322      *
323      *       <hr />
324      *
325      *       <pre>$location.path() = {{$location.path()}}</pre>
326      *       <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
327      *       <pre>$route.current.params = {{$route.current.params}}</pre>
328      *       <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
329      *       <pre>$routeParams = {{$routeParams}}</pre>
330      *     </div>
331      *   </file>
332      *
333      *   <file name="book.html">
334      *     controller: {{name}}<br />
335      *     Book Id: {{params.bookId}}<br />
336      *   </file>
337      *
338      *   <file name="chapter.html">
339      *     controller: {{name}}<br />
340      *     Book Id: {{params.bookId}}<br />
341      *     Chapter Id: {{params.chapterId}}
342      *   </file>
343      *
344      *   <file name="script.js">
345      *     angular.module('ngRouteExample', ['ngRoute'])
346      *
347      *      .controller('MainController', function($scope, $route, $routeParams, $location) {
348      *          $scope.$route = $route;
349      *          $scope.$location = $location;
350      *          $scope.$routeParams = $routeParams;
351      *      })
352      *
353      *      .controller('BookController', function($scope, $routeParams) {
354      *          $scope.name = "BookController";
355      *          $scope.params = $routeParams;
356      *      })
357      *
358      *      .controller('ChapterController', function($scope, $routeParams) {
359      *          $scope.name = "ChapterController";
360      *          $scope.params = $routeParams;
361      *      })
362      *
363      *     .config(function($routeProvider, $locationProvider) {
364      *       $routeProvider
365      *        .when('/Book/:bookId', {
366      *         templateUrl: 'book.html',
367      *         controller: 'BookController',
368      *         resolve: {
369      *           // I will cause a 1 second delay
370      *           delay: function($q, $timeout) {
371      *             var delay = $q.defer();
372      *             $timeout(delay.resolve, 1000);
373      *             return delay.promise;
374      *           }
375      *         }
376      *       })
377      *       .when('/Book/:bookId/ch/:chapterId', {
378      *         templateUrl: 'chapter.html',
379      *         controller: 'ChapterController'
380      *       });
381      *
382      *       // configure html5 to get links working on jsfiddle
383      *       $locationProvider.html5Mode(true);
384      *     });
385      *
386      *   </file>
387      *
388      *   <file name="protractor.js" type="protractor">
389      *     it('should load and compile correct template', function() {
390      *       element(by.linkText('Moby: Ch1')).click();
391      *       var content = element(by.css('[ng-view]')).getText();
392      *       expect(content).toMatch(/controller\: ChapterController/);
393      *       expect(content).toMatch(/Book Id\: Moby/);
394      *       expect(content).toMatch(/Chapter Id\: 1/);
395      *
396      *       element(by.partialLinkText('Scarlet')).click();
397      *
398      *       content = element(by.css('[ng-view]')).getText();
399      *       expect(content).toMatch(/controller\: BookController/);
400      *       expect(content).toMatch(/Book Id\: Scarlet/);
401      *     });
402      *   </file>
403      * </example>
404      */
405
406     /**
407      * @ngdoc event
408      * @name $route#$routeChangeStart
409      * @eventType broadcast on root scope
410      * @description
411      * Broadcasted before a route change. At this  point the route services starts
412      * resolving all of the dependencies needed for the route change to occur.
413      * Typically this involves fetching the view template as well as any dependencies
414      * defined in `resolve` route property. Once  all of the dependencies are resolved
415      * `$routeChangeSuccess` is fired.
416      *
417      * The route change (and the `$location` change that triggered it) can be prevented
418      * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on}
419      * for more details about event object.
420      *
421      * @param {Object} angularEvent Synthetic event object.
422      * @param {Route} next Future route information.
423      * @param {Route} current Current route information.
424      */
425
426     /**
427      * @ngdoc event
428      * @name $route#$routeChangeSuccess
429      * @eventType broadcast on root scope
430      * @description
431      * Broadcasted after a route change has happened successfully.
432      * The `resolve` dependencies are now available in the `current.locals` property.
433      *
434      * {@link ngRoute.directive:ngView ngView} listens for the directive
435      * to instantiate the controller and render the view.
436      *
437      * @param {Object} angularEvent Synthetic event object.
438      * @param {Route} current Current route information.
439      * @param {Route|Undefined} previous Previous route information, or undefined if current is
440      * first route entered.
441      */
442
443     /**
444      * @ngdoc event
445      * @name $route#$routeChangeError
446      * @eventType broadcast on root scope
447      * @description
448      * Broadcasted if any of the resolve promises are rejected.
449      *
450      * @param {Object} angularEvent Synthetic event object
451      * @param {Route} current Current route information.
452      * @param {Route} previous Previous route information.
453      * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
454      */
455
456     /**
457      * @ngdoc event
458      * @name $route#$routeUpdate
459      * @eventType broadcast on root scope
460      * @description
461      * The `reloadOnSearch` property has been set to false, and we are reusing the same
462      * instance of the Controller.
463      *
464      * @param {Object} angularEvent Synthetic event object
465      * @param {Route} current Current/previous route information.
466      */
467
468     var forceReload = false,
469         preparedRoute,
470         preparedRouteIsUpdateOnly,
471         $route = {
472           routes: routes,
473
474           /**
475            * @ngdoc method
476            * @name $route#reload
477            *
478            * @description
479            * Causes `$route` service to reload the current route even if
480            * {@link ng.$location $location} hasn't changed.
481            *
482            * As a result of that, {@link ngRoute.directive:ngView ngView}
483            * creates new scope and reinstantiates the controller.
484            */
485           reload: function() {
486             forceReload = true;
487
488             var fakeLocationEvent = {
489               defaultPrevented: false,
490               preventDefault: function fakePreventDefault() {
491                 this.defaultPrevented = true;
492                 forceReload = false;
493               }
494             };
495
496             $rootScope.$evalAsync(function() {
497               prepareRoute(fakeLocationEvent);
498               if (!fakeLocationEvent.defaultPrevented) commitRoute();
499             });
500           },
501
502           /**
503            * @ngdoc method
504            * @name $route#updateParams
505            *
506            * @description
507            * Causes `$route` service to update the current URL, replacing
508            * current route parameters with those specified in `newParams`.
509            * Provided property names that match the route's path segment
510            * definitions will be interpolated into the location's path, while
511            * remaining properties will be treated as query params.
512            *
513            * @param {!Object<string, string>} newParams mapping of URL parameter names to values
514            */
515           updateParams: function(newParams) {
516             if (this.current && this.current.$$route) {
517               newParams = angular.extend({}, this.current.params, newParams);
518               $location.path(interpolate(this.current.$$route.originalPath, newParams));
519               // interpolate modifies newParams, only query params are left
520               $location.search(newParams);
521             } else {
522               throw $routeMinErr('norout', 'Tried updating route when with no current route');
523             }
524           }
525         };
526
527     $rootScope.$on('$locationChangeStart', prepareRoute);
528     $rootScope.$on('$locationChangeSuccess', commitRoute);
529
530     return $route;
531
532     /////////////////////////////////////////////////////
533
534     /**
535      * @param on {string} current url
536      * @param route {Object} route regexp to match the url against
537      * @return {?Object}
538      *
539      * @description
540      * Check if the route matches the current url.
541      *
542      * Inspired by match in
543      * visionmedia/express/lib/router/router.js.
544      */
545     function switchRouteMatcher(on, route) {
546       var keys = route.keys,
547           params = {};
548
549       if (!route.regexp) return null;
550
551       var m = route.regexp.exec(on);
552       if (!m) return null;
553
554       for (var i = 1, len = m.length; i < len; ++i) {
555         var key = keys[i - 1];
556
557         var val = m[i];
558
559         if (key && val) {
560           params[key.name] = val;
561         }
562       }
563       return params;
564     }
565
566     function prepareRoute($locationEvent) {
567       var lastRoute = $route.current;
568
569       preparedRoute = parseRoute();
570       preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route
571           && angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
572           && !preparedRoute.reloadOnSearch && !forceReload;
573
574       if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
575         if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
576           if ($locationEvent) {
577             $locationEvent.preventDefault();
578           }
579         }
580       }
581     }
582
583     function commitRoute() {
584       var lastRoute = $route.current;
585       var nextRoute = preparedRoute;
586
587       if (preparedRouteIsUpdateOnly) {
588         lastRoute.params = nextRoute.params;
589         angular.copy(lastRoute.params, $routeParams);
590         $rootScope.$broadcast('$routeUpdate', lastRoute);
591       } else if (nextRoute || lastRoute) {
592         forceReload = false;
593         $route.current = nextRoute;
594         if (nextRoute) {
595           if (nextRoute.redirectTo) {
596             if (angular.isString(nextRoute.redirectTo)) {
597               $location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
598                        .replace();
599             } else {
600               $location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
601                        .replace();
602             }
603           }
604         }
605
606         $q.when(nextRoute).
607           then(function() {
608             if (nextRoute) {
609               var locals = angular.extend({}, nextRoute.resolve),
610                   template, templateUrl;
611
612               angular.forEach(locals, function(value, key) {
613                 locals[key] = angular.isString(value) ?
614                     $injector.get(value) : $injector.invoke(value, null, null, key);
615               });
616
617               if (angular.isDefined(template = nextRoute.template)) {
618                 if (angular.isFunction(template)) {
619                   template = template(nextRoute.params);
620                 }
621               } else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
622                 if (angular.isFunction(templateUrl)) {
623                   templateUrl = templateUrl(nextRoute.params);
624                 }
625                 if (angular.isDefined(templateUrl)) {
626                   nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl);
627                   template = $templateRequest(templateUrl);
628                 }
629               }
630               if (angular.isDefined(template)) {
631                 locals['$template'] = template;
632               }
633               return $q.all(locals);
634             }
635           }).
636           then(function(locals) {
637             // after route change
638             if (nextRoute == $route.current) {
639               if (nextRoute) {
640                 nextRoute.locals = locals;
641                 angular.copy(nextRoute.params, $routeParams);
642               }
643               $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
644             }
645           }, function(error) {
646             if (nextRoute == $route.current) {
647               $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
648             }
649           });
650       }
651     }
652
653
654     /**
655      * @returns {Object} the current active route, by matching it against the URL
656      */
657     function parseRoute() {
658       // Match a route
659       var params, match;
660       angular.forEach(routes, function(route, path) {
661         if (!match && (params = switchRouteMatcher($location.path(), route))) {
662           match = inherit(route, {
663             params: angular.extend({}, $location.search(), params),
664             pathParams: params});
665           match.$$route = route;
666         }
667       });
668       // No route matched; fallback to "otherwise" route
669       return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
670     }
671
672     /**
673      * @returns {string} interpolation of the redirect path with the parameters
674      */
675     function interpolate(string, params) {
676       var result = [];
677       angular.forEach((string || '').split(':'), function(segment, i) {
678         if (i === 0) {
679           result.push(segment);
680         } else {
681           var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/);
682           var key = segmentMatch[1];
683           result.push(params[key]);
684           result.push(segmentMatch[2] || '');
685           delete params[key];
686         }
687       });
688       return result.join('');
689     }
690   }];
691 }
692
693 ngRouteModule.provider('$routeParams', $RouteParamsProvider);
694
695
696 /**
697  * @ngdoc service
698  * @name $routeParams
699  * @requires $route
700  *
701  * @description
702  * The `$routeParams` service allows you to retrieve the current set of route parameters.
703  *
704  * Requires the {@link ngRoute `ngRoute`} module to be installed.
705  *
706  * The route parameters are a combination of {@link ng.$location `$location`}'s
707  * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}.
708  * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
709  *
710  * In case of parameter name collision, `path` params take precedence over `search` params.
711  *
712  * The service guarantees that the identity of the `$routeParams` object will remain unchanged
713  * (but its properties will likely change) even when a route change occurs.
714  *
715  * Note that the `$routeParams` are only updated *after* a route change completes successfully.
716  * This means that you cannot rely on `$routeParams` being correct in route resolve functions.
717  * Instead you can use `$route.current.params` to access the new route's parameters.
718  *
719  * @example
720  * ```js
721  *  // Given:
722  *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
723  *  // Route: /Chapter/:chapterId/Section/:sectionId
724  *  //
725  *  // Then
726  *  $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
727  * ```
728  */
729 function $RouteParamsProvider() {
730   this.$get = function() { return {}; };
731 }
732
733 ngRouteModule.directive('ngView', ngViewFactory);
734 ngRouteModule.directive('ngView', ngViewFillContentFactory);
735
736
737 /**
738  * @ngdoc directive
739  * @name ngView
740  * @restrict ECA
741  *
742  * @description
743  * # Overview
744  * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
745  * including the rendered template of the current route into the main layout (`index.html`) file.
746  * Every time the current route changes, the included view changes with it according to the
747  * configuration of the `$route` service.
748  *
749  * Requires the {@link ngRoute `ngRoute`} module to be installed.
750  *
751  * @animations
752  * enter - animation is used to bring new content into the browser.
753  * leave - animation is used to animate existing content away.
754  *
755  * The enter and leave animation occur concurrently.
756  *
757  * @scope
758  * @priority 400
759  * @param {string=} onload Expression to evaluate whenever the view updates.
760  *
761  * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
762  *                  $anchorScroll} to scroll the viewport after the view is updated.
763  *
764  *                  - If the attribute is not set, disable scrolling.
765  *                  - If the attribute is set without value, enable scrolling.
766  *                  - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
767  *                    as an expression yields a truthy value.
768  * @example
769     <example name="ngView-directive" module="ngViewExample"
770              deps="angular-route.js;angular-animate.js"
771              animations="true" fixBase="true">
772       <file name="index.html">
773         <div ng-controller="MainCtrl as main">
774           Choose:
775           <a href="Book/Moby">Moby</a> |
776           <a href="Book/Moby/ch/1">Moby: Ch1</a> |
777           <a href="Book/Gatsby">Gatsby</a> |
778           <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
779           <a href="Book/Scarlet">Scarlet Letter</a><br/>
780
781           <div class="view-animate-container">
782             <div ng-view class="view-animate"></div>
783           </div>
784           <hr />
785
786           <pre>$location.path() = {{main.$location.path()}}</pre>
787           <pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
788           <pre>$route.current.params = {{main.$route.current.params}}</pre>
789           <pre>$routeParams = {{main.$routeParams}}</pre>
790         </div>
791       </file>
792
793       <file name="book.html">
794         <div>
795           controller: {{book.name}}<br />
796           Book Id: {{book.params.bookId}}<br />
797         </div>
798       </file>
799
800       <file name="chapter.html">
801         <div>
802           controller: {{chapter.name}}<br />
803           Book Id: {{chapter.params.bookId}}<br />
804           Chapter Id: {{chapter.params.chapterId}}
805         </div>
806       </file>
807
808       <file name="animations.css">
809         .view-animate-container {
810           position:relative;
811           height:100px!important;
812           background:white;
813           border:1px solid black;
814           height:40px;
815           overflow:hidden;
816         }
817
818         .view-animate {
819           padding:10px;
820         }
821
822         .view-animate.ng-enter, .view-animate.ng-leave {
823           transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
824
825           display:block;
826           width:100%;
827           border-left:1px solid black;
828
829           position:absolute;
830           top:0;
831           left:0;
832           right:0;
833           bottom:0;
834           padding:10px;
835         }
836
837         .view-animate.ng-enter {
838           left:100%;
839         }
840         .view-animate.ng-enter.ng-enter-active {
841           left:0;
842         }
843         .view-animate.ng-leave.ng-leave-active {
844           left:-100%;
845         }
846       </file>
847
848       <file name="script.js">
849         angular.module('ngViewExample', ['ngRoute', 'ngAnimate'])
850           .config(['$routeProvider', '$locationProvider',
851             function($routeProvider, $locationProvider) {
852               $routeProvider
853                 .when('/Book/:bookId', {
854                   templateUrl: 'book.html',
855                   controller: 'BookCtrl',
856                   controllerAs: 'book'
857                 })
858                 .when('/Book/:bookId/ch/:chapterId', {
859                   templateUrl: 'chapter.html',
860                   controller: 'ChapterCtrl',
861                   controllerAs: 'chapter'
862                 });
863
864               $locationProvider.html5Mode(true);
865           }])
866           .controller('MainCtrl', ['$route', '$routeParams', '$location',
867             function($route, $routeParams, $location) {
868               this.$route = $route;
869               this.$location = $location;
870               this.$routeParams = $routeParams;
871           }])
872           .controller('BookCtrl', ['$routeParams', function($routeParams) {
873             this.name = "BookCtrl";
874             this.params = $routeParams;
875           }])
876           .controller('ChapterCtrl', ['$routeParams', function($routeParams) {
877             this.name = "ChapterCtrl";
878             this.params = $routeParams;
879           }]);
880
881       </file>
882
883       <file name="protractor.js" type="protractor">
884         it('should load and compile correct template', function() {
885           element(by.linkText('Moby: Ch1')).click();
886           var content = element(by.css('[ng-view]')).getText();
887           expect(content).toMatch(/controller\: ChapterCtrl/);
888           expect(content).toMatch(/Book Id\: Moby/);
889           expect(content).toMatch(/Chapter Id\: 1/);
890
891           element(by.partialLinkText('Scarlet')).click();
892
893           content = element(by.css('[ng-view]')).getText();
894           expect(content).toMatch(/controller\: BookCtrl/);
895           expect(content).toMatch(/Book Id\: Scarlet/);
896         });
897       </file>
898     </example>
899  */
900
901
902 /**
903  * @ngdoc event
904  * @name ngView#$viewContentLoaded
905  * @eventType emit on the current ngView scope
906  * @description
907  * Emitted every time the ngView content is reloaded.
908  */
909 ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
910 function ngViewFactory($route, $anchorScroll, $animate) {
911   return {
912     restrict: 'ECA',
913     terminal: true,
914     priority: 400,
915     transclude: 'element',
916     link: function(scope, $element, attr, ctrl, $transclude) {
917         var currentScope,
918             currentElement,
919             previousLeaveAnimation,
920             autoScrollExp = attr.autoscroll,
921             onloadExp = attr.onload || '';
922
923         scope.$on('$routeChangeSuccess', update);
924         update();
925
926         function cleanupLastView() {
927           if (previousLeaveAnimation) {
928             $animate.cancel(previousLeaveAnimation);
929             previousLeaveAnimation = null;
930           }
931
932           if (currentScope) {
933             currentScope.$destroy();
934             currentScope = null;
935           }
936           if (currentElement) {
937             previousLeaveAnimation = $animate.leave(currentElement);
938             previousLeaveAnimation.then(function() {
939               previousLeaveAnimation = null;
940             });
941             currentElement = null;
942           }
943         }
944
945         function update() {
946           var locals = $route.current && $route.current.locals,
947               template = locals && locals.$template;
948
949           if (angular.isDefined(template)) {
950             var newScope = scope.$new();
951             var current = $route.current;
952
953             // Note: This will also link all children of ng-view that were contained in the original
954             // html. If that content contains controllers, ... they could pollute/change the scope.
955             // However, using ng-view on an element with additional content does not make sense...
956             // Note: We can't remove them in the cloneAttchFn of $transclude as that
957             // function is called before linking the content, which would apply child
958             // directives to non existing elements.
959             var clone = $transclude(newScope, function(clone) {
960               $animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter() {
961                 if (angular.isDefined(autoScrollExp)
962                   && (!autoScrollExp || scope.$eval(autoScrollExp))) {
963                   $anchorScroll();
964                 }
965               });
966               cleanupLastView();
967             });
968
969             currentElement = clone;
970             currentScope = current.scope = newScope;
971             currentScope.$emit('$viewContentLoaded');
972             currentScope.$eval(onloadExp);
973           } else {
974             cleanupLastView();
975           }
976         }
977     }
978   };
979 }
980
981 // This directive is called during the $transclude call of the first `ngView` directive.
982 // It will replace and compile the content of the element with the loaded template.
983 // We need this directive so that the element content is already filled when
984 // the link function of another directive on the same element as ngView
985 // is called.
986 ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
987 function ngViewFillContentFactory($compile, $controller, $route) {
988   return {
989     restrict: 'ECA',
990     priority: -400,
991     link: function(scope, $element) {
992       var current = $route.current,
993           locals = current.locals;
994
995       $element.html(locals.$template);
996
997       var link = $compile($element.contents());
998
999       if (current.controller) {
1000         locals.$scope = scope;
1001         var controller = $controller(current.controller, locals);
1002         if (current.controllerAs) {
1003           scope[current.controllerAs] = controller;
1004         }
1005         $element.data('$ngControllerController', controller);
1006         $element.children().data('$ngControllerController', controller);
1007       }
1008       scope[current.resolveAs || '$resolve'] = locals;
1009
1010       link(scope);
1011     }
1012   };
1013 }
1014
1015
1016 })(window, window.angular);