Rework javascript libraries
[clamp.git] / src / main / resources / META-INF / resources / designer / lib / angular-route.js
1 /**
2  * @license AngularJS v1.2.32
3  * (c) 2010-2014 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
27 /**
28  * @ngdoc provider
29  * @name $routeProvider
30  * @kind function
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(new (angular.extend(function() {}, {prototype: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=}` – A controller alias name. If present the controller will be
82    *      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. The map object
109    *      is:
110    *
111    *      - `key` – `{string}`: a name of a dependency to be injected into the controller.
112    *      - `factory` - `{string|function}`: If `string` then it is an alias for a service.
113    *        Otherwise if function, then it is {@link auto.$injector#invoke injected}
114    *        and the return value is treated as the dependency. If the result is a promise, it is
115    *        resolved before its value is injected into the controller. Be aware that
116    *        `ngRoute.$routeParams` will still refer to the previous route within these resolve
117    *        functions.  Use `$route.current.params` to access the new route parameters, instead.
118    *
119    *    - `redirectTo` – {(string|function())=} – value to update
120    *      {@link ng.$location $location} path with and trigger route redirection.
121    *
122    *      If `redirectTo` is a function, it will be called with the following parameters:
123    *
124    *      - `{Object.<string>}` - route parameters extracted from the current
125    *        `$location.path()` by applying the current route templateUrl.
126    *      - `{string}` - current `$location.path()`
127    *      - `{Object}` - current `$location.search()`
128    *
129    *      The custom `redirectTo` function is expected to return a string which will be used
130    *      to update `$location.path()` and `$location.search()`.
131    *
132    *    - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
133    *      or `$location.hash()` changes.
134    *
135    *      If the option is set to `false` and url in the browser changes, then
136    *      `$routeUpdate` event is broadcasted on the root scope.
137    *
138    *    - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
139    *
140    *      If the option is set to `true`, then the particular route can be matched without being
141    *      case sensitive
142    *
143    * @returns {Object} self
144    *
145    * @description
146    * Adds a new route definition to the `$route` service.
147    */
148   this.when = function(path, route) {
149     routes[path] = angular.extend(
150       {reloadOnSearch: true},
151       route,
152       path && pathRegExp(path, route)
153     );
154
155     // create redirection for trailing slashes
156     if (path) {
157       var redirectPath = (path[path.length-1] == '/')
158             ? path.substr(0, path.length-1)
159             : path +'/';
160
161       routes[redirectPath] = angular.extend(
162         {redirectTo: path},
163         pathRegExp(redirectPath, route)
164       );
165     }
166
167     return this;
168   };
169
170    /**
171     * @param path {string} path
172     * @param opts {Object} options
173     * @return {?Object}
174     *
175     * @description
176     * Normalizes the given path, returning a regular expression
177     * and the original path.
178     *
179     * Inspired by pathRexp in visionmedia/express/lib/utils.js.
180     */
181   function pathRegExp(path, opts) {
182     var insensitive = opts.caseInsensitiveMatch,
183         ret = {
184           originalPath: path,
185           regexp: path
186         },
187         keys = ret.keys = [];
188
189     path = path
190       .replace(/([().])/g, '\\$1')
191       .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
192         var optional = option === '?' ? option : null;
193         var star = option === '*' ? option : null;
194         keys.push({ name: key, optional: !!optional });
195         slash = slash || '';
196         return ''
197           + (optional ? '' : slash)
198           + '(?:'
199           + (optional ? slash : '')
200           + (star && '(.+?)' || '([^/]+)')
201           + (optional || '')
202           + ')'
203           + (optional || '');
204       })
205       .replace(/([\/$\*])/g, '\\$1');
206
207     ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
208     return ret;
209   }
210
211   /**
212    * @ngdoc method
213    * @name $routeProvider#otherwise
214    *
215    * @description
216    * Sets route definition that will be used on route change when no other route definition
217    * is matched.
218    *
219    * @param {Object} params Mapping information to be assigned to `$route.current`.
220    * @returns {Object} self
221    */
222   this.otherwise = function(params) {
223     this.when(null, params);
224     return this;
225   };
226
227
228   this.$get = ['$rootScope',
229                '$location',
230                '$routeParams',
231                '$q',
232                '$injector',
233                '$http',
234                '$templateCache',
235                '$sce',
236       function($rootScope, $location, $routeParams, $q, $injector, $http, $templateCache, $sce) {
237
238     /**
239      * @ngdoc service
240      * @name $route
241      * @requires $location
242      * @requires $routeParams
243      *
244      * @property {Object} current Reference to the current route definition.
245      * The route definition contains:
246      *
247      *   - `controller`: The controller constructor as define in route definition.
248      *   - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
249      *     controller instantiation. The `locals` contain
250      *     the resolved values of the `resolve` map. Additionally the `locals` also contain:
251      *
252      *     - `$scope` - The current route scope.
253      *     - `$template` - The current route template HTML.
254      *
255      * @property {Object} routes Object with all route configuration Objects as its properties.
256      *
257      * @description
258      * `$route` is used for deep-linking URLs to controllers and views (HTML partials).
259      * It watches `$location.url()` and tries to map the path to an existing route definition.
260      *
261      * Requires the {@link ngRoute `ngRoute`} module to be installed.
262      *
263      * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
264      *
265      * The `$route` service is typically used in conjunction with the
266      * {@link ngRoute.directive:ngView `ngView`} directive and the
267      * {@link ngRoute.$routeParams `$routeParams`} service.
268      *
269      * @example
270      * This example shows how changing the URL hash causes the `$route` to match a route against the
271      * URL, and the `ngView` pulls in the partial.
272      *
273      * <example name="$route-service" module="ngRouteExample"
274      *          deps="angular-route.js" fixBase="true">
275      *   <file name="index.html">
276      *     <div ng-controller="MainController">
277      *       Choose:
278      *       <a href="Book/Moby">Moby</a> |
279      *       <a href="Book/Moby/ch/1">Moby: Ch1</a> |
280      *       <a href="Book/Gatsby">Gatsby</a> |
281      *       <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
282      *       <a href="Book/Scarlet">Scarlet Letter</a><br/>
283      *
284      *       <div ng-view></div>
285      *
286      *       <hr />
287      *
288      *       <pre>$location.path() = {{$location.path()}}</pre>
289      *       <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
290      *       <pre>$route.current.params = {{$route.current.params}}</pre>
291      *       <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
292      *       <pre>$routeParams = {{$routeParams}}</pre>
293      *     </div>
294      *   </file>
295      *
296      *   <file name="book.html">
297      *     controller: {{name}}<br />
298      *     Book Id: {{params.bookId}}<br />
299      *   </file>
300      *
301      *   <file name="chapter.html">
302      *     controller: {{name}}<br />
303      *     Book Id: {{params.bookId}}<br />
304      *     Chapter Id: {{params.chapterId}}
305      *   </file>
306      *
307      *   <file name="script.js">
308      *     angular.module('ngRouteExample', ['ngRoute'])
309      *
310      *      .controller('MainController', function($scope, $route, $routeParams, $location) {
311      *          $scope.$route = $route;
312      *          $scope.$location = $location;
313      *          $scope.$routeParams = $routeParams;
314      *      })
315      *
316      *      .controller('BookController', function($scope, $routeParams) {
317      *          $scope.name = "BookController";
318      *          $scope.params = $routeParams;
319      *      })
320      *
321      *      .controller('ChapterController', function($scope, $routeParams) {
322      *          $scope.name = "ChapterController";
323      *          $scope.params = $routeParams;
324      *      })
325      *
326      *     .config(function($routeProvider, $locationProvider) {
327      *       $routeProvider
328      *        .when('/Book/:bookId', {
329      *         templateUrl: 'book.html',
330      *         controller: 'BookController',
331      *         resolve: {
332      *           // I will cause a 1 second delay
333      *           delay: function($q, $timeout) {
334      *             var delay = $q.defer();
335      *             $timeout(delay.resolve, 1000);
336      *             return delay.promise;
337      *           }
338      *         }
339      *       })
340      *       .when('/Book/:bookId/ch/:chapterId', {
341      *         templateUrl: 'chapter.html',
342      *         controller: 'ChapterController'
343      *       });
344      *
345      *       // configure html5 to get links working on jsfiddle
346      *       $locationProvider.html5Mode(true);
347      *     });
348      *
349      *   </file>
350      *
351      *   <file name="protractor.js" type="protractor">
352      *     it('should load and compile correct template', function() {
353      *       element(by.linkText('Moby: Ch1')).click();
354      *       var content = element(by.css('[ng-view]')).getText();
355      *       expect(content).toMatch(/controller\: ChapterController/);
356      *       expect(content).toMatch(/Book Id\: Moby/);
357      *       expect(content).toMatch(/Chapter Id\: 1/);
358      *
359      *       element(by.partialLinkText('Scarlet')).click();
360      *
361      *       content = element(by.css('[ng-view]')).getText();
362      *       expect(content).toMatch(/controller\: BookController/);
363      *       expect(content).toMatch(/Book Id\: Scarlet/);
364      *     });
365      *   </file>
366      * </example>
367      */
368
369     /**
370      * @ngdoc event
371      * @name $route#$routeChangeStart
372      * @eventType broadcast on root scope
373      * @description
374      * Broadcasted before a route change. At this  point the route services starts
375      * resolving all of the dependencies needed for the route change to occur.
376      * Typically this involves fetching the view template as well as any dependencies
377      * defined in `resolve` route property. Once  all of the dependencies are resolved
378      * `$routeChangeSuccess` is fired.
379      *
380      * @param {Object} angularEvent Synthetic event object.
381      * @param {Route} next Future route information.
382      * @param {Route} current Current route information.
383      */
384
385     /**
386      * @ngdoc event
387      * @name $route#$routeChangeSuccess
388      * @eventType broadcast on root scope
389      * @description
390      * Broadcasted after a route dependencies are resolved.
391      * {@link ngRoute.directive:ngView ngView} listens for the directive
392      * to instantiate the controller and render the view.
393      *
394      * @param {Object} angularEvent Synthetic event object.
395      * @param {Route} current Current route information.
396      * @param {Route|Undefined} previous Previous route information, or undefined if current is
397      * first route entered.
398      */
399
400     /**
401      * @ngdoc event
402      * @name $route#$routeChangeError
403      * @eventType broadcast on root scope
404      * @description
405      * Broadcasted if any of the resolve promises are rejected.
406      *
407      * @param {Object} angularEvent Synthetic event object
408      * @param {Route} current Current route information.
409      * @param {Route} previous Previous route information.
410      * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
411      */
412
413     /**
414      * @ngdoc event
415      * @name $route#$routeUpdate
416      * @eventType broadcast on root scope
417      * @description
418      *
419      * The `reloadOnSearch` property has been set to false, and we are reusing the same
420      * instance of the Controller.
421      */
422
423     var forceReload = false,
424         $route = {
425           routes: routes,
426
427           /**
428            * @ngdoc method
429            * @name $route#reload
430            *
431            * @description
432            * Causes `$route` service to reload the current route even if
433            * {@link ng.$location $location} hasn't changed.
434            *
435            * As a result of that, {@link ngRoute.directive:ngView ngView}
436            * creates new scope, reinstantiates the controller.
437            */
438           reload: function() {
439             forceReload = true;
440             $rootScope.$evalAsync(updateRoute);
441           }
442         };
443
444     $rootScope.$on('$locationChangeSuccess', updateRoute);
445
446     return $route;
447
448     /////////////////////////////////////////////////////
449
450     /**
451      * @param on {string} current url
452      * @param route {Object} route regexp to match the url against
453      * @return {?Object}
454      *
455      * @description
456      * Check if the route matches the current url.
457      *
458      * Inspired by match in
459      * visionmedia/express/lib/router/router.js.
460      */
461     function switchRouteMatcher(on, route) {
462       var keys = route.keys,
463           params = {};
464
465       if (!route.regexp) return null;
466
467       var m = route.regexp.exec(on);
468       if (!m) return null;
469
470       for (var i = 1, len = m.length; i < len; ++i) {
471         var key = keys[i - 1];
472
473         var val = m[i];
474
475         if (key && val) {
476           params[key.name] = val;
477         }
478       }
479       return params;
480     }
481
482     function updateRoute() {
483       var next = parseRoute(),
484           last = $route.current;
485
486       if (next && last && next.$$route === last.$$route
487           && angular.equals(next.pathParams, last.pathParams)
488           && !next.reloadOnSearch && !forceReload) {
489         last.params = next.params;
490         angular.copy(last.params, $routeParams);
491         $rootScope.$broadcast('$routeUpdate', last);
492       } else if (next || last) {
493         forceReload = false;
494         $rootScope.$broadcast('$routeChangeStart', next, last);
495         $route.current = next;
496         if (next) {
497           if (next.redirectTo) {
498             if (angular.isString(next.redirectTo)) {
499               $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
500                        .replace();
501             } else {
502               $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
503                        .replace();
504             }
505           }
506         }
507
508         $q.when(next).
509           then(function() {
510             if (next) {
511               var locals = angular.extend({}, next.resolve),
512                   template, templateUrl;
513
514               angular.forEach(locals, function(value, key) {
515                 locals[key] = angular.isString(value) ?
516                     $injector.get(value) : $injector.invoke(value);
517               });
518
519               if (angular.isDefined(template = next.template)) {
520                 if (angular.isFunction(template)) {
521                   template = template(next.params);
522                 }
523               } else if (angular.isDefined(templateUrl = next.templateUrl)) {
524                 if (angular.isFunction(templateUrl)) {
525                   templateUrl = templateUrl(next.params);
526                 }
527                 templateUrl = $sce.getTrustedResourceUrl(templateUrl);
528                 if (angular.isDefined(templateUrl)) {
529                   next.loadedTemplateUrl = templateUrl;
530                   template = $http.get(templateUrl, {cache: $templateCache}).
531                       then(function(response) { return response.data; });
532                 }
533               }
534               if (angular.isDefined(template)) {
535                 locals['$template'] = template;
536               }
537               return $q.all(locals);
538             }
539           }).
540           // after route change
541           then(function(locals) {
542             if (next == $route.current) {
543               if (next) {
544                 next.locals = locals;
545                 angular.copy(next.params, $routeParams);
546               }
547               $rootScope.$broadcast('$routeChangeSuccess', next, last);
548             }
549           }, function(error) {
550             if (next == $route.current) {
551               $rootScope.$broadcast('$routeChangeError', next, last, error);
552             }
553           });
554       }
555     }
556
557
558     /**
559      * @returns {Object} the current active route, by matching it against the URL
560      */
561     function parseRoute() {
562       // Match a route
563       var params, match;
564       angular.forEach(routes, function(route, path) {
565         if (!match && (params = switchRouteMatcher($location.path(), route))) {
566           match = inherit(route, {
567             params: angular.extend({}, $location.search(), params),
568             pathParams: params});
569           match.$$route = route;
570         }
571       });
572       // No route matched; fallback to "otherwise" route
573       return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
574     }
575
576     /**
577      * @returns {string} interpolation of the redirect path with the parameters
578      */
579     function interpolate(string, params) {
580       var result = [];
581       angular.forEach((string||'').split(':'), function(segment, i) {
582         if (i === 0) {
583           result.push(segment);
584         } else {
585           var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/);
586           var key = segmentMatch[1];
587           result.push(params[key]);
588           result.push(segmentMatch[2] || '');
589           delete params[key];
590         }
591       });
592       return result.join('');
593     }
594   }];
595 }
596
597 ngRouteModule.provider('$routeParams', $RouteParamsProvider);
598
599
600 /**
601  * @ngdoc service
602  * @name $routeParams
603  * @requires $route
604  *
605  * @description
606  * The `$routeParams` service allows you to retrieve the current set of route parameters.
607  *
608  * Requires the {@link ngRoute `ngRoute`} module to be installed.
609  *
610  * The route parameters are a combination of {@link ng.$location `$location`}'s
611  * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}.
612  * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
613  *
614  * In case of parameter name collision, `path` params take precedence over `search` params.
615  *
616  * The service guarantees that the identity of the `$routeParams` object will remain unchanged
617  * (but its properties will likely change) even when a route change occurs.
618  *
619  * Note that the `$routeParams` are only updated *after* a route change completes successfully.
620  * This means that you cannot rely on `$routeParams` being correct in route resolve functions.
621  * Instead you can use `$route.current.params` to access the new route's parameters.
622  *
623  * @example
624  * ```js
625  *  // Given:
626  *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
627  *  // Route: /Chapter/:chapterId/Section/:sectionId
628  *  //
629  *  // Then
630  *  $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
631  * ```
632  */
633 function $RouteParamsProvider() {
634   this.$get = function() { return {}; };
635 }
636
637 ngRouteModule.directive('ngView', ngViewFactory);
638 ngRouteModule.directive('ngView', ngViewFillContentFactory);
639
640
641 /**
642  * @ngdoc directive
643  * @name ngView
644  * @restrict ECA
645  *
646  * @description
647  * # Overview
648  * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
649  * including the rendered template of the current route into the main layout (`index.html`) file.
650  * Every time the current route changes, the included view changes with it according to the
651  * configuration of the `$route` service.
652  *
653  * Requires the {@link ngRoute `ngRoute`} module to be installed.
654  *
655  * @animations
656  * enter - animation is used to bring new content into the browser.
657  * leave - animation is used to animate existing content away.
658  *
659  * The enter and leave animation occur concurrently.
660  *
661  * @scope
662  * @priority 400
663  * @param {string=} onload Expression to evaluate whenever the view updates.
664  *
665  * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
666  *                  $anchorScroll} to scroll the viewport after the view is updated.
667  *
668  *                  - If the attribute is not set, disable scrolling.
669  *                  - If the attribute is set without value, enable scrolling.
670  *                  - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
671  *                    as an expression yields a truthy value.
672  * @example
673     <example name="ngView-directive" module="ngViewExample"
674              deps="angular-route.js;angular-animate.js"
675              animations="true" fixBase="true">
676       <file name="index.html">
677         <div ng-controller="MainCtrl as main">
678           Choose:
679           <a href="Book/Moby">Moby</a> |
680           <a href="Book/Moby/ch/1">Moby: Ch1</a> |
681           <a href="Book/Gatsby">Gatsby</a> |
682           <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
683           <a href="Book/Scarlet">Scarlet Letter</a><br/>
684
685           <div class="view-animate-container">
686             <div ng-view class="view-animate"></div>
687           </div>
688           <hr />
689
690           <pre>$location.path() = {{main.$location.path()}}</pre>
691           <pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
692           <pre>$route.current.params = {{main.$route.current.params}}</pre>
693           <pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
694           <pre>$routeParams = {{main.$routeParams}}</pre>
695         </div>
696       </file>
697
698       <file name="book.html">
699         <div>
700           controller: {{book.name}}<br />
701           Book Id: {{book.params.bookId}}<br />
702         </div>
703       </file>
704
705       <file name="chapter.html">
706         <div>
707           controller: {{chapter.name}}<br />
708           Book Id: {{chapter.params.bookId}}<br />
709           Chapter Id: {{chapter.params.chapterId}}
710         </div>
711       </file>
712
713       <file name="animations.css">
714         .view-animate-container {
715           position:relative;
716           height:100px!important;
717           position:relative;
718           background:white;
719           border:1px solid black;
720           height:40px;
721           overflow:hidden;
722         }
723
724         .view-animate {
725           padding:10px;
726         }
727
728         .view-animate.ng-enter, .view-animate.ng-leave {
729           -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
730           transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
731
732           display:block;
733           width:100%;
734           border-left:1px solid black;
735
736           position:absolute;
737           top:0;
738           left:0;
739           right:0;
740           bottom:0;
741           padding:10px;
742         }
743
744         .view-animate.ng-enter {
745           left:100%;
746         }
747         .view-animate.ng-enter.ng-enter-active {
748           left:0;
749         }
750         .view-animate.ng-leave.ng-leave-active {
751           left:-100%;
752         }
753       </file>
754
755       <file name="script.js">
756         angular.module('ngViewExample', ['ngRoute', 'ngAnimate'])
757           .config(['$routeProvider', '$locationProvider',
758             function($routeProvider, $locationProvider) {
759               $routeProvider
760                 .when('/Book/:bookId', {
761                   templateUrl: 'book.html',
762                   controller: 'BookCtrl',
763                   controllerAs: 'book'
764                 })
765                 .when('/Book/:bookId/ch/:chapterId', {
766                   templateUrl: 'chapter.html',
767                   controller: 'ChapterCtrl',
768                   controllerAs: 'chapter'
769                 });
770
771               $locationProvider.html5Mode(true);
772           }])
773           .controller('MainCtrl', ['$route', '$routeParams', '$location',
774             function($route, $routeParams, $location) {
775               this.$route = $route;
776               this.$location = $location;
777               this.$routeParams = $routeParams;
778           }])
779           .controller('BookCtrl', ['$routeParams', function($routeParams) {
780             this.name = "BookCtrl";
781             this.params = $routeParams;
782           }])
783           .controller('ChapterCtrl', ['$routeParams', function($routeParams) {
784             this.name = "ChapterCtrl";
785             this.params = $routeParams;
786           }]);
787
788       </file>
789
790       <file name="protractor.js" type="protractor">
791         it('should load and compile correct template', function() {
792           element(by.linkText('Moby: Ch1')).click();
793           var content = element(by.css('[ng-view]')).getText();
794           expect(content).toMatch(/controller\: ChapterCtrl/);
795           expect(content).toMatch(/Book Id\: Moby/);
796           expect(content).toMatch(/Chapter Id\: 1/);
797
798           element(by.partialLinkText('Scarlet')).click();
799
800           content = element(by.css('[ng-view]')).getText();
801           expect(content).toMatch(/controller\: BookCtrl/);
802           expect(content).toMatch(/Book Id\: Scarlet/);
803         });
804       </file>
805     </example>
806  */
807
808
809 /**
810  * @ngdoc event
811  * @name ngView#$viewContentLoaded
812  * @eventType emit on the current ngView scope
813  * @description
814  * Emitted every time the ngView content is reloaded.
815  */
816 ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
817 function ngViewFactory(   $route,   $anchorScroll,   $animate) {
818   return {
819     restrict: 'ECA',
820     terminal: true,
821     priority: 400,
822     transclude: 'element',
823     link: function(scope, $element, attr, ctrl, $transclude) {
824         var currentScope,
825             currentElement,
826             previousElement,
827             autoScrollExp = attr.autoscroll,
828             onloadExp = attr.onload || '';
829
830         scope.$on('$routeChangeSuccess', update);
831         update();
832
833         function cleanupLastView() {
834           if(previousElement) {
835             previousElement.remove();
836             previousElement = null;
837           }
838           if(currentScope) {
839             currentScope.$destroy();
840             currentScope = null;
841           }
842           if(currentElement) {
843             $animate.leave(currentElement, function() {
844               previousElement = null;
845             });
846             previousElement = currentElement;
847             currentElement = null;
848           }
849         }
850
851         function update() {
852           var locals = $route.current && $route.current.locals,
853               template = locals && locals.$template;
854
855           if (angular.isDefined(template)) {
856             var newScope = scope.$new();
857             var current = $route.current;
858
859             // Note: This will also link all children of ng-view that were contained in the original
860             // html. If that content contains controllers, ... they could pollute/change the scope.
861             // However, using ng-view on an element with additional content does not make sense...
862             // Note: We can't remove them in the cloneAttchFn of $transclude as that
863             // function is called before linking the content, which would apply child
864             // directives to non existing elements.
865             var clone = $transclude(newScope, function(clone) {
866               $animate.enter(clone, null, currentElement || $element, function onNgViewEnter () {
867                 if (angular.isDefined(autoScrollExp)
868                   && (!autoScrollExp || scope.$eval(autoScrollExp))) {
869                   $anchorScroll();
870                 }
871               });
872               cleanupLastView();
873             });
874
875             currentElement = clone;
876             currentScope = current.scope = newScope;
877             currentScope.$emit('$viewContentLoaded');
878             currentScope.$eval(onloadExp);
879           } else {
880             cleanupLastView();
881           }
882         }
883     }
884   };
885 }
886
887 // This directive is called during the $transclude call of the first `ngView` directive.
888 // It will replace and compile the content of the element with the loaded template.
889 // We need this directive so that the element content is already filled when
890 // the link function of another directive on the same element as ngView
891 // is called.
892 ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
893 function ngViewFillContentFactory($compile, $controller, $route) {
894   return {
895     restrict: 'ECA',
896     priority: -400,
897     link: function(scope, $element) {
898       var current = $route.current,
899           locals = current.locals;
900
901       $element.html(locals.$template);
902
903       var link = $compile($element.contents());
904
905       if (current.controller) {
906         locals.$scope = scope;
907         var controller = $controller(current.controller, locals);
908         if (current.controllerAs) {
909           scope[current.controllerAs] = controller;
910         }
911         $element.data('$ngControllerController', controller);
912         $element.children().data('$ngControllerController', controller);
913       }
914
915       link(scope);
916     }
917   };
918 }
919
920
921 })(window, window.angular);