UNPKG

47.4 kBJavaScriptView Raw
1/**
2 * @license Angular v9.0.4
3 * (c) 2010-2020 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { Location, PlatformLocation, LocationStrategy, APP_BASE_HREF, CommonModule, HashLocationStrategy, PathLocationStrategy } from '@angular/common';
8import { InjectionToken, Inject, Optional, NgModule } from '@angular/core';
9import { UpgradeModule } from '@angular/upgrade/static';
10
11/**
12 * @fileoverview added by tsickle
13 * Generated from: packages/common/upgrade/src/utils.ts
14 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
15 */
16/**
17 * @license
18 * Copyright Google Inc. All Rights Reserved.
19 *
20 * Use of this source code is governed by an MIT-style license that can be
21 * found in the LICENSE file at https://angular.io/license
22 */
23/**
24 * @param {?} val
25 * @param {?} prefix
26 * @return {?}
27 */
28function stripPrefix(val, prefix) {
29 return val.startsWith(prefix) ? val.substring(prefix.length) : val;
30}
31/**
32 * @param {?} a
33 * @param {?} b
34 * @return {?}
35 */
36function deepEqual(a, b) {
37 if (a === b) {
38 return true;
39 }
40 else if (!a || !b) {
41 return false;
42 }
43 else {
44 try {
45 if ((a.prototype !== b.prototype) || (Array.isArray(a) && Array.isArray(b))) {
46 return false;
47 }
48 return JSON.stringify(a) === JSON.stringify(b);
49 }
50 catch (e) {
51 return false;
52 }
53 }
54}
55/**
56 * @param {?} el
57 * @return {?}
58 */
59function isAnchor(el) {
60 return ((/** @type {?} */ (el))).href !== undefined;
61}
62/**
63 * @param {?} obj
64 * @return {?}
65 */
66function isPromise(obj) {
67 // allow any Promise/A+ compliant thenable.
68 // It's up to the caller to ensure that obj.then conforms to the spec
69 return !!obj && typeof obj.then === 'function';
70}
71
72/**
73 * @fileoverview added by tsickle
74 * Generated from: packages/common/upgrade/src/location_shim.ts
75 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
76 */
77/** @type {?} */
78const PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/;
79/** @type {?} */
80const DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/;
81/** @type {?} */
82const IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
83/** @type {?} */
84const DEFAULT_PORTS = {
85 'http:': 80,
86 'https:': 443,
87 'ftp:': 21
88};
89/**
90 * Location service that provides a drop-in replacement for the $location service
91 * provided in AngularJS.
92 *
93 * @see [Using the Angular Unified Location Service](guide/upgrade#using-the-unified-angular-location-service)
94 *
95 * \@publicApi
96 */
97class $locationShim {
98 /**
99 * @param {?} $injector
100 * @param {?} location
101 * @param {?} platformLocation
102 * @param {?} urlCodec
103 * @param {?} locationStrategy
104 */
105 constructor($injector, location, platformLocation, urlCodec, locationStrategy) {
106 this.location = location;
107 this.platformLocation = platformLocation;
108 this.urlCodec = urlCodec;
109 this.locationStrategy = locationStrategy;
110 this.initalizing = true;
111 this.updateBrowser = false;
112 this.$$absUrl = '';
113 this.$$url = '';
114 this.$$host = '';
115 this.$$replace = false;
116 this.$$path = '';
117 this.$$search = '';
118 this.$$hash = '';
119 this.$$changeListeners = [];
120 this.cachedState = null;
121 this.lastBrowserUrl = '';
122 // This variable should be used *only* inside the cacheState function.
123 this.lastCachedState = null;
124 /** @type {?} */
125 const initialUrl = this.browserUrl();
126 /** @type {?} */
127 let parsedUrl = this.urlCodec.parse(initialUrl);
128 if (typeof parsedUrl === 'string') {
129 throw 'Invalid URL';
130 }
131 this.$$protocol = parsedUrl.protocol;
132 this.$$host = parsedUrl.hostname;
133 this.$$port = parseInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
134 this.$$parseLinkUrl(initialUrl, initialUrl);
135 this.cacheState();
136 this.$$state = this.browserState();
137 if (isPromise($injector)) {
138 $injector.then((/**
139 * @param {?} $i
140 * @return {?}
141 */
142 $i => this.initialize($i)));
143 }
144 else {
145 this.initialize($injector);
146 }
147 }
148 /**
149 * @private
150 * @param {?} $injector
151 * @return {?}
152 */
153 initialize($injector) {
154 /** @type {?} */
155 const $rootScope = $injector.get('$rootScope');
156 /** @type {?} */
157 const $rootElement = $injector.get('$rootElement');
158 $rootElement.on('click', (/**
159 * @param {?} event
160 * @return {?}
161 */
162 (event) => {
163 if (event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 ||
164 event.button === 2) {
165 return;
166 }
167 /** @type {?} */
168 let elm = event.target;
169 // traverse the DOM up to find first A tag
170 while (elm && elm.nodeName.toLowerCase() !== 'a') {
171 // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
172 if (elm === $rootElement[0] || !(elm = elm.parentNode)) {
173 return;
174 }
175 }
176 if (!isAnchor(elm)) {
177 return;
178 }
179 /** @type {?} */
180 const absHref = elm.href;
181 /** @type {?} */
182 const relHref = elm.getAttribute('href');
183 // Ignore when url is started with javascript: or mailto:
184 if (IGNORE_URI_REGEXP.test(absHref)) {
185 return;
186 }
187 if (absHref && !elm.getAttribute('target') && !event.isDefaultPrevented()) {
188 if (this.$$parseLinkUrl(absHref, relHref)) {
189 // We do a preventDefault for all urls that are part of the AngularJS application,
190 // in html5mode and also without, so that we are able to abort navigation without
191 // getting double entries in the location history.
192 event.preventDefault();
193 // update location manually
194 if (this.absUrl() !== this.browserUrl()) {
195 $rootScope.$apply();
196 }
197 }
198 }
199 }));
200 this.location.onUrlChange((/**
201 * @param {?} newUrl
202 * @param {?} newState
203 * @return {?}
204 */
205 (newUrl, newState) => {
206 /** @type {?} */
207 let oldUrl = this.absUrl();
208 /** @type {?} */
209 let oldState = this.$$state;
210 this.$$parse(newUrl);
211 newUrl = this.absUrl();
212 this.$$state = newState;
213 /** @type {?} */
214 const defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, newState, oldState)
215 .defaultPrevented;
216 // if the location was changed by a `$locationChangeStart` handler then stop
217 // processing this location change
218 if (this.absUrl() !== newUrl)
219 return;
220 // If default was prevented, set back to old state. This is the state that was locally
221 // cached in the $location service.
222 if (defaultPrevented) {
223 this.$$parse(oldUrl);
224 this.state(oldState);
225 this.setBrowserUrlWithFallback(oldUrl, false, oldState);
226 this.$$notifyChangeListeners(this.url(), this.$$state, oldUrl, oldState);
227 }
228 else {
229 this.initalizing = false;
230 $rootScope.$broadcast('$locationChangeSuccess', newUrl, oldUrl, newState, oldState);
231 this.resetBrowserUpdate();
232 }
233 if (!$rootScope.$$phase) {
234 $rootScope.$digest();
235 }
236 }));
237 // update browser
238 $rootScope.$watch((/**
239 * @return {?}
240 */
241 () => {
242 if (this.initalizing || this.updateBrowser) {
243 this.updateBrowser = false;
244 /** @type {?} */
245 const oldUrl = this.browserUrl();
246 /** @type {?} */
247 const newUrl = this.absUrl();
248 /** @type {?} */
249 const oldState = this.browserState();
250 /** @type {?} */
251 let currentReplace = this.$$replace;
252 /** @type {?} */
253 const urlOrStateChanged = !this.urlCodec.areEqual(oldUrl, newUrl) || oldState !== this.$$state;
254 // Fire location changes one time to on initialization. This must be done on the
255 // next tick (thus inside $evalAsync()) in order for listeners to be registered
256 // before the event fires. Mimicing behavior from $locationWatch:
257 // https://github.com/angular/angular.js/blob/master/src/ng/location.js#L983
258 if (this.initalizing || urlOrStateChanged) {
259 this.initalizing = false;
260 $rootScope.$evalAsync((/**
261 * @return {?}
262 */
263 () => {
264 // Get the new URL again since it could have changed due to async update
265 /** @type {?} */
266 const newUrl = this.absUrl();
267 /** @type {?} */
268 const defaultPrevented = $rootScope
269 .$broadcast('$locationChangeStart', newUrl, oldUrl, this.$$state, oldState)
270 .defaultPrevented;
271 // if the location was changed by a `$locationChangeStart` handler then stop
272 // processing this location change
273 if (this.absUrl() !== newUrl)
274 return;
275 if (defaultPrevented) {
276 this.$$parse(oldUrl);
277 this.$$state = oldState;
278 }
279 else {
280 // This block doesn't run when initalizing because it's going to perform the update to
281 // the URL which shouldn't be needed when initalizing.
282 if (urlOrStateChanged) {
283 this.setBrowserUrlWithFallback(newUrl, currentReplace, oldState === this.$$state ? null : this.$$state);
284 this.$$replace = false;
285 }
286 $rootScope.$broadcast('$locationChangeSuccess', newUrl, oldUrl, this.$$state, oldState);
287 if (urlOrStateChanged) {
288 this.$$notifyChangeListeners(this.url(), this.$$state, oldUrl, oldState);
289 }
290 }
291 }));
292 }
293 }
294 this.$$replace = false;
295 }));
296 }
297 /**
298 * @private
299 * @return {?}
300 */
301 resetBrowserUpdate() {
302 this.$$replace = false;
303 this.$$state = this.browserState();
304 this.updateBrowser = false;
305 this.lastBrowserUrl = this.browserUrl();
306 }
307 /**
308 * @private
309 * @param {?=} url
310 * @param {?=} replace
311 * @param {?=} state
312 * @return {?}
313 */
314 browserUrl(url, replace, state) {
315 // In modern browsers `history.state` is `null` by default; treating it separately
316 // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
317 // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
318 if (typeof state === 'undefined') {
319 state = null;
320 }
321 // setter
322 if (url) {
323 /** @type {?} */
324 let sameState = this.lastHistoryState === state;
325 // Normalize the inputted URL
326 url = this.urlCodec.parse(url).href;
327 // Don't change anything if previous and current URLs and states match.
328 if (this.lastBrowserUrl === url && sameState) {
329 return this;
330 }
331 this.lastBrowserUrl = url;
332 this.lastHistoryState = state;
333 // Remove server base from URL as the Angular APIs for updating URL require
334 // it to be the path+.
335 url = this.stripBaseUrl(this.getServerBase(), url) || url;
336 // Set the URL
337 if (replace) {
338 this.locationStrategy.replaceState(state, '', url, '');
339 }
340 else {
341 this.locationStrategy.pushState(state, '', url, '');
342 }
343 this.cacheState();
344 return this;
345 // getter
346 }
347 else {
348 return this.platformLocation.href;
349 }
350 }
351 /**
352 * @private
353 * @return {?}
354 */
355 cacheState() {
356 // This should be the only place in $browser where `history.state` is read.
357 this.cachedState = this.platformLocation.getState();
358 if (typeof this.cachedState === 'undefined') {
359 this.cachedState = null;
360 }
361 // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
362 if (deepEqual(this.cachedState, this.lastCachedState)) {
363 this.cachedState = this.lastCachedState;
364 }
365 this.lastCachedState = this.cachedState;
366 this.lastHistoryState = this.cachedState;
367 }
368 /**
369 * This function emulates the $browser.state() function from AngularJS. It will cause
370 * history.state to be cached unless changed with deep equality check.
371 * @private
372 * @return {?}
373 */
374 browserState() { return this.cachedState; }
375 /**
376 * @private
377 * @param {?} base
378 * @param {?} url
379 * @return {?}
380 */
381 stripBaseUrl(base, url) {
382 if (url.startsWith(base)) {
383 return url.substr(base.length);
384 }
385 return undefined;
386 }
387 /**
388 * @private
389 * @return {?}
390 */
391 getServerBase() {
392 const { protocol, hostname, port } = this.platformLocation;
393 /** @type {?} */
394 const baseHref = this.locationStrategy.getBaseHref();
395 /** @type {?} */
396 let url = `${protocol}//${hostname}${port ? ':' + port : ''}${baseHref || '/'}`;
397 return url.endsWith('/') ? url : url + '/';
398 }
399 /**
400 * @private
401 * @param {?} url
402 * @return {?}
403 */
404 parseAppUrl(url) {
405 if (DOUBLE_SLASH_REGEX.test(url)) {
406 throw new Error(`Bad Path - URL cannot start with double slashes: ${url}`);
407 }
408 /** @type {?} */
409 let prefixed = (url.charAt(0) !== '/');
410 if (prefixed) {
411 url = '/' + url;
412 }
413 /** @type {?} */
414 let match = this.urlCodec.parse(url, this.getServerBase());
415 if (typeof match === 'string') {
416 throw new Error(`Bad URL - Cannot parse URL: ${url}`);
417 }
418 /** @type {?} */
419 let path = prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname;
420 this.$$path = this.urlCodec.decodePath(path);
421 this.$$search = this.urlCodec.decodeSearch(match.search);
422 this.$$hash = this.urlCodec.decodeHash(match.hash);
423 // make sure path starts with '/';
424 if (this.$$path && this.$$path.charAt(0) !== '/') {
425 this.$$path = '/' + this.$$path;
426 }
427 }
428 /**
429 * Registers listeners for URL changes. This API is used to catch updates performed by the
430 * AngularJS framework. These changes are a subset of the `$locationChangeStart` and
431 * `$locationChangeSuccess` events which fire when AngularJS updates its internally-referenced
432 * version of the browser URL.
433 *
434 * It's possible for `$locationChange` events to happen, but for the browser URL
435 * (window.location) to remain unchanged. This `onChange` callback will fire only when AngularJS
436 * actually updates the browser URL (window.location).
437 *
438 * @param {?} fn The callback function that is triggered for the listener when the URL changes.
439 * @param {?=} err The callback function that is triggered when an error occurs.
440 * @return {?}
441 */
442 onChange(fn, err = (/**
443 * @param {?} e
444 * @return {?}
445 */
446 (e) => { })) {
447 this.$$changeListeners.push([fn, err]);
448 }
449 /**
450 * \@internal
451 * @param {?=} url
452 * @param {?=} state
453 * @param {?=} oldUrl
454 * @param {?=} oldState
455 * @return {?}
456 */
457 $$notifyChangeListeners(url = '', state, oldUrl = '', oldState) {
458 this.$$changeListeners.forEach((/**
459 * @param {?} __0
460 * @return {?}
461 */
462 ([fn, err]) => {
463 try {
464 fn(url, state, oldUrl, oldState);
465 }
466 catch (e) {
467 err(e);
468 }
469 }));
470 }
471 /**
472 * Parses the provided URL, and sets the current URL to the parsed result.
473 *
474 * @param {?} url The URL string.
475 * @return {?}
476 */
477 $$parse(url) {
478 /** @type {?} */
479 let pathUrl;
480 if (url.startsWith('/')) {
481 pathUrl = url;
482 }
483 else {
484 // Remove protocol & hostname if URL starts with it
485 pathUrl = this.stripBaseUrl(this.getServerBase(), url);
486 }
487 if (typeof pathUrl === 'undefined') {
488 throw new Error(`Invalid url "${url}", missing path prefix "${this.getServerBase()}".`);
489 }
490 this.parseAppUrl(pathUrl);
491 if (!this.$$path) {
492 this.$$path = '/';
493 }
494 this.composeUrls();
495 }
496 /**
497 * Parses the provided URL and its relative URL.
498 *
499 * @param {?} url The full URL string.
500 * @param {?=} relHref A URL string relative to the full URL string.
501 * @return {?}
502 */
503 $$parseLinkUrl(url, relHref) {
504 // When relHref is passed, it should be a hash and is handled separately
505 if (relHref && relHref[0] === '#') {
506 this.hash(relHref.slice(1));
507 return true;
508 }
509 /** @type {?} */
510 let rewrittenUrl;
511 /** @type {?} */
512 let appUrl = this.stripBaseUrl(this.getServerBase(), url);
513 if (typeof appUrl !== 'undefined') {
514 rewrittenUrl = this.getServerBase() + appUrl;
515 }
516 else if (this.getServerBase() === url + '/') {
517 rewrittenUrl = this.getServerBase();
518 }
519 // Set the URL
520 if (rewrittenUrl) {
521 this.$$parse(rewrittenUrl);
522 }
523 return !!rewrittenUrl;
524 }
525 /**
526 * @private
527 * @param {?} url
528 * @param {?} replace
529 * @param {?} state
530 * @return {?}
531 */
532 setBrowserUrlWithFallback(url, replace, state) {
533 /** @type {?} */
534 const oldUrl = this.url();
535 /** @type {?} */
536 const oldState = this.$$state;
537 try {
538 this.browserUrl(url, replace, state);
539 // Make sure $location.state() returns referentially identical (not just deeply equal)
540 // state object; this makes possible quick checking if the state changed in the digest
541 // loop. Checking deep equality would be too expensive.
542 this.$$state = this.browserState();
543 }
544 catch (e) {
545 // Restore old values if pushState fails
546 this.url(oldUrl);
547 this.$$state = oldState;
548 throw e;
549 }
550 }
551 /**
552 * @private
553 * @return {?}
554 */
555 composeUrls() {
556 this.$$url = this.urlCodec.normalize(this.$$path, this.$$search, this.$$hash);
557 this.$$absUrl = this.getServerBase() + this.$$url.substr(1); // remove '/' from front of URL
558 this.updateBrowser = true;
559 }
560 /**
561 * Retrieves the full URL representation with all segments encoded according to
562 * rules specified in
563 * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
564 *
565 *
566 * ```js
567 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
568 * let absUrl = $location.absUrl();
569 * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
570 * ```
571 * @return {?}
572 */
573 absUrl() { return this.$$absUrl; }
574 /**
575 * @param {?=} url
576 * @return {?}
577 */
578 url(url) {
579 if (typeof url === 'string') {
580 if (!url.length) {
581 url = '/';
582 }
583 /** @type {?} */
584 const match = PATH_MATCH.exec(url);
585 if (!match)
586 return this;
587 if (match[1] || url === '')
588 this.path(this.urlCodec.decodePath(match[1]));
589 if (match[2] || match[1] || url === '')
590 this.search(match[3] || '');
591 this.hash(match[5] || '');
592 // Chainable method
593 return this;
594 }
595 return this.$$url;
596 }
597 /**
598 * Retrieves the protocol of the current URL.
599 *
600 * ```js
601 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
602 * let protocol = $location.protocol();
603 * // => "http"
604 * ```
605 * @return {?}
606 */
607 protocol() { return this.$$protocol; }
608 /**
609 * Retrieves the protocol of the current URL.
610 *
611 * In contrast to the non-AngularJS version `location.host` which returns `hostname:port`, this
612 * returns the `hostname` portion only.
613 *
614 *
615 * ```js
616 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
617 * let host = $location.host();
618 * // => "example.com"
619 *
620 * // given URL http://user:password\@example.com:8080/#/some/path?foo=bar&baz=xoxo
621 * host = $location.host();
622 * // => "example.com"
623 * host = location.host;
624 * // => "example.com:8080"
625 * ```
626 * @return {?}
627 */
628 host() { return this.$$host; }
629 /**
630 * Retrieves the port of the current URL.
631 *
632 * ```js
633 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
634 * let port = $location.port();
635 * // => 80
636 * ```
637 * @return {?}
638 */
639 port() { return this.$$port; }
640 /**
641 * @param {?=} path
642 * @return {?}
643 */
644 path(path) {
645 if (typeof path === 'undefined') {
646 return this.$$path;
647 }
648 // null path converts to empty string. Prepend with "/" if needed.
649 path = path !== null ? path.toString() : '';
650 path = path.charAt(0) === '/' ? path : '/' + path;
651 this.$$path = path;
652 this.composeUrls();
653 return this;
654 }
655 /**
656 * @param {?=} search
657 * @param {?=} paramValue
658 * @return {?}
659 */
660 search(search, paramValue) {
661 switch (arguments.length) {
662 case 0:
663 return this.$$search;
664 case 1:
665 if (typeof search === 'string' || typeof search === 'number') {
666 this.$$search = this.urlCodec.decodeSearch(search.toString());
667 }
668 else if (typeof search === 'object' && search !== null) {
669 // Copy the object so it's never mutated
670 search = Object.assign({}, search);
671 // remove object undefined or null properties
672 for (const key in search) {
673 if (search[key] == null)
674 delete search[key];
675 }
676 this.$$search = search;
677 }
678 else {
679 throw new Error('LocationProvider.search(): First argument must be a string or an object.');
680 }
681 break;
682 default:
683 if (typeof search === 'string') {
684 /** @type {?} */
685 const currentSearch = this.search();
686 if (typeof paramValue === 'undefined' || paramValue === null) {
687 delete currentSearch[search];
688 return this.search(currentSearch);
689 }
690 else {
691 currentSearch[search] = paramValue;
692 return this.search(currentSearch);
693 }
694 }
695 }
696 this.composeUrls();
697 return this;
698 }
699 /**
700 * @param {?=} hash
701 * @return {?}
702 */
703 hash(hash) {
704 if (typeof hash === 'undefined') {
705 return this.$$hash;
706 }
707 this.$$hash = hash !== null ? hash.toString() : '';
708 this.composeUrls();
709 return this;
710 }
711 /**
712 * Changes to `$location` during the current `$digest` will replace the current
713 * history record, instead of adding a new one.
714 * @template THIS
715 * @this {THIS}
716 * @return {THIS}
717 */
718 replace() {
719 (/** @type {?} */ (this)).$$replace = true;
720 return (/** @type {?} */ (this));
721 }
722 /**
723 * @param {?=} state
724 * @return {?}
725 */
726 state(state) {
727 if (typeof state === 'undefined') {
728 return this.$$state;
729 }
730 this.$$state = state;
731 return this;
732 }
733}
734if (false) {
735 /**
736 * @type {?}
737 * @private
738 */
739 $locationShim.prototype.initalizing;
740 /**
741 * @type {?}
742 * @private
743 */
744 $locationShim.prototype.updateBrowser;
745 /**
746 * @type {?}
747 * @private
748 */
749 $locationShim.prototype.$$absUrl;
750 /**
751 * @type {?}
752 * @private
753 */
754 $locationShim.prototype.$$url;
755 /**
756 * @type {?}
757 * @private
758 */
759 $locationShim.prototype.$$protocol;
760 /**
761 * @type {?}
762 * @private
763 */
764 $locationShim.prototype.$$host;
765 /**
766 * @type {?}
767 * @private
768 */
769 $locationShim.prototype.$$port;
770 /**
771 * @type {?}
772 * @private
773 */
774 $locationShim.prototype.$$replace;
775 /**
776 * @type {?}
777 * @private
778 */
779 $locationShim.prototype.$$path;
780 /**
781 * @type {?}
782 * @private
783 */
784 $locationShim.prototype.$$search;
785 /**
786 * @type {?}
787 * @private
788 */
789 $locationShim.prototype.$$hash;
790 /**
791 * @type {?}
792 * @private
793 */
794 $locationShim.prototype.$$state;
795 /**
796 * @type {?}
797 * @private
798 */
799 $locationShim.prototype.$$changeListeners;
800 /**
801 * @type {?}
802 * @private
803 */
804 $locationShim.prototype.cachedState;
805 /**
806 * @type {?}
807 * @private
808 */
809 $locationShim.prototype.lastHistoryState;
810 /**
811 * @type {?}
812 * @private
813 */
814 $locationShim.prototype.lastBrowserUrl;
815 /**
816 * @type {?}
817 * @private
818 */
819 $locationShim.prototype.lastCachedState;
820 /**
821 * @type {?}
822 * @private
823 */
824 $locationShim.prototype.location;
825 /**
826 * @type {?}
827 * @private
828 */
829 $locationShim.prototype.platformLocation;
830 /**
831 * @type {?}
832 * @private
833 */
834 $locationShim.prototype.urlCodec;
835 /**
836 * @type {?}
837 * @private
838 */
839 $locationShim.prototype.locationStrategy;
840}
841/**
842 * The factory function used to create an instance of the `$locationShim` in Angular,
843 * and provides an API-compatiable `$locationProvider` for AngularJS.
844 *
845 * \@publicApi
846 */
847class $locationShimProvider {
848 /**
849 * @param {?} ngUpgrade
850 * @param {?} location
851 * @param {?} platformLocation
852 * @param {?} urlCodec
853 * @param {?} locationStrategy
854 */
855 constructor(ngUpgrade, location, platformLocation, urlCodec, locationStrategy) {
856 this.ngUpgrade = ngUpgrade;
857 this.location = location;
858 this.platformLocation = platformLocation;
859 this.urlCodec = urlCodec;
860 this.locationStrategy = locationStrategy;
861 }
862 /**
863 * Factory method that returns an instance of the $locationShim
864 * @return {?}
865 */
866 $get() {
867 return new $locationShim(this.ngUpgrade.$injector, this.location, this.platformLocation, this.urlCodec, this.locationStrategy);
868 }
869 /**
870 * Stub method used to keep API compatible with AngularJS. This setting is configured through
871 * the LocationUpgradeModule's `config` method in your Angular app.
872 * @param {?=} prefix
873 * @return {?}
874 */
875 hashPrefix(prefix) {
876 throw new Error('Configure LocationUpgrade through LocationUpgradeModule.config method.');
877 }
878 /**
879 * Stub method used to keep API compatible with AngularJS. This setting is configured through
880 * the LocationUpgradeModule's `config` method in your Angular app.
881 * @param {?=} mode
882 * @return {?}
883 */
884 html5Mode(mode) {
885 throw new Error('Configure LocationUpgrade through LocationUpgradeModule.config method.');
886 }
887}
888if (false) {
889 /**
890 * @type {?}
891 * @private
892 */
893 $locationShimProvider.prototype.ngUpgrade;
894 /**
895 * @type {?}
896 * @private
897 */
898 $locationShimProvider.prototype.location;
899 /**
900 * @type {?}
901 * @private
902 */
903 $locationShimProvider.prototype.platformLocation;
904 /**
905 * @type {?}
906 * @private
907 */
908 $locationShimProvider.prototype.urlCodec;
909 /**
910 * @type {?}
911 * @private
912 */
913 $locationShimProvider.prototype.locationStrategy;
914}
915
916/**
917 * @fileoverview added by tsickle
918 * Generated from: packages/common/upgrade/src/params.ts
919 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
920 */
921/**
922 * @license
923 * Copyright Google Inc. All Rights Reserved.
924 *
925 * Use of this source code is governed by an MIT-style license that can be
926 * found in the LICENSE file at https://angular.io/license
927 */
928/**
929 * A codec for encoding and decoding URL parts.
930 *
931 * \@publicApi
932 *
933 * @abstract
934 */
935class UrlCodec {
936}
937if (false) {
938 /**
939 * Encodes the path from the provided string
940 *
941 * @abstract
942 * @param {?} path The path string
943 * @return {?}
944 */
945 UrlCodec.prototype.encodePath = function (path) { };
946 /**
947 * Decodes the path from the provided string
948 *
949 * @abstract
950 * @param {?} path The path string
951 * @return {?}
952 */
953 UrlCodec.prototype.decodePath = function (path) { };
954 /**
955 * Encodes the search string from the provided string or object
956 *
957 * @abstract
958 * @param {?} search
959 * @return {?}
960 */
961 UrlCodec.prototype.encodeSearch = function (search) { };
962 /**
963 * Decodes the search objects from the provided string
964 *
965 * @abstract
966 * @param {?} search
967 * @return {?}
968 */
969 UrlCodec.prototype.decodeSearch = function (search) { };
970 /**
971 * Encodes the hash from the provided string
972 *
973 * @abstract
974 * @param {?} hash
975 * @return {?}
976 */
977 UrlCodec.prototype.encodeHash = function (hash) { };
978 /**
979 * Decodes the hash from the provided string
980 *
981 * @abstract
982 * @param {?} hash
983 * @return {?}
984 */
985 UrlCodec.prototype.decodeHash = function (hash) { };
986 /**
987 * Normalizes the URL from the provided string
988 *
989 * @abstract
990 * @param {?} href
991 * @return {?}
992 */
993 UrlCodec.prototype.normalize = function (href) { };
994 /**
995 * Normalizes the URL from the provided string, search, hash, and base URL parameters
996 *
997 * @abstract
998 * @param {?} path The URL path
999 * @param {?} search The search object
1000 * @param {?} hash The has string
1001 * @param {?=} baseUrl The base URL for the URL
1002 * @return {?}
1003 */
1004 UrlCodec.prototype.normalize = function (path, search, hash, baseUrl) { };
1005 /**
1006 * Checks whether the two strings are equal
1007 * @abstract
1008 * @param {?} valA First string for comparison
1009 * @param {?} valB Second string for comparison
1010 * @return {?}
1011 */
1012 UrlCodec.prototype.areEqual = function (valA, valB) { };
1013 /**
1014 * Parses the URL string based on the base URL
1015 *
1016 * @abstract
1017 * @param {?} url The full URL string
1018 * @param {?=} base The base for the URL
1019 * @return {?}
1020 */
1021 UrlCodec.prototype.parse = function (url, base) { };
1022}
1023/**
1024 * A `UrlCodec` that uses logic from AngularJS to serialize and parse URLs
1025 * and URL parameters.
1026 *
1027 * \@publicApi
1028 */
1029class AngularJSUrlCodec {
1030 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L15
1031 /**
1032 * @param {?} path
1033 * @return {?}
1034 */
1035 encodePath(path) {
1036 /** @type {?} */
1037 const segments = path.split('/');
1038 /** @type {?} */
1039 let i = segments.length;
1040 while (i--) {
1041 // decode forward slashes to prevent them from being double encoded
1042 segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, '/'));
1043 }
1044 path = segments.join('/');
1045 return _stripIndexHtml((path && path[0] !== '/' && '/' || '') + path);
1046 }
1047 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L42
1048 /**
1049 * @param {?} search
1050 * @return {?}
1051 */
1052 encodeSearch(search) {
1053 if (typeof search === 'string') {
1054 search = parseKeyValue(search);
1055 }
1056 search = toKeyValue(search);
1057 return search ? '?' + search : '';
1058 }
1059 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L44
1060 /**
1061 * @param {?} hash
1062 * @return {?}
1063 */
1064 encodeHash(hash) {
1065 hash = encodeUriSegment(hash);
1066 return hash ? '#' + hash : '';
1067 }
1068 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L27
1069 /**
1070 * @param {?} path
1071 * @param {?=} html5Mode
1072 * @return {?}
1073 */
1074 decodePath(path, html5Mode = true) {
1075 /** @type {?} */
1076 const segments = path.split('/');
1077 /** @type {?} */
1078 let i = segments.length;
1079 while (i--) {
1080 segments[i] = decodeURIComponent(segments[i]);
1081 if (html5Mode) {
1082 // encode forward slashes to prevent them from being mistaken for path separators
1083 segments[i] = segments[i].replace(/\//g, '%2F');
1084 }
1085 }
1086 return segments.join('/');
1087 }
1088 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L72
1089 /**
1090 * @param {?} search
1091 * @return {?}
1092 */
1093 decodeSearch(search) { return parseKeyValue(search); }
1094 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L73
1095 /**
1096 * @param {?} hash
1097 * @return {?}
1098 */
1099 decodeHash(hash) {
1100 hash = decodeURIComponent(hash);
1101 return hash[0] === '#' ? hash.substring(1) : hash;
1102 }
1103 /**
1104 * @param {?} pathOrHref
1105 * @param {?=} search
1106 * @param {?=} hash
1107 * @param {?=} baseUrl
1108 * @return {?}
1109 */
1110 normalize(pathOrHref, search, hash, baseUrl) {
1111 if (arguments.length === 1) {
1112 /** @type {?} */
1113 const parsed = this.parse(pathOrHref, baseUrl);
1114 if (typeof parsed === 'string') {
1115 return parsed;
1116 }
1117 /** @type {?} */
1118 const serverUrl = `${parsed.protocol}://${parsed.hostname}${parsed.port ? ':' + parsed.port : ''}`;
1119 return this.normalize(this.decodePath(parsed.pathname), this.decodeSearch(parsed.search), this.decodeHash(parsed.hash), serverUrl);
1120 }
1121 else {
1122 /** @type {?} */
1123 const encPath = this.encodePath(pathOrHref);
1124 /** @type {?} */
1125 const encSearch = search && this.encodeSearch(search) || '';
1126 /** @type {?} */
1127 const encHash = hash && this.encodeHash(hash) || '';
1128 /** @type {?} */
1129 let joinedPath = (baseUrl || '') + encPath;
1130 if (!joinedPath.length || joinedPath[0] !== '/') {
1131 joinedPath = '/' + joinedPath;
1132 }
1133 return joinedPath + encSearch + encHash;
1134 }
1135 }
1136 /**
1137 * @param {?} valA
1138 * @param {?} valB
1139 * @return {?}
1140 */
1141 areEqual(valA, valB) { return this.normalize(valA) === this.normalize(valB); }
1142 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/urlUtils.js#L60
1143 /**
1144 * @param {?} url
1145 * @param {?=} base
1146 * @return {?}
1147 */
1148 parse(url, base) {
1149 try {
1150 // Safari 12 throws an error when the URL constructor is called with an undefined base.
1151 /** @type {?} */
1152 const parsed = !base ? new URL(url) : new URL(url, base);
1153 return {
1154 href: parsed.href,
1155 protocol: parsed.protocol ? parsed.protocol.replace(/:$/, '') : '',
1156 host: parsed.host,
1157 search: parsed.search ? parsed.search.replace(/^\?/, '') : '',
1158 hash: parsed.hash ? parsed.hash.replace(/^#/, '') : '',
1159 hostname: parsed.hostname,
1160 port: parsed.port,
1161 pathname: (parsed.pathname.charAt(0) === '/') ? parsed.pathname : '/' + parsed.pathname
1162 };
1163 }
1164 catch (e) {
1165 throw new Error(`Invalid URL (${url}) with base (${base})`);
1166 }
1167 }
1168}
1169/**
1170 * @param {?} url
1171 * @return {?}
1172 */
1173function _stripIndexHtml(url) {
1174 return url.replace(/\/index.html$/, '');
1175}
1176/**
1177 * Tries to decode the URI component without throwing an exception.
1178 *
1179 * @param {?} value
1180 * @return {?} the decoded URI if it can be decoded or else `undefined`.
1181 */
1182function tryDecodeURIComponent(value) {
1183 try {
1184 return decodeURIComponent(value);
1185 }
1186 catch (e) {
1187 // Ignore any invalid uri component.
1188 return undefined;
1189 }
1190}
1191/**
1192 * Parses an escaped url query string into key-value pairs. Logic taken from
1193 * https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1382
1194 * @param {?} keyValue
1195 * @return {?}
1196 */
1197function parseKeyValue(keyValue) {
1198 /** @type {?} */
1199 const obj = {};
1200 (keyValue || '').split('&').forEach((/**
1201 * @param {?} keyValue
1202 * @return {?}
1203 */
1204 (keyValue) => {
1205 /** @type {?} */
1206 let splitPoint;
1207 /** @type {?} */
1208 let key;
1209 /** @type {?} */
1210 let val;
1211 if (keyValue) {
1212 key = keyValue = keyValue.replace(/\+/g, '%20');
1213 splitPoint = keyValue.indexOf('=');
1214 if (splitPoint !== -1) {
1215 key = keyValue.substring(0, splitPoint);
1216 val = keyValue.substring(splitPoint + 1);
1217 }
1218 key = tryDecodeURIComponent(key);
1219 if (typeof key !== 'undefined') {
1220 val = typeof val !== 'undefined' ? tryDecodeURIComponent(val) : true;
1221 if (!obj.hasOwnProperty(key)) {
1222 obj[key] = val;
1223 }
1224 else if (Array.isArray(obj[key])) {
1225 ((/** @type {?} */ (obj[key]))).push(val);
1226 }
1227 else {
1228 obj[key] = [obj[key], val];
1229 }
1230 }
1231 }
1232 }));
1233 return obj;
1234}
1235/**
1236 * Serializes into key-value pairs. Logic taken from
1237 * https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1409
1238 * @param {?} obj
1239 * @return {?}
1240 */
1241function toKeyValue(obj) {
1242 /** @type {?} */
1243 const parts = [];
1244 for (const key in obj) {
1245 /** @type {?} */
1246 let value = obj[key];
1247 if (Array.isArray(value)) {
1248 value.forEach((/**
1249 * @param {?} arrayValue
1250 * @return {?}
1251 */
1252 (arrayValue) => {
1253 parts.push(encodeUriQuery(key, true) +
1254 (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1255 }));
1256 }
1257 else {
1258 parts.push(encodeUriQuery(key, true) +
1259 (value === true ? '' : '=' + encodeUriQuery((/** @type {?} */ (value)), true)));
1260 }
1261 }
1262 return parts.length ? parts.join('&') : '';
1263}
1264/**
1265 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1266 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1267 * segments:
1268 * segment = *pchar
1269 * pchar = unreserved / pct-encoded / sub-delims / ":" / "\@"
1270 * pct-encoded = "%" HEXDIG HEXDIG
1271 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1272 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1273 * / "*" / "+" / "," / ";" / "="
1274 *
1275 * Logic from https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1437
1276 * @param {?} val
1277 * @return {?}
1278 */
1279function encodeUriSegment(val) {
1280 return encodeUriQuery(val, true)
1281 .replace(/%26/gi, '&')
1282 .replace(/%3D/gi, '=')
1283 .replace(/%2B/gi, '+');
1284}
1285/**
1286 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1287 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1288 * encoded per http://tools.ietf.org/html/rfc3986:
1289 * query = *( pchar / "/" / "?" )
1290 * pchar = unreserved / pct-encoded / sub-delims / ":" / "\@"
1291 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1292 * pct-encoded = "%" HEXDIG HEXDIG
1293 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1294 * / "*" / "+" / "," / ";" / "="
1295 *
1296 * Logic from https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1456
1297 * @param {?} val
1298 * @param {?=} pctEncodeSpaces
1299 * @return {?}
1300 */
1301function encodeUriQuery(val, pctEncodeSpaces = false) {
1302 return encodeURIComponent(val)
1303 .replace(/%40/gi, '@')
1304 .replace(/%3A/gi, ':')
1305 .replace(/%24/g, '$')
1306 .replace(/%2C/gi, ',')
1307 .replace(/%3B/gi, ';')
1308 .replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1309}
1310
1311/**
1312 * @fileoverview added by tsickle
1313 * Generated from: packages/common/upgrade/src/location_upgrade_module.ts
1314 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1315 */
1316/**
1317 * Configuration options for LocationUpgrade.
1318 *
1319 * \@publicApi
1320 * @record
1321 */
1322function LocationUpgradeConfig() { }
1323if (false) {
1324 /**
1325 * Configures whether the location upgrade module should use the `HashLocationStrategy`
1326 * or the `PathLocationStrategy`
1327 * @type {?|undefined}
1328 */
1329 LocationUpgradeConfig.prototype.useHash;
1330 /**
1331 * Configures the hash prefix used in the URL when using the `HashLocationStrategy`
1332 * @type {?|undefined}
1333 */
1334 LocationUpgradeConfig.prototype.hashPrefix;
1335 /**
1336 * Configures the URL codec for encoding and decoding URLs. Default is the `AngularJSCodec`
1337 * @type {?|undefined}
1338 */
1339 LocationUpgradeConfig.prototype.urlCodec;
1340 /**
1341 * Configures the base href when used in server-side rendered applications
1342 * @type {?|undefined}
1343 */
1344 LocationUpgradeConfig.prototype.serverBaseHref;
1345 /**
1346 * Configures the base href when used in client-side rendered applications
1347 * @type {?|undefined}
1348 */
1349 LocationUpgradeConfig.prototype.appBaseHref;
1350}
1351/**
1352 * A provider token used to configure the location upgrade module.
1353 *
1354 * \@publicApi
1355 * @type {?}
1356 */
1357const LOCATION_UPGRADE_CONFIGURATION = new InjectionToken('LOCATION_UPGRADE_CONFIGURATION');
1358/** @type {?} */
1359const APP_BASE_HREF_RESOLVED = new InjectionToken('APP_BASE_HREF_RESOLVED');
1360/**
1361 * `NgModule` used for providing and configuring Angular's Unified Location Service for upgrading.
1362 *
1363 * @see [Using the Unified Angular Location Service](guide/upgrade#using-the-unified-angular-location-service)
1364 *
1365 * \@publicApi
1366 */
1367class LocationUpgradeModule {
1368 /**
1369 * @param {?=} config
1370 * @return {?}
1371 */
1372 static config(config) {
1373 return {
1374 ngModule: LocationUpgradeModule,
1375 providers: [
1376 Location,
1377 {
1378 provide: $locationShim,
1379 useFactory: provide$location,
1380 deps: [UpgradeModule, Location, PlatformLocation, UrlCodec, LocationStrategy]
1381 },
1382 { provide: LOCATION_UPGRADE_CONFIGURATION, useValue: config ? config : {} },
1383 { provide: UrlCodec, useFactory: provideUrlCodec, deps: [LOCATION_UPGRADE_CONFIGURATION] },
1384 {
1385 provide: APP_BASE_HREF_RESOLVED,
1386 useFactory: provideAppBaseHref,
1387 deps: [LOCATION_UPGRADE_CONFIGURATION, [new Inject(APP_BASE_HREF), new Optional()]]
1388 },
1389 {
1390 provide: LocationStrategy,
1391 useFactory: provideLocationStrategy,
1392 deps: [
1393 PlatformLocation,
1394 APP_BASE_HREF_RESOLVED,
1395 LOCATION_UPGRADE_CONFIGURATION,
1396 ]
1397 },
1398 ],
1399 };
1400 }
1401}
1402LocationUpgradeModule.decorators = [
1403 { type: NgModule, args: [{ imports: [CommonModule] },] }
1404];
1405/**
1406 * @param {?} config
1407 * @param {?=} appBaseHref
1408 * @return {?}
1409 */
1410function provideAppBaseHref(config, appBaseHref) {
1411 if (config && config.appBaseHref != null) {
1412 return config.appBaseHref;
1413 }
1414 else if (appBaseHref != null) {
1415 return appBaseHref;
1416 }
1417 return '';
1418}
1419/**
1420 * @param {?} config
1421 * @return {?}
1422 */
1423function provideUrlCodec(config) {
1424 /** @type {?} */
1425 const codec = config && config.urlCodec || AngularJSUrlCodec;
1426 return new ((/** @type {?} */ (codec)))();
1427}
1428/**
1429 * @param {?} platformLocation
1430 * @param {?} baseHref
1431 * @param {?=} options
1432 * @return {?}
1433 */
1434function provideLocationStrategy(platformLocation, baseHref, options = {}) {
1435 return options.useHash ? new HashLocationStrategy(platformLocation, baseHref) :
1436 new PathLocationStrategy(platformLocation, baseHref);
1437}
1438/**
1439 * @param {?} ngUpgrade
1440 * @param {?} location
1441 * @param {?} platformLocation
1442 * @param {?} urlCodec
1443 * @param {?} locationStrategy
1444 * @return {?}
1445 */
1446function provide$location(ngUpgrade, location, platformLocation, urlCodec, locationStrategy) {
1447 /** @type {?} */
1448 const $locationProvider = new $locationShimProvider(ngUpgrade, location, platformLocation, urlCodec, locationStrategy);
1449 return $locationProvider.$get();
1450}
1451
1452/**
1453 * @fileoverview added by tsickle
1454 * Generated from: packages/common/upgrade/src/index.ts
1455 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1456 */
1457
1458/**
1459 * @fileoverview added by tsickle
1460 * Generated from: packages/common/upgrade/public_api.ts
1461 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1462 */
1463
1464/**
1465 * @fileoverview added by tsickle
1466 * Generated from: packages/common/upgrade/index.ts
1467 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1468 */
1469
1470/**
1471 * Generated bundle index. Do not edit.
1472 */
1473
1474export { $locationShim, $locationShimProvider, AngularJSUrlCodec, LOCATION_UPGRADE_CONFIGURATION, LocationUpgradeModule, UrlCodec, provideAppBaseHref as ɵangular_packages_common_upgrade_upgrade_a, provideUrlCodec as ɵangular_packages_common_upgrade_upgrade_b, provideLocationStrategy as ɵangular_packages_common_upgrade_upgrade_c, provide$location as ɵangular_packages_common_upgrade_upgrade_d };
1475//# sourceMappingURL=upgrade.js.map