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