├── LICENSE.md ├── README.md ├── angular-route.js ├── angular-route.min.js ├── angular-route.min.js.map ├── bower.json ├── index.js └── package.json /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Angular 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # packaged angular-route 2 | 3 | **This package contains the legacy AngularJS (version 1.x). AngularJS support has officially ended 4 | as of January 2022. 5 | [See what ending support means](https://docs.angularjs.org/misc/version-support-status) and 6 | [read the end of life announcement](https://goo.gle/angularjs-end-of-life).** 7 | 8 | **[See `@angular/core` for the actively supported Angular](https://npmjs.com/@angular/core).** 9 | 10 | ## Install 11 | 12 | You can install this package either with `npm` or with `bower`. 13 | 14 | ### npm 15 | 16 | ```shell 17 | npm install angular-route 18 | ``` 19 | 20 | Then add `ngRoute` as a dependency for your app: 21 | 22 | ```javascript 23 | angular.module('myApp', [require('angular-route')]); 24 | ``` 25 | 26 | ### bower 27 | 28 | ```shell 29 | bower install angular-route 30 | ``` 31 | 32 | Add a ` 36 | ``` 37 | 38 | Then add `ngRoute` as a dependency for your app: 39 | 40 | ```javascript 41 | angular.module('myApp', ['ngRoute']); 42 | ``` 43 | 44 | ## Documentation 45 | 46 | Documentation is available on the 47 | [AngularJS docs site](http://docs.angularjs.org/api/ngRoute). 48 | 49 | ## License 50 | 51 | The MIT License 52 | 53 | Copyright (c) 2022 Google LLC 54 | 55 | Permission is hereby granted, free of charge, to any person obtaining a copy 56 | of this software and associated documentation files (the "Software"), to deal 57 | in the Software without restriction, including without limitation the rights 58 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 59 | copies of the Software, and to permit persons to whom the Software is 60 | furnished to do so, subject to the following conditions: 61 | 62 | The above copyright notice and this permission notice shall be included in 63 | all copies or substantial portions of the Software. 64 | 65 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 66 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 67 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 68 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 69 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 70 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 71 | THE SOFTWARE. 72 | -------------------------------------------------------------------------------- /angular-route.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.8.3 3 | * (c) 2010-2020 Google LLC. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular) {'use strict'; 7 | 8 | /* global shallowCopy: true */ 9 | 10 | /** 11 | * Creates a shallow copy of an object, an array or a primitive. 12 | * 13 | * Assumes that there are no proto properties for objects. 14 | */ 15 | function shallowCopy(src, dst) { 16 | if (isArray(src)) { 17 | dst = dst || []; 18 | 19 | for (var i = 0, ii = src.length; i < ii; i++) { 20 | dst[i] = src[i]; 21 | } 22 | } else if (isObject(src)) { 23 | dst = dst || {}; 24 | 25 | for (var key in src) { 26 | if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { 27 | dst[key] = src[key]; 28 | } 29 | } 30 | } 31 | 32 | return dst || src; 33 | } 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 */ 81 | /* global shallowCopy: false */ 82 | 83 | // `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`). 84 | // They are initialized inside the `$RouteProvider`, to ensure `window.angular` is available. 85 | var isArray; 86 | var isObject; 87 | var isDefined; 88 | var noop; 89 | 90 | /** 91 | * @ngdoc module 92 | * @name ngRoute 93 | * @description 94 | * 95 | * The `ngRoute` module provides routing and deeplinking services and directives for AngularJS apps. 96 | * 97 | * ## Example 98 | * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. 99 | * 100 | */ 101 | /* global -ngRouteModule */ 102 | var ngRouteModule = angular. 103 | module('ngRoute', []). 104 | info({ angularVersion: '1.8.3' }). 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 | 113 | 114 | /** 115 | * @ngdoc provider 116 | * @name $routeProvider 117 | * @this 118 | * 119 | * @description 120 | * 121 | * Used for configuring routes. 122 | * 123 | * ## Example 124 | * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`. 125 | * 126 | * ## Dependencies 127 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 128 | */ 129 | function $RouteProvider() { 130 | isArray = angular.isArray; 131 | isObject = angular.isObject; 132 | isDefined = angular.isDefined; 133 | noop = angular.noop; 134 | 135 | function inherit(parent, extra) { 136 | return angular.extend(Object.create(parent), extra); 137 | } 138 | 139 | var routes = {}; 140 | 141 | /** 142 | * @ngdoc method 143 | * @name $routeProvider#when 144 | * 145 | * @param {string} path Route path (matched against `$location.path`). If `$location.path` 146 | * contains redundant trailing slash or is missing one, the route will still match and the 147 | * `$location.path` will be updated to add or drop the trailing slash to exactly match the 148 | * route definition. 149 | * 150 | * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up 151 | * to the next slash are matched and stored in `$routeParams` under the given `name` 152 | * when the route matches. 153 | * * `path` can contain named groups starting with a colon and ending with a star: 154 | * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name` 155 | * when the route matches. 156 | * * `path` can contain optional named groups with a question mark: e.g.`:name?`. 157 | * 158 | * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match 159 | * `/color/brown/largecode/code/with/slashes/edit` and extract: 160 | * 161 | * * `color: brown` 162 | * * `largecode: code/with/slashes`. 163 | * 164 | * 165 | * @param {Object} route Mapping information to be assigned to `$route.current` on route 166 | * match. 167 | * 168 | * Object properties: 169 | * 170 | * - `controller` – `{(string|Function)=}` – Controller fn that should be associated with 171 | * newly created scope or the name of a {@link angular.Module#controller registered 172 | * controller} if passed as a string. 173 | * - `controllerAs` – `{string=}` – An identifier name for a reference to the controller. 174 | * If present, the controller will be published to scope under the `controllerAs` name. 175 | * - `template` – `{(string|Function)=}` – html template as a string or a function that 176 | * returns an html template as a string which should be used by {@link 177 | * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives. 178 | * This property takes precedence over `templateUrl`. 179 | * 180 | * If `template` is a function, it will be called with the following parameters: 181 | * 182 | * - `{Array.}` - route parameters extracted from the current 183 | * `$location.path()` by applying the current route 184 | * 185 | * One of `template` or `templateUrl` is required. 186 | * 187 | * - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html 188 | * template that should be used by {@link ngRoute.directive:ngView ngView}. 189 | * 190 | * If `templateUrl` is a function, it will be called with the following parameters: 191 | * 192 | * - `{Array.}` - route parameters extracted from the current 193 | * `$location.path()` by applying the current route 194 | * 195 | * One of `templateUrl` or `template` is required. 196 | * 197 | * - `resolve` - `{Object.=}` - An optional map of dependencies which should 198 | * be injected into the controller. If any of these dependencies are promises, the router 199 | * will wait for them all to be resolved or one to be rejected before the controller is 200 | * instantiated. 201 | * If all the promises are resolved successfully, the values of the resolved promises are 202 | * injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is 203 | * fired. If any of the promises are rejected the 204 | * {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. 205 | * For easier access to the resolved dependencies from the template, the `resolve` map will 206 | * be available on the scope of the route, under `$resolve` (by default) or a custom name 207 | * specified by the `resolveAs` property (see below). This can be particularly useful, when 208 | * working with {@link angular.Module#component components} as route templates.
209 | *
210 | * **Note:** If your scope already contains a property with this name, it will be hidden 211 | * or overwritten. Make sure, you specify an appropriate name for this property, that 212 | * does not collide with other properties on the scope. 213 | *
214 | * The map object is: 215 | * 216 | * - `key` – `{string}`: a name of a dependency to be injected into the controller. 217 | * - `factory` - `{string|Function}`: If `string` then it is an alias for a service. 218 | * Otherwise if function, then it is {@link auto.$injector#invoke injected} 219 | * and the return value is treated as the dependency. If the result is a promise, it is 220 | * resolved before its value is injected into the controller. Be aware that 221 | * `ngRoute.$routeParams` will still refer to the previous route within these resolve 222 | * functions. Use `$route.current.params` to access the new route parameters, instead. 223 | * 224 | * - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on 225 | * the scope of the route. If omitted, defaults to `$resolve`. 226 | * 227 | * - `redirectTo` – `{(string|Function)=}` – value to update 228 | * {@link ng.$location $location} path with and trigger route redirection. 229 | * 230 | * If `redirectTo` is a function, it will be called with the following parameters: 231 | * 232 | * - `{Object.}` - route parameters extracted from the current 233 | * `$location.path()` by applying the current route templateUrl. 234 | * - `{string}` - current `$location.path()` 235 | * - `{Object}` - current `$location.search()` 236 | * 237 | * The custom `redirectTo` function is expected to return a string which will be used 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). 270 | * 271 | * - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()` 272 | * or `$location.hash()` changes. 273 | * 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 | *
278 | * **Note:** This option has no effect if `reloadOnUrl` is set to `false`. 279 | *
280 | * 281 | * - `[caseInsensitiveMatch=false]` - `{boolean=}` - match routes without being case sensitive 282 | * 283 | * If the option is set to `true`, then the particular route can be matched without being 284 | * case sensitive 285 | * 286 | * @returns {Object} self 287 | * 288 | * @description 289 | * Adds a new route definition to the `$route` service. 290 | */ 291 | this.when = function(path, route) { 292 | //copy original route object to preserve params inherited from proto chain 293 | var routeCopy = shallowCopy(route); 294 | if (angular.isUndefined(routeCopy.reloadOnUrl)) { 295 | routeCopy.reloadOnUrl = true; 296 | } 297 | if (angular.isUndefined(routeCopy.reloadOnSearch)) { 298 | routeCopy.reloadOnSearch = true; 299 | } 300 | if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) { 301 | routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch; 302 | } 303 | routes[path] = angular.extend( 304 | routeCopy, 305 | {originalPath: path}, 306 | path && routeToRegExp(path, routeCopy) 307 | ); 308 | 309 | // create redirection for trailing slashes 310 | if (path) { 311 | var redirectPath = (path[path.length - 1] === '/') 312 | ? path.substr(0, path.length - 1) 313 | : path + '/'; 314 | 315 | routes[redirectPath] = angular.extend( 316 | {originalPath: path, redirectTo: path}, 317 | routeToRegExp(redirectPath, routeCopy) 318 | ); 319 | } 320 | 321 | return this; 322 | }; 323 | 324 | /** 325 | * @ngdoc property 326 | * @name $routeProvider#caseInsensitiveMatch 327 | * @description 328 | * 329 | * A boolean property indicating if routes defined 330 | * using this provider should be matched using a case insensitive 331 | * algorithm. Defaults to `false`. 332 | */ 333 | this.caseInsensitiveMatch = false; 334 | 335 | /** 336 | * @ngdoc method 337 | * @name $routeProvider#otherwise 338 | * 339 | * @description 340 | * Sets route definition that will be used on route change when no other route definition 341 | * is matched. 342 | * 343 | * @param {Object|string} params Mapping information to be assigned to `$route.current`. 344 | * If called with a string, the value maps to `redirectTo`. 345 | * @returns {Object} self 346 | */ 347 | this.otherwise = function(params) { 348 | if (typeof params === 'string') { 349 | params = {redirectTo: params}; 350 | } 351 | this.when(null, params); 352 | return this; 353 | }; 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**:
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 | 396 | 397 | this.$get = ['$rootScope', 398 | '$location', 399 | '$routeParams', 400 | '$q', 401 | '$injector', 402 | '$templateRequest', 403 | '$sce', 404 | '$browser', 405 | function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) { 406 | 407 | /** 408 | * @ngdoc service 409 | * @name $route 410 | * @requires $location 411 | * @requires $routeParams 412 | * 413 | * @property {Object} current Reference to the current route definition. 414 | * The route definition contains: 415 | * 416 | * - `controller`: The controller constructor as defined in the route definition. 417 | * - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for 418 | * controller instantiation. The `locals` contain 419 | * the resolved values of the `resolve` map. Additionally the `locals` also contain: 420 | * 421 | * - `$scope` - The current route scope. 422 | * - `$template` - The current route template HTML. 423 | * 424 | * The `locals` will be assigned to the route scope's `$resolve` property. You can override 425 | * the property name, using `resolveAs` in the route definition. See 426 | * {@link ngRoute.$routeProvider $routeProvider} for more info. 427 | * 428 | * @property {Object} routes Object with all route configuration Objects as its properties. 429 | * 430 | * @description 431 | * `$route` is used for deep-linking URLs to controllers and views (HTML partials). 432 | * It watches `$location.url()` and tries to map the path to an existing route definition. 433 | * 434 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 435 | * 436 | * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API. 437 | * 438 | * The `$route` service is typically used in conjunction with the 439 | * {@link ngRoute.directive:ngView `ngView`} directive and the 440 | * {@link ngRoute.$routeParams `$routeParams`} service. 441 | * 442 | * @example 443 | * This example shows how changing the URL hash causes the `$route` to match a route against the 444 | * URL, and the `ngView` pulls in the partial. 445 | * 446 | * 448 | * 449 | *
450 | * Choose: 451 | * Moby | 452 | * Moby: Ch1 | 453 | * Gatsby | 454 | * Gatsby: Ch4 | 455 | * Scarlet Letter
456 | * 457 | *
458 | * 459 | *
460 | * 461 | *
$location.path() = {{$location.path()}}
462 | *
$route.current.templateUrl = {{$route.current.templateUrl}}
463 | *
$route.current.params = {{$route.current.params}}
464 | *
$route.current.scope.name = {{$route.current.scope.name}}
465 | *
$routeParams = {{$routeParams}}
466 | *
467 | *
468 | * 469 | * 470 | * controller: {{name}}
471 | * Book Id: {{params.bookId}}
472 | *
473 | * 474 | * 475 | * controller: {{name}}
476 | * Book Id: {{params.bookId}}
477 | * Chapter Id: {{params.chapterId}} 478 | *
479 | * 480 | * 481 | * angular.module('ngRouteExample', ['ngRoute']) 482 | * 483 | * .controller('MainController', function($scope, $route, $routeParams, $location) { 484 | * $scope.$route = $route; 485 | * $scope.$location = $location; 486 | * $scope.$routeParams = $routeParams; 487 | * }) 488 | * 489 | * .controller('BookController', function($scope, $routeParams) { 490 | * $scope.name = 'BookController'; 491 | * $scope.params = $routeParams; 492 | * }) 493 | * 494 | * .controller('ChapterController', function($scope, $routeParams) { 495 | * $scope.name = 'ChapterController'; 496 | * $scope.params = $routeParams; 497 | * }) 498 | * 499 | * .config(function($routeProvider, $locationProvider) { 500 | * $routeProvider 501 | * .when('/Book/:bookId', { 502 | * templateUrl: 'book.html', 503 | * controller: 'BookController', 504 | * resolve: { 505 | * // I will cause a 1 second delay 506 | * delay: function($q, $timeout) { 507 | * var delay = $q.defer(); 508 | * $timeout(delay.resolve, 1000); 509 | * return delay.promise; 510 | * } 511 | * } 512 | * }) 513 | * .when('/Book/:bookId/ch/:chapterId', { 514 | * templateUrl: 'chapter.html', 515 | * controller: 'ChapterController' 516 | * }); 517 | * 518 | * // configure html5 to get links working on jsfiddle 519 | * $locationProvider.html5Mode(true); 520 | * }); 521 | * 522 | * 523 | * 524 | * 525 | * it('should load and compile correct template', function() { 526 | * element(by.linkText('Moby: Ch1')).click(); 527 | * var content = element(by.css('[ng-view]')).getText(); 528 | * expect(content).toMatch(/controller: ChapterController/); 529 | * expect(content).toMatch(/Book Id: Moby/); 530 | * expect(content).toMatch(/Chapter Id: 1/); 531 | * 532 | * element(by.partialLinkText('Scarlet')).click(); 533 | * 534 | * content = element(by.css('[ng-view]')).getText(); 535 | * expect(content).toMatch(/controller: BookController/); 536 | * expect(content).toMatch(/Book Id: Scarlet/); 537 | * }); 538 | * 539 | *
540 | */ 541 | 542 | /** 543 | * @ngdoc event 544 | * @name $route#$routeChangeStart 545 | * @eventType broadcast on root scope 546 | * @description 547 | * Broadcasted before a route change. At this point the route services starts 548 | * resolving all of the dependencies needed for the route change to occur. 549 | * Typically this involves fetching the view template as well as any dependencies 550 | * defined in `resolve` route property. Once all of the dependencies are resolved 551 | * `$routeChangeSuccess` is fired. 552 | * 553 | * The route change (and the `$location` change that triggered it) can be prevented 554 | * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} 555 | * for more details about event object. 556 | * 557 | * @param {Object} angularEvent Synthetic event object. 558 | * @param {Route} next Future route information. 559 | * @param {Route} current Current route information. 560 | */ 561 | 562 | /** 563 | * @ngdoc event 564 | * @name $route#$routeChangeSuccess 565 | * @eventType broadcast on root scope 566 | * @description 567 | * Broadcasted after a route change has happened successfully. 568 | * The `resolve` dependencies are now available in the `current.locals` property. 569 | * 570 | * {@link ngRoute.directive:ngView ngView} listens for the directive 571 | * to instantiate the controller and render the view. 572 | * 573 | * @param {Object} angularEvent Synthetic event object. 574 | * @param {Route} current Current route information. 575 | * @param {Route|Undefined} previous Previous route information, or undefined if current is 576 | * first route entered. 577 | */ 578 | 579 | /** 580 | * @ngdoc event 581 | * @name $route#$routeChangeError 582 | * @eventType broadcast on root scope 583 | * @description 584 | * Broadcasted if a redirection function fails or any redirection or resolve promises are 585 | * rejected. 586 | * 587 | * @param {Object} angularEvent Synthetic event object 588 | * @param {Route} current Current route information. 589 | * @param {Route} previous Previous route information. 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. 592 | */ 593 | 594 | /** 595 | * @ngdoc event 596 | * @name $route#$routeUpdate 597 | * @eventType broadcast on root scope 598 | * @description 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`. 602 | * 603 | * @param {Object} angularEvent Synthetic event object 604 | * @param {Route} current Current/previous route information. 605 | */ 606 | 607 | var forceReload = false, 608 | preparedRoute, 609 | preparedRouteIsUpdateOnly, 610 | $route = { 611 | routes: routes, 612 | 613 | /** 614 | * @ngdoc method 615 | * @name $route#reload 616 | * 617 | * @description 618 | * Causes `$route` service to reload the current route even if 619 | * {@link ng.$location $location} hasn't changed. 620 | * 621 | * As a result of that, {@link ngRoute.directive:ngView ngView} 622 | * creates new scope and reinstantiates the controller. 623 | */ 624 | reload: function() { 625 | forceReload = true; 626 | 627 | var fakeLocationEvent = { 628 | defaultPrevented: false, 629 | preventDefault: function fakePreventDefault() { 630 | this.defaultPrevented = true; 631 | forceReload = false; 632 | } 633 | }; 634 | 635 | $rootScope.$evalAsync(function() { 636 | prepareRoute(fakeLocationEvent); 637 | if (!fakeLocationEvent.defaultPrevented) commitRoute(); 638 | }); 639 | }, 640 | 641 | /** 642 | * @ngdoc method 643 | * @name $route#updateParams 644 | * 645 | * @description 646 | * Causes `$route` service to update the current URL, replacing 647 | * current route parameters with those specified in `newParams`. 648 | * Provided property names that match the route's path segment 649 | * definitions will be interpolated into the location's path, while 650 | * remaining properties will be treated as query params. 651 | * 652 | * @param {!Object} newParams mapping of URL parameter names to values 653 | */ 654 | updateParams: function(newParams) { 655 | if (this.current && this.current.$$route) { 656 | newParams = angular.extend({}, this.current.params, newParams); 657 | $location.path(interpolate(this.current.$$route.originalPath, newParams)); 658 | // interpolate modifies newParams, only query params are left 659 | $location.search(newParams); 660 | } else { 661 | throw $routeMinErr('norout', 'Tried updating route with no current route'); 662 | } 663 | } 664 | }; 665 | 666 | $rootScope.$on('$locationChangeStart', prepareRoute); 667 | $rootScope.$on('$locationChangeSuccess', commitRoute); 668 | 669 | return $route; 670 | 671 | ///////////////////////////////////////////////////// 672 | 673 | /** 674 | * @param on {string} current url 675 | * @param route {Object} route regexp to match the url against 676 | * @return {?Object} 677 | * 678 | * @description 679 | * Check if the route matches the current url. 680 | * 681 | * Inspired by match in 682 | * visionmedia/express/lib/router/router.js. 683 | */ 684 | function switchRouteMatcher(on, route) { 685 | var keys = route.keys, 686 | params = {}; 687 | 688 | if (!route.regexp) return null; 689 | 690 | var m = route.regexp.exec(on); 691 | if (!m) return null; 692 | 693 | for (var i = 1, len = m.length; i < len; ++i) { 694 | var key = keys[i - 1]; 695 | 696 | var val = m[i]; 697 | 698 | if (key && val) { 699 | params[key.name] = val; 700 | } 701 | } 702 | return params; 703 | } 704 | 705 | function prepareRoute($locationEvent) { 706 | var lastRoute = $route.current; 707 | 708 | preparedRoute = parseRoute(); 709 | preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute); 710 | 711 | if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) { 712 | if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) { 713 | if ($locationEvent) { 714 | $locationEvent.preventDefault(); 715 | } 716 | } 717 | } 718 | } 719 | 720 | function commitRoute() { 721 | var lastRoute = $route.current; 722 | var nextRoute = preparedRoute; 723 | 724 | if (preparedRouteIsUpdateOnly) { 725 | lastRoute.params = nextRoute.params; 726 | angular.copy(lastRoute.params, $routeParams); 727 | $rootScope.$broadcast('$routeUpdate', lastRoute); 728 | } else if (nextRoute || lastRoute) { 729 | forceReload = false; 730 | $route.current = nextRoute; 731 | 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) { 754 | $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error); 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'); 763 | }); 764 | } 765 | } 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 | 837 | function resolveLocals(route) { 838 | if (route) { 839 | var locals = angular.extend({}, route.resolve); 840 | angular.forEach(locals, function(value, key) { 841 | locals[key] = angular.isString(value) ? 842 | $injector.get(value) : 843 | $injector.invoke(value, null, null, key); 844 | }); 845 | var template = getTemplateFor(route); 846 | if (angular.isDefined(template)) { 847 | locals['$template'] = template; 848 | } 849 | return $q.all(locals); 850 | } 851 | } 852 | 853 | function getTemplateFor(route) { 854 | var template, templateUrl; 855 | if (angular.isDefined(template = route.template)) { 856 | if (angular.isFunction(template)) { 857 | template = template(route.params); 858 | } 859 | } else if (angular.isDefined(templateUrl = route.templateUrl)) { 860 | if (angular.isFunction(templateUrl)) { 861 | templateUrl = templateUrl(route.params); 862 | } 863 | if (angular.isDefined(templateUrl)) { 864 | route.loadedTemplateUrl = $sce.valueOf(templateUrl); 865 | template = $templateRequest(templateUrl); 866 | } 867 | } 868 | return template; 869 | } 870 | 871 | /** 872 | * @returns {Object} the current active route, by matching it against the URL 873 | */ 874 | function parseRoute() { 875 | // Match a route 876 | var params, match; 877 | angular.forEach(routes, function(route, path) { 878 | if (!match && (params = switchRouteMatcher($location.path(), route))) { 879 | match = inherit(route, { 880 | params: angular.extend({}, $location.search(), params), 881 | pathParams: params}); 882 | match.$$route = route; 883 | } 884 | }); 885 | // No route matched; fallback to "otherwise" route 886 | return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}}); 887 | } 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 | 912 | /** 913 | * @returns {string} interpolation of the redirect path with the parameters 914 | */ 915 | function interpolate(string, params) { 916 | var result = []; 917 | angular.forEach((string || '').split(':'), function(segment, i) { 918 | if (i === 0) { 919 | result.push(segment); 920 | } else { 921 | var segmentMatch = segment.match(/(\w+)(?:[?*])?(.*)/); 922 | var key = segmentMatch[1]; 923 | result.push(params[key]); 924 | result.push(segmentMatch[2] || ''); 925 | delete params[key]; 926 | } 927 | }); 928 | return result.join(''); 929 | } 930 | }]; 931 | } 932 | 933 | instantiateRoute.$inject = ['$injector']; 934 | function instantiateRoute($injector) { 935 | if (isEagerInstantiationEnabled) { 936 | // Instantiate `$route` 937 | $injector.get('$route'); 938 | } 939 | } 940 | 941 | ngRouteModule.provider('$routeParams', $RouteParamsProvider); 942 | 943 | 944 | /** 945 | * @ngdoc service 946 | * @name $routeParams 947 | * @requires $route 948 | * @this 949 | * 950 | * @description 951 | * The `$routeParams` service allows you to retrieve the current set of route parameters. 952 | * 953 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 954 | * 955 | * The route parameters are a combination of {@link ng.$location `$location`}'s 956 | * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}. 957 | * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched. 958 | * 959 | * In case of parameter name collision, `path` params take precedence over `search` params. 960 | * 961 | * The service guarantees that the identity of the `$routeParams` object will remain unchanged 962 | * (but its properties will likely change) even when a route change occurs. 963 | * 964 | * Note that the `$routeParams` are only updated *after* a route change completes successfully. 965 | * This means that you cannot rely on `$routeParams` being correct in route resolve functions. 966 | * Instead you can use `$route.current.params` to access the new route's parameters. 967 | * 968 | * @example 969 | * ```js 970 | * // Given: 971 | * // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby 972 | * // Route: /Chapter/:chapterId/Section/:sectionId 973 | * // 974 | * // Then 975 | * $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'} 976 | * ``` 977 | */ 978 | function $RouteParamsProvider() { 979 | this.$get = function() { return {}; }; 980 | } 981 | 982 | ngRouteModule.directive('ngView', ngViewFactory); 983 | ngRouteModule.directive('ngView', ngViewFillContentFactory); 984 | 985 | 986 | /** 987 | * @ngdoc directive 988 | * @name ngView 989 | * @restrict ECA 990 | * 991 | * @description 992 | * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by 993 | * including the rendered template of the current route into the main layout (`index.html`) file. 994 | * Every time the current route changes, the included view changes with it according to the 995 | * configuration of the `$route` service. 996 | * 997 | * Requires the {@link ngRoute `ngRoute`} module to be installed. 998 | * 999 | * @animations 1000 | * | Animation | Occurs | 1001 | * |----------------------------------|-------------------------------------| 1002 | * | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM | 1003 | * | {@link ng.$animate#leave leave} | when the old element is removed from to the DOM | 1004 | * 1005 | * The enter and leave animation occur concurrently. 1006 | * 1007 | * @scope 1008 | * @priority 400 1009 | * @param {string=} onload Expression to evaluate whenever the view updates. 1010 | * 1011 | * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll 1012 | * $anchorScroll} to scroll the viewport after the view is updated. 1013 | * 1014 | * - If the attribute is not set, disable scrolling. 1015 | * - If the attribute is set without value, enable scrolling. 1016 | * - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated 1017 | * as an expression yields a truthy value. 1018 | * @example 1019 | 1022 | 1023 |
1024 | Choose: 1025 | Moby | 1026 | Moby: Ch1 | 1027 | Gatsby | 1028 | Gatsby: Ch4 | 1029 | Scarlet Letter
1030 | 1031 |
1032 |
1033 |
1034 |
1035 | 1036 |
$location.path() = {{main.$location.path()}}
1037 |
$route.current.templateUrl = {{main.$route.current.templateUrl}}
1038 |
$route.current.params = {{main.$route.current.params}}
1039 |
$routeParams = {{main.$routeParams}}
1040 |
1041 |
1042 | 1043 | 1044 |
1045 | controller: {{book.name}}
1046 | Book Id: {{book.params.bookId}}
1047 |
1048 |
1049 | 1050 | 1051 |
1052 | controller: {{chapter.name}}
1053 | Book Id: {{chapter.params.bookId}}
1054 | Chapter Id: {{chapter.params.chapterId}} 1055 |
1056 |
1057 | 1058 | 1059 | .view-animate-container { 1060 | position:relative; 1061 | height:100px!important; 1062 | background:white; 1063 | border:1px solid black; 1064 | height:40px; 1065 | overflow:hidden; 1066 | } 1067 | 1068 | .view-animate { 1069 | padding:10px; 1070 | } 1071 | 1072 | .view-animate.ng-enter, .view-animate.ng-leave { 1073 | transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s; 1074 | 1075 | display:block; 1076 | width:100%; 1077 | border-left:1px solid black; 1078 | 1079 | position:absolute; 1080 | top:0; 1081 | left:0; 1082 | right:0; 1083 | bottom:0; 1084 | padding:10px; 1085 | } 1086 | 1087 | .view-animate.ng-enter { 1088 | left:100%; 1089 | } 1090 | .view-animate.ng-enter.ng-enter-active { 1091 | left:0; 1092 | } 1093 | .view-animate.ng-leave.ng-leave-active { 1094 | left:-100%; 1095 | } 1096 | 1097 | 1098 | 1099 | angular.module('ngViewExample', ['ngRoute', 'ngAnimate']) 1100 | .config(['$routeProvider', '$locationProvider', 1101 | function($routeProvider, $locationProvider) { 1102 | $routeProvider 1103 | .when('/Book/:bookId', { 1104 | templateUrl: 'book.html', 1105 | controller: 'BookCtrl', 1106 | controllerAs: 'book' 1107 | }) 1108 | .when('/Book/:bookId/ch/:chapterId', { 1109 | templateUrl: 'chapter.html', 1110 | controller: 'ChapterCtrl', 1111 | controllerAs: 'chapter' 1112 | }); 1113 | 1114 | $locationProvider.html5Mode(true); 1115 | }]) 1116 | .controller('MainCtrl', ['$route', '$routeParams', '$location', 1117 | function MainCtrl($route, $routeParams, $location) { 1118 | this.$route = $route; 1119 | this.$location = $location; 1120 | this.$routeParams = $routeParams; 1121 | }]) 1122 | .controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) { 1123 | this.name = 'BookCtrl'; 1124 | this.params = $routeParams; 1125 | }]) 1126 | .controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) { 1127 | this.name = 'ChapterCtrl'; 1128 | this.params = $routeParams; 1129 | }]); 1130 | 1131 | 1132 | 1133 | 1134 | it('should load and compile correct template', function() { 1135 | element(by.linkText('Moby: Ch1')).click(); 1136 | var content = element(by.css('[ng-view]')).getText(); 1137 | expect(content).toMatch(/controller: ChapterCtrl/); 1138 | expect(content).toMatch(/Book Id: Moby/); 1139 | expect(content).toMatch(/Chapter Id: 1/); 1140 | 1141 | element(by.partialLinkText('Scarlet')).click(); 1142 | 1143 | content = element(by.css('[ng-view]')).getText(); 1144 | expect(content).toMatch(/controller: BookCtrl/); 1145 | expect(content).toMatch(/Book Id: Scarlet/); 1146 | }); 1147 | 1148 |
1149 | */ 1150 | 1151 | 1152 | /** 1153 | * @ngdoc event 1154 | * @name ngView#$viewContentLoaded 1155 | * @eventType emit on the current ngView scope 1156 | * @description 1157 | * Emitted every time the ngView content is reloaded. 1158 | */ 1159 | ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate']; 1160 | function ngViewFactory($route, $anchorScroll, $animate) { 1161 | return { 1162 | restrict: 'ECA', 1163 | terminal: true, 1164 | priority: 400, 1165 | transclude: 'element', 1166 | link: function(scope, $element, attr, ctrl, $transclude) { 1167 | var currentScope, 1168 | currentElement, 1169 | previousLeaveAnimation, 1170 | autoScrollExp = attr.autoscroll, 1171 | onloadExp = attr.onload || ''; 1172 | 1173 | scope.$on('$routeChangeSuccess', update); 1174 | update(); 1175 | 1176 | function cleanupLastView() { 1177 | if (previousLeaveAnimation) { 1178 | $animate.cancel(previousLeaveAnimation); 1179 | previousLeaveAnimation = null; 1180 | } 1181 | 1182 | if (currentScope) { 1183 | currentScope.$destroy(); 1184 | currentScope = null; 1185 | } 1186 | if (currentElement) { 1187 | previousLeaveAnimation = $animate.leave(currentElement); 1188 | previousLeaveAnimation.done(function(response) { 1189 | if (response !== false) previousLeaveAnimation = null; 1190 | }); 1191 | currentElement = null; 1192 | } 1193 | } 1194 | 1195 | function update() { 1196 | var locals = $route.current && $route.current.locals, 1197 | template = locals && locals.$template; 1198 | 1199 | if (angular.isDefined(template)) { 1200 | var newScope = scope.$new(); 1201 | var current = $route.current; 1202 | 1203 | // Note: This will also link all children of ng-view that were contained in the original 1204 | // html. If that content contains controllers, ... they could pollute/change the scope. 1205 | // However, using ng-view on an element with additional content does not make sense... 1206 | // Note: We can't remove them in the cloneAttchFn of $transclude as that 1207 | // function is called before linking the content, which would apply child 1208 | // directives to non existing elements. 1209 | var clone = $transclude(newScope, function(clone) { 1210 | $animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) { 1211 | if (response !== false && angular.isDefined(autoScrollExp) 1212 | && (!autoScrollExp || scope.$eval(autoScrollExp))) { 1213 | $anchorScroll(); 1214 | } 1215 | }); 1216 | cleanupLastView(); 1217 | }); 1218 | 1219 | currentElement = clone; 1220 | currentScope = current.scope = newScope; 1221 | currentScope.$emit('$viewContentLoaded'); 1222 | currentScope.$eval(onloadExp); 1223 | } else { 1224 | cleanupLastView(); 1225 | } 1226 | } 1227 | } 1228 | }; 1229 | } 1230 | 1231 | // This directive is called during the $transclude call of the first `ngView` directive. 1232 | // It will replace and compile the content of the element with the loaded template. 1233 | // We need this directive so that the element content is already filled when 1234 | // the link function of another directive on the same element as ngView 1235 | // is called. 1236 | ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route']; 1237 | function ngViewFillContentFactory($compile, $controller, $route) { 1238 | return { 1239 | restrict: 'ECA', 1240 | priority: -400, 1241 | link: function(scope, $element) { 1242 | var current = $route.current, 1243 | locals = current.locals; 1244 | 1245 | $element.html(locals.$template); 1246 | 1247 | var link = $compile($element.contents()); 1248 | 1249 | if (current.controller) { 1250 | locals.$scope = scope; 1251 | var controller = $controller(current.controller, locals); 1252 | if (current.controllerAs) { 1253 | scope[current.controllerAs] = controller; 1254 | } 1255 | $element.data('$ngControllerController', controller); 1256 | $element.children().data('$ngControllerController', controller); 1257 | } 1258 | scope[current.resolveAs || '$resolve'] = locals; 1259 | 1260 | link(scope); 1261 | } 1262 | }; 1263 | } 1264 | 1265 | 1266 | })(window, window.angular); 1267 | -------------------------------------------------------------------------------- /angular-route.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.8.3 3 | (c) 2010-2020 Google LLC. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(I,b){'use strict';function z(b,h){var d=[],c=b.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)(\*\?|[?*])?/g,function(b,c,h,k){b="?"===k||"*?"===k;k="*"===k||"*?"===k;d.push({name:h,optional:b});c=c||"";return(b?"(?:"+c:c+"(?:")+(k?"(.+?)":"([^/]+)")+(b?"?)?":")")}).replace(/([/$*])/g,"\\$1");h.ignoreTrailingSlashes&&(c=c.replace(/\/+$/,"")+"/*");return{keys:d,regexp:new RegExp("^"+c+"(?:[?#]|$)",h.caseInsensitiveMatch?"i":"")}}function A(b){p&&b.get("$route")}function v(u,h,d){return{restrict:"ECA", 7 | terminal:!0,priority:400,transclude:"element",link:function(c,f,g,l,k){function q(){r&&(d.cancel(r),r=null);m&&(m.$destroy(),m=null);s&&(r=d.leave(s),r.done(function(b){!1!==b&&(r=null)}),s=null)}function C(){var g=u.current&&u.current.locals;if(b.isDefined(g&&g.$template)){var g=c.$new(),l=u.current;s=k(g,function(g){d.enter(g,null,s||f).done(function(d){!1===d||!b.isDefined(w)||w&&!c.$eval(w)||h()});q()});m=l.scope=g;m.$emit("$viewContentLoaded");m.$eval(p)}else q()}var m,s,r,w=g.autoscroll,p=g.onload|| 8 | "";c.$on("$routeChangeSuccess",C);C()}}}function x(b,h,d){return{restrict:"ECA",priority:-400,link:function(c,f){var g=d.current,l=g.locals;f.html(l.$template);var k=b(f.contents());if(g.controller){l.$scope=c;var q=h(g.controller,l);g.controllerAs&&(c[g.controllerAs]=q);f.data("$ngControllerController",q);f.children().data("$ngControllerController",q)}c[g.resolveAs||"$resolve"]=l;k(c)}}}var D,E,F,G,y=b.module("ngRoute",[]).info({angularVersion:"1.8.3"}).provider("$route",function(){function u(d, 9 | c){return b.extend(Object.create(d),c)}D=b.isArray;E=b.isObject;F=b.isDefined;G=b.noop;var h={};this.when=function(d,c){var f;f=void 0;if(D(c)){f=f||[];for(var g=0,l=c.length;g", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/angular/angular.js/issues" 24 | }, 25 | "homepage": "http://angularjs.org", 26 | "jspm": { 27 | "shim": { 28 | "angular-route": { 29 | "deps": ["angular"] 30 | } 31 | } 32 | } 33 | } 34 | --------------------------------------------------------------------------------