UNPKG

38 kBJavaScriptView Raw
1/**
2 * @license Angular v9.0.4
3 * (c) 2010-2020 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { __read, __assign, __decorate } from 'tslib';
8import { Location, PlatformLocation, LocationStrategy, APP_BASE_HREF, CommonModule, HashLocationStrategy, PathLocationStrategy } from '@angular/common';
9import { InjectionToken, Inject, Optional, NgModule } from '@angular/core';
10import { UpgradeModule } from '@angular/upgrade/static';
11
12/**
13 * @license
14 * Copyright Google Inc. All Rights Reserved.
15 *
16 * Use of this source code is governed by an MIT-style license that can be
17 * found in the LICENSE file at https://angular.io/license
18 */
19function stripPrefix(val, prefix) {
20 return val.startsWith(prefix) ? val.substring(prefix.length) : val;
21}
22function deepEqual(a, b) {
23 if (a === b) {
24 return true;
25 }
26 else if (!a || !b) {
27 return false;
28 }
29 else {
30 try {
31 if ((a.prototype !== b.prototype) || (Array.isArray(a) && Array.isArray(b))) {
32 return false;
33 }
34 return JSON.stringify(a) === JSON.stringify(b);
35 }
36 catch (e) {
37 return false;
38 }
39 }
40}
41function isAnchor(el) {
42 return el.href !== undefined;
43}
44function isPromise(obj) {
45 // allow any Promise/A+ compliant thenable.
46 // It's up to the caller to ensure that obj.then conforms to the spec
47 return !!obj && typeof obj.then === 'function';
48}
49
50/**
51 * @license
52 * Copyright Google Inc. All Rights Reserved.
53 *
54 * Use of this source code is governed by an MIT-style license that can be
55 * found in the LICENSE file at https://angular.io/license
56 */
57var PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/;
58var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/;
59var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
60var DEFAULT_PORTS = {
61 'http:': 80,
62 'https:': 443,
63 'ftp:': 21
64};
65/**
66 * Location service that provides a drop-in replacement for the $location service
67 * provided in AngularJS.
68 *
69 * @see [Using the Angular Unified Location Service](guide/upgrade#using-the-unified-angular-location-service)
70 *
71 * @publicApi
72 */
73var $locationShim = /** @class */ (function () {
74 function $locationShim($injector, location, platformLocation, urlCodec, locationStrategy) {
75 var _this = this;
76 this.location = location;
77 this.platformLocation = platformLocation;
78 this.urlCodec = urlCodec;
79 this.locationStrategy = locationStrategy;
80 this.initalizing = true;
81 this.updateBrowser = false;
82 this.$$absUrl = '';
83 this.$$url = '';
84 this.$$host = '';
85 this.$$replace = false;
86 this.$$path = '';
87 this.$$search = '';
88 this.$$hash = '';
89 this.$$changeListeners = [];
90 this.cachedState = null;
91 this.lastBrowserUrl = '';
92 // This variable should be used *only* inside the cacheState function.
93 this.lastCachedState = null;
94 var initialUrl = this.browserUrl();
95 var parsedUrl = this.urlCodec.parse(initialUrl);
96 if (typeof parsedUrl === 'string') {
97 throw 'Invalid URL';
98 }
99 this.$$protocol = parsedUrl.protocol;
100 this.$$host = parsedUrl.hostname;
101 this.$$port = parseInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
102 this.$$parseLinkUrl(initialUrl, initialUrl);
103 this.cacheState();
104 this.$$state = this.browserState();
105 if (isPromise($injector)) {
106 $injector.then(function ($i) { return _this.initialize($i); });
107 }
108 else {
109 this.initialize($injector);
110 }
111 }
112 $locationShim.prototype.initialize = function ($injector) {
113 var _this = this;
114 var $rootScope = $injector.get('$rootScope');
115 var $rootElement = $injector.get('$rootElement');
116 $rootElement.on('click', function (event) {
117 if (event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 ||
118 event.button === 2) {
119 return;
120 }
121 var elm = event.target;
122 // traverse the DOM up to find first A tag
123 while (elm && elm.nodeName.toLowerCase() !== 'a') {
124 // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
125 if (elm === $rootElement[0] || !(elm = elm.parentNode)) {
126 return;
127 }
128 }
129 if (!isAnchor(elm)) {
130 return;
131 }
132 var absHref = elm.href;
133 var relHref = elm.getAttribute('href');
134 // Ignore when url is started with javascript: or mailto:
135 if (IGNORE_URI_REGEXP.test(absHref)) {
136 return;
137 }
138 if (absHref && !elm.getAttribute('target') && !event.isDefaultPrevented()) {
139 if (_this.$$parseLinkUrl(absHref, relHref)) {
140 // We do a preventDefault for all urls that are part of the AngularJS application,
141 // in html5mode and also without, so that we are able to abort navigation without
142 // getting double entries in the location history.
143 event.preventDefault();
144 // update location manually
145 if (_this.absUrl() !== _this.browserUrl()) {
146 $rootScope.$apply();
147 }
148 }
149 }
150 });
151 this.location.onUrlChange(function (newUrl, newState) {
152 var oldUrl = _this.absUrl();
153 var oldState = _this.$$state;
154 _this.$$parse(newUrl);
155 newUrl = _this.absUrl();
156 _this.$$state = newState;
157 var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, newState, oldState)
158 .defaultPrevented;
159 // if the location was changed by a `$locationChangeStart` handler then stop
160 // processing this location change
161 if (_this.absUrl() !== newUrl)
162 return;
163 // If default was prevented, set back to old state. This is the state that was locally
164 // cached in the $location service.
165 if (defaultPrevented) {
166 _this.$$parse(oldUrl);
167 _this.state(oldState);
168 _this.setBrowserUrlWithFallback(oldUrl, false, oldState);
169 _this.$$notifyChangeListeners(_this.url(), _this.$$state, oldUrl, oldState);
170 }
171 else {
172 _this.initalizing = false;
173 $rootScope.$broadcast('$locationChangeSuccess', newUrl, oldUrl, newState, oldState);
174 _this.resetBrowserUpdate();
175 }
176 if (!$rootScope.$$phase) {
177 $rootScope.$digest();
178 }
179 });
180 // update browser
181 $rootScope.$watch(function () {
182 if (_this.initalizing || _this.updateBrowser) {
183 _this.updateBrowser = false;
184 var oldUrl_1 = _this.browserUrl();
185 var newUrl = _this.absUrl();
186 var oldState_1 = _this.browserState();
187 var currentReplace_1 = _this.$$replace;
188 var urlOrStateChanged_1 = !_this.urlCodec.areEqual(oldUrl_1, newUrl) || oldState_1 !== _this.$$state;
189 // Fire location changes one time to on initialization. This must be done on the
190 // next tick (thus inside $evalAsync()) in order for listeners to be registered
191 // before the event fires. Mimicing behavior from $locationWatch:
192 // https://github.com/angular/angular.js/blob/master/src/ng/location.js#L983
193 if (_this.initalizing || urlOrStateChanged_1) {
194 _this.initalizing = false;
195 $rootScope.$evalAsync(function () {
196 // Get the new URL again since it could have changed due to async update
197 var newUrl = _this.absUrl();
198 var defaultPrevented = $rootScope
199 .$broadcast('$locationChangeStart', newUrl, oldUrl_1, _this.$$state, oldState_1)
200 .defaultPrevented;
201 // if the location was changed by a `$locationChangeStart` handler then stop
202 // processing this location change
203 if (_this.absUrl() !== newUrl)
204 return;
205 if (defaultPrevented) {
206 _this.$$parse(oldUrl_1);
207 _this.$$state = oldState_1;
208 }
209 else {
210 // This block doesn't run when initalizing because it's going to perform the update to
211 // the URL which shouldn't be needed when initalizing.
212 if (urlOrStateChanged_1) {
213 _this.setBrowserUrlWithFallback(newUrl, currentReplace_1, oldState_1 === _this.$$state ? null : _this.$$state);
214 _this.$$replace = false;
215 }
216 $rootScope.$broadcast('$locationChangeSuccess', newUrl, oldUrl_1, _this.$$state, oldState_1);
217 if (urlOrStateChanged_1) {
218 _this.$$notifyChangeListeners(_this.url(), _this.$$state, oldUrl_1, oldState_1);
219 }
220 }
221 });
222 }
223 }
224 _this.$$replace = false;
225 });
226 };
227 $locationShim.prototype.resetBrowserUpdate = function () {
228 this.$$replace = false;
229 this.$$state = this.browserState();
230 this.updateBrowser = false;
231 this.lastBrowserUrl = this.browserUrl();
232 };
233 $locationShim.prototype.browserUrl = function (url, replace, state) {
234 // In modern browsers `history.state` is `null` by default; treating it separately
235 // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
236 // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
237 if (typeof state === 'undefined') {
238 state = null;
239 }
240 // setter
241 if (url) {
242 var sameState = this.lastHistoryState === state;
243 // Normalize the inputted URL
244 url = this.urlCodec.parse(url).href;
245 // Don't change anything if previous and current URLs and states match.
246 if (this.lastBrowserUrl === url && sameState) {
247 return this;
248 }
249 this.lastBrowserUrl = url;
250 this.lastHistoryState = state;
251 // Remove server base from URL as the Angular APIs for updating URL require
252 // it to be the path+.
253 url = this.stripBaseUrl(this.getServerBase(), url) || url;
254 // Set the URL
255 if (replace) {
256 this.locationStrategy.replaceState(state, '', url, '');
257 }
258 else {
259 this.locationStrategy.pushState(state, '', url, '');
260 }
261 this.cacheState();
262 return this;
263 // getter
264 }
265 else {
266 return this.platformLocation.href;
267 }
268 };
269 $locationShim.prototype.cacheState = function () {
270 // This should be the only place in $browser where `history.state` is read.
271 this.cachedState = this.platformLocation.getState();
272 if (typeof this.cachedState === 'undefined') {
273 this.cachedState = null;
274 }
275 // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
276 if (deepEqual(this.cachedState, this.lastCachedState)) {
277 this.cachedState = this.lastCachedState;
278 }
279 this.lastCachedState = this.cachedState;
280 this.lastHistoryState = this.cachedState;
281 };
282 /**
283 * This function emulates the $browser.state() function from AngularJS. It will cause
284 * history.state to be cached unless changed with deep equality check.
285 */
286 $locationShim.prototype.browserState = function () { return this.cachedState; };
287 $locationShim.prototype.stripBaseUrl = function (base, url) {
288 if (url.startsWith(base)) {
289 return url.substr(base.length);
290 }
291 return undefined;
292 };
293 $locationShim.prototype.getServerBase = function () {
294 var _a = this.platformLocation, protocol = _a.protocol, hostname = _a.hostname, port = _a.port;
295 var baseHref = this.locationStrategy.getBaseHref();
296 var url = protocol + "//" + hostname + (port ? ':' + port : '') + (baseHref || '/');
297 return url.endsWith('/') ? url : url + '/';
298 };
299 $locationShim.prototype.parseAppUrl = function (url) {
300 if (DOUBLE_SLASH_REGEX.test(url)) {
301 throw new Error("Bad Path - URL cannot start with double slashes: " + url);
302 }
303 var prefixed = (url.charAt(0) !== '/');
304 if (prefixed) {
305 url = '/' + url;
306 }
307 var match = this.urlCodec.parse(url, this.getServerBase());
308 if (typeof match === 'string') {
309 throw new Error("Bad URL - Cannot parse URL: " + url);
310 }
311 var path = prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname;
312 this.$$path = this.urlCodec.decodePath(path);
313 this.$$search = this.urlCodec.decodeSearch(match.search);
314 this.$$hash = this.urlCodec.decodeHash(match.hash);
315 // make sure path starts with '/';
316 if (this.$$path && this.$$path.charAt(0) !== '/') {
317 this.$$path = '/' + this.$$path;
318 }
319 };
320 /**
321 * Registers listeners for URL changes. This API is used to catch updates performed by the
322 * AngularJS framework. These changes are a subset of the `$locationChangeStart` and
323 * `$locationChangeSuccess` events which fire when AngularJS updates its internally-referenced
324 * version of the browser URL.
325 *
326 * It's possible for `$locationChange` events to happen, but for the browser URL
327 * (window.location) to remain unchanged. This `onChange` callback will fire only when AngularJS
328 * actually updates the browser URL (window.location).
329 *
330 * @param fn The callback function that is triggered for the listener when the URL changes.
331 * @param err The callback function that is triggered when an error occurs.
332 */
333 $locationShim.prototype.onChange = function (fn, err) {
334 if (err === void 0) { err = function (e) { }; }
335 this.$$changeListeners.push([fn, err]);
336 };
337 /** @internal */
338 $locationShim.prototype.$$notifyChangeListeners = function (url, state, oldUrl, oldState) {
339 if (url === void 0) { url = ''; }
340 if (oldUrl === void 0) { oldUrl = ''; }
341 this.$$changeListeners.forEach(function (_a) {
342 var _b = __read(_a, 2), fn = _b[0], err = _b[1];
343 try {
344 fn(url, state, oldUrl, oldState);
345 }
346 catch (e) {
347 err(e);
348 }
349 });
350 };
351 /**
352 * Parses the provided URL, and sets the current URL to the parsed result.
353 *
354 * @param url The URL string.
355 */
356 $locationShim.prototype.$$parse = function (url) {
357 var pathUrl;
358 if (url.startsWith('/')) {
359 pathUrl = url;
360 }
361 else {
362 // Remove protocol & hostname if URL starts with it
363 pathUrl = this.stripBaseUrl(this.getServerBase(), url);
364 }
365 if (typeof pathUrl === 'undefined') {
366 throw new Error("Invalid url \"" + url + "\", missing path prefix \"" + this.getServerBase() + "\".");
367 }
368 this.parseAppUrl(pathUrl);
369 if (!this.$$path) {
370 this.$$path = '/';
371 }
372 this.composeUrls();
373 };
374 /**
375 * Parses the provided URL and its relative URL.
376 *
377 * @param url The full URL string.
378 * @param relHref A URL string relative to the full URL string.
379 */
380 $locationShim.prototype.$$parseLinkUrl = function (url, relHref) {
381 // When relHref is passed, it should be a hash and is handled separately
382 if (relHref && relHref[0] === '#') {
383 this.hash(relHref.slice(1));
384 return true;
385 }
386 var rewrittenUrl;
387 var appUrl = this.stripBaseUrl(this.getServerBase(), url);
388 if (typeof appUrl !== 'undefined') {
389 rewrittenUrl = this.getServerBase() + appUrl;
390 }
391 else if (this.getServerBase() === url + '/') {
392 rewrittenUrl = this.getServerBase();
393 }
394 // Set the URL
395 if (rewrittenUrl) {
396 this.$$parse(rewrittenUrl);
397 }
398 return !!rewrittenUrl;
399 };
400 $locationShim.prototype.setBrowserUrlWithFallback = function (url, replace, state) {
401 var oldUrl = this.url();
402 var oldState = this.$$state;
403 try {
404 this.browserUrl(url, replace, state);
405 // Make sure $location.state() returns referentially identical (not just deeply equal)
406 // state object; this makes possible quick checking if the state changed in the digest
407 // loop. Checking deep equality would be too expensive.
408 this.$$state = this.browserState();
409 }
410 catch (e) {
411 // Restore old values if pushState fails
412 this.url(oldUrl);
413 this.$$state = oldState;
414 throw e;
415 }
416 };
417 $locationShim.prototype.composeUrls = function () {
418 this.$$url = this.urlCodec.normalize(this.$$path, this.$$search, this.$$hash);
419 this.$$absUrl = this.getServerBase() + this.$$url.substr(1); // remove '/' from front of URL
420 this.updateBrowser = true;
421 };
422 /**
423 * Retrieves the full URL representation with all segments encoded according to
424 * rules specified in
425 * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
426 *
427 *
428 * ```js
429 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
430 * let absUrl = $location.absUrl();
431 * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
432 * ```
433 */
434 $locationShim.prototype.absUrl = function () { return this.$$absUrl; };
435 $locationShim.prototype.url = function (url) {
436 if (typeof url === 'string') {
437 if (!url.length) {
438 url = '/';
439 }
440 var match = PATH_MATCH.exec(url);
441 if (!match)
442 return this;
443 if (match[1] || url === '')
444 this.path(this.urlCodec.decodePath(match[1]));
445 if (match[2] || match[1] || url === '')
446 this.search(match[3] || '');
447 this.hash(match[5] || '');
448 // Chainable method
449 return this;
450 }
451 return this.$$url;
452 };
453 /**
454 * Retrieves the protocol of the current URL.
455 *
456 * ```js
457 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
458 * let protocol = $location.protocol();
459 * // => "http"
460 * ```
461 */
462 $locationShim.prototype.protocol = function () { return this.$$protocol; };
463 /**
464 * Retrieves the protocol of the current URL.
465 *
466 * In contrast to the non-AngularJS version `location.host` which returns `hostname:port`, this
467 * returns the `hostname` portion only.
468 *
469 *
470 * ```js
471 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
472 * let host = $location.host();
473 * // => "example.com"
474 *
475 * // given URL http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
476 * host = $location.host();
477 * // => "example.com"
478 * host = location.host;
479 * // => "example.com:8080"
480 * ```
481 */
482 $locationShim.prototype.host = function () { return this.$$host; };
483 /**
484 * Retrieves the port of the current URL.
485 *
486 * ```js
487 * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
488 * let port = $location.port();
489 * // => 80
490 * ```
491 */
492 $locationShim.prototype.port = function () { return this.$$port; };
493 $locationShim.prototype.path = function (path) {
494 if (typeof path === 'undefined') {
495 return this.$$path;
496 }
497 // null path converts to empty string. Prepend with "/" if needed.
498 path = path !== null ? path.toString() : '';
499 path = path.charAt(0) === '/' ? path : '/' + path;
500 this.$$path = path;
501 this.composeUrls();
502 return this;
503 };
504 $locationShim.prototype.search = function (search, paramValue) {
505 switch (arguments.length) {
506 case 0:
507 return this.$$search;
508 case 1:
509 if (typeof search === 'string' || typeof search === 'number') {
510 this.$$search = this.urlCodec.decodeSearch(search.toString());
511 }
512 else if (typeof search === 'object' && search !== null) {
513 // Copy the object so it's never mutated
514 search = __assign({}, search);
515 // remove object undefined or null properties
516 for (var key in search) {
517 if (search[key] == null)
518 delete search[key];
519 }
520 this.$$search = search;
521 }
522 else {
523 throw new Error('LocationProvider.search(): First argument must be a string or an object.');
524 }
525 break;
526 default:
527 if (typeof search === 'string') {
528 var currentSearch = this.search();
529 if (typeof paramValue === 'undefined' || paramValue === null) {
530 delete currentSearch[search];
531 return this.search(currentSearch);
532 }
533 else {
534 currentSearch[search] = paramValue;
535 return this.search(currentSearch);
536 }
537 }
538 }
539 this.composeUrls();
540 return this;
541 };
542 $locationShim.prototype.hash = function (hash) {
543 if (typeof hash === 'undefined') {
544 return this.$$hash;
545 }
546 this.$$hash = hash !== null ? hash.toString() : '';
547 this.composeUrls();
548 return this;
549 };
550 /**
551 * Changes to `$location` during the current `$digest` will replace the current
552 * history record, instead of adding a new one.
553 */
554 $locationShim.prototype.replace = function () {
555 this.$$replace = true;
556 return this;
557 };
558 $locationShim.prototype.state = function (state) {
559 if (typeof state === 'undefined') {
560 return this.$$state;
561 }
562 this.$$state = state;
563 return this;
564 };
565 return $locationShim;
566}());
567/**
568 * The factory function used to create an instance of the `$locationShim` in Angular,
569 * and provides an API-compatiable `$locationProvider` for AngularJS.
570 *
571 * @publicApi
572 */
573var $locationShimProvider = /** @class */ (function () {
574 function $locationShimProvider(ngUpgrade, location, platformLocation, urlCodec, locationStrategy) {
575 this.ngUpgrade = ngUpgrade;
576 this.location = location;
577 this.platformLocation = platformLocation;
578 this.urlCodec = urlCodec;
579 this.locationStrategy = locationStrategy;
580 }
581 /**
582 * Factory method that returns an instance of the $locationShim
583 */
584 $locationShimProvider.prototype.$get = function () {
585 return new $locationShim(this.ngUpgrade.$injector, this.location, this.platformLocation, this.urlCodec, this.locationStrategy);
586 };
587 /**
588 * Stub method used to keep API compatible with AngularJS. This setting is configured through
589 * the LocationUpgradeModule's `config` method in your Angular app.
590 */
591 $locationShimProvider.prototype.hashPrefix = function (prefix) {
592 throw new Error('Configure LocationUpgrade through LocationUpgradeModule.config method.');
593 };
594 /**
595 * Stub method used to keep API compatible with AngularJS. This setting is configured through
596 * the LocationUpgradeModule's `config` method in your Angular app.
597 */
598 $locationShimProvider.prototype.html5Mode = function (mode) {
599 throw new Error('Configure LocationUpgrade through LocationUpgradeModule.config method.');
600 };
601 return $locationShimProvider;
602}());
603
604/**
605 * @license
606 * Copyright Google Inc. All Rights Reserved.
607 *
608 * Use of this source code is governed by an MIT-style license that can be
609 * found in the LICENSE file at https://angular.io/license
610 */
611/**
612 * A codec for encoding and decoding URL parts.
613 *
614 * @publicApi
615 **/
616var UrlCodec = /** @class */ (function () {
617 function UrlCodec() {
618 }
619 return UrlCodec;
620}());
621/**
622 * A `UrlCodec` that uses logic from AngularJS to serialize and parse URLs
623 * and URL parameters.
624 *
625 * @publicApi
626 */
627var AngularJSUrlCodec = /** @class */ (function () {
628 function AngularJSUrlCodec() {
629 }
630 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L15
631 AngularJSUrlCodec.prototype.encodePath = function (path) {
632 var segments = path.split('/');
633 var i = segments.length;
634 while (i--) {
635 // decode forward slashes to prevent them from being double encoded
636 segments[i] = encodeUriSegment(segments[i].replace(/%2F/g, '/'));
637 }
638 path = segments.join('/');
639 return _stripIndexHtml((path && path[0] !== '/' && '/' || '') + path);
640 };
641 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L42
642 AngularJSUrlCodec.prototype.encodeSearch = function (search) {
643 if (typeof search === 'string') {
644 search = parseKeyValue(search);
645 }
646 search = toKeyValue(search);
647 return search ? '?' + search : '';
648 };
649 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L44
650 AngularJSUrlCodec.prototype.encodeHash = function (hash) {
651 hash = encodeUriSegment(hash);
652 return hash ? '#' + hash : '';
653 };
654 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L27
655 AngularJSUrlCodec.prototype.decodePath = function (path, html5Mode) {
656 if (html5Mode === void 0) { html5Mode = true; }
657 var segments = path.split('/');
658 var i = segments.length;
659 while (i--) {
660 segments[i] = decodeURIComponent(segments[i]);
661 if (html5Mode) {
662 // encode forward slashes to prevent them from being mistaken for path separators
663 segments[i] = segments[i].replace(/\//g, '%2F');
664 }
665 }
666 return segments.join('/');
667 };
668 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L72
669 AngularJSUrlCodec.prototype.decodeSearch = function (search) { return parseKeyValue(search); };
670 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L73
671 AngularJSUrlCodec.prototype.decodeHash = function (hash) {
672 hash = decodeURIComponent(hash);
673 return hash[0] === '#' ? hash.substring(1) : hash;
674 };
675 AngularJSUrlCodec.prototype.normalize = function (pathOrHref, search, hash, baseUrl) {
676 if (arguments.length === 1) {
677 var parsed = this.parse(pathOrHref, baseUrl);
678 if (typeof parsed === 'string') {
679 return parsed;
680 }
681 var serverUrl = parsed.protocol + "://" + parsed.hostname + (parsed.port ? ':' + parsed.port : '');
682 return this.normalize(this.decodePath(parsed.pathname), this.decodeSearch(parsed.search), this.decodeHash(parsed.hash), serverUrl);
683 }
684 else {
685 var encPath = this.encodePath(pathOrHref);
686 var encSearch = search && this.encodeSearch(search) || '';
687 var encHash = hash && this.encodeHash(hash) || '';
688 var joinedPath = (baseUrl || '') + encPath;
689 if (!joinedPath.length || joinedPath[0] !== '/') {
690 joinedPath = '/' + joinedPath;
691 }
692 return joinedPath + encSearch + encHash;
693 }
694 };
695 AngularJSUrlCodec.prototype.areEqual = function (valA, valB) { return this.normalize(valA) === this.normalize(valB); };
696 // https://github.com/angular/angular.js/blob/864c7f0/src/ng/urlUtils.js#L60
697 AngularJSUrlCodec.prototype.parse = function (url, base) {
698 try {
699 // Safari 12 throws an error when the URL constructor is called with an undefined base.
700 var parsed = !base ? new URL(url) : new URL(url, base);
701 return {
702 href: parsed.href,
703 protocol: parsed.protocol ? parsed.protocol.replace(/:$/, '') : '',
704 host: parsed.host,
705 search: parsed.search ? parsed.search.replace(/^\?/, '') : '',
706 hash: parsed.hash ? parsed.hash.replace(/^#/, '') : '',
707 hostname: parsed.hostname,
708 port: parsed.port,
709 pathname: (parsed.pathname.charAt(0) === '/') ? parsed.pathname : '/' + parsed.pathname
710 };
711 }
712 catch (e) {
713 throw new Error("Invalid URL (" + url + ") with base (" + base + ")");
714 }
715 };
716 return AngularJSUrlCodec;
717}());
718function _stripIndexHtml(url) {
719 return url.replace(/\/index.html$/, '');
720}
721/**
722 * Tries to decode the URI component without throwing an exception.
723 *
724 * @param str value potential URI component to check.
725 * @returns the decoded URI if it can be decoded or else `undefined`.
726 */
727function tryDecodeURIComponent(value) {
728 try {
729 return decodeURIComponent(value);
730 }
731 catch (e) {
732 // Ignore any invalid uri component.
733 return undefined;
734 }
735}
736/**
737 * Parses an escaped url query string into key-value pairs. Logic taken from
738 * https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1382
739 */
740function parseKeyValue(keyValue) {
741 var obj = {};
742 (keyValue || '').split('&').forEach(function (keyValue) {
743 var splitPoint, key, val;
744 if (keyValue) {
745 key = keyValue = keyValue.replace(/\+/g, '%20');
746 splitPoint = keyValue.indexOf('=');
747 if (splitPoint !== -1) {
748 key = keyValue.substring(0, splitPoint);
749 val = keyValue.substring(splitPoint + 1);
750 }
751 key = tryDecodeURIComponent(key);
752 if (typeof key !== 'undefined') {
753 val = typeof val !== 'undefined' ? tryDecodeURIComponent(val) : true;
754 if (!obj.hasOwnProperty(key)) {
755 obj[key] = val;
756 }
757 else if (Array.isArray(obj[key])) {
758 obj[key].push(val);
759 }
760 else {
761 obj[key] = [obj[key], val];
762 }
763 }
764 }
765 });
766 return obj;
767}
768/**
769 * Serializes into key-value pairs. Logic taken from
770 * https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1409
771 */
772function toKeyValue(obj) {
773 var parts = [];
774 var _loop_1 = function (key) {
775 var value = obj[key];
776 if (Array.isArray(value)) {
777 value.forEach(function (arrayValue) {
778 parts.push(encodeUriQuery(key, true) +
779 (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
780 });
781 }
782 else {
783 parts.push(encodeUriQuery(key, true) +
784 (value === true ? '' : '=' + encodeUriQuery(value, true)));
785 }
786 };
787 for (var key in obj) {
788 _loop_1(key);
789 }
790 return parts.length ? parts.join('&') : '';
791}
792/**
793 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
794 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
795 * segments:
796 * segment = *pchar
797 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
798 * pct-encoded = "%" HEXDIG HEXDIG
799 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
800 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
801 * / "*" / "+" / "," / ";" / "="
802 *
803 * Logic from https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1437
804 */
805function encodeUriSegment(val) {
806 return encodeUriQuery(val, true)
807 .replace(/%26/gi, '&')
808 .replace(/%3D/gi, '=')
809 .replace(/%2B/gi, '+');
810}
811/**
812 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
813 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
814 * encoded per http://tools.ietf.org/html/rfc3986:
815 * query = *( pchar / "/" / "?" )
816 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
817 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
818 * pct-encoded = "%" HEXDIG HEXDIG
819 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
820 * / "*" / "+" / "," / ";" / "="
821 *
822 * Logic from https://github.com/angular/angular.js/blob/864c7f0/src/Angular.js#L1456
823 */
824function encodeUriQuery(val, pctEncodeSpaces) {
825 if (pctEncodeSpaces === void 0) { pctEncodeSpaces = false; }
826 return encodeURIComponent(val)
827 .replace(/%40/gi, '@')
828 .replace(/%3A/gi, ':')
829 .replace(/%24/g, '$')
830 .replace(/%2C/gi, ',')
831 .replace(/%3B/gi, ';')
832 .replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
833}
834
835/**
836 * @license
837 * Copyright Google Inc. All Rights Reserved.
838 *
839 * Use of this source code is governed by an MIT-style license that can be
840 * found in the LICENSE file at https://angular.io/license
841 */
842/**
843 * A provider token used to configure the location upgrade module.
844 *
845 * @publicApi
846 */
847var LOCATION_UPGRADE_CONFIGURATION = new InjectionToken('LOCATION_UPGRADE_CONFIGURATION');
848var APP_BASE_HREF_RESOLVED = new InjectionToken('APP_BASE_HREF_RESOLVED');
849/**
850 * `NgModule` used for providing and configuring Angular's Unified Location Service for upgrading.
851 *
852 * @see [Using the Unified Angular Location Service](guide/upgrade#using-the-unified-angular-location-service)
853 *
854 * @publicApi
855 */
856var LocationUpgradeModule = /** @class */ (function () {
857 function LocationUpgradeModule() {
858 }
859 LocationUpgradeModule_1 = LocationUpgradeModule;
860 LocationUpgradeModule.config = function (config) {
861 return {
862 ngModule: LocationUpgradeModule_1,
863 providers: [
864 Location,
865 {
866 provide: $locationShim,
867 useFactory: provide$location,
868 deps: [UpgradeModule, Location, PlatformLocation, UrlCodec, LocationStrategy]
869 },
870 { provide: LOCATION_UPGRADE_CONFIGURATION, useValue: config ? config : {} },
871 { provide: UrlCodec, useFactory: provideUrlCodec, deps: [LOCATION_UPGRADE_CONFIGURATION] },
872 {
873 provide: APP_BASE_HREF_RESOLVED,
874 useFactory: provideAppBaseHref,
875 deps: [LOCATION_UPGRADE_CONFIGURATION, [new Inject(APP_BASE_HREF), new Optional()]]
876 },
877 {
878 provide: LocationStrategy,
879 useFactory: provideLocationStrategy,
880 deps: [
881 PlatformLocation,
882 APP_BASE_HREF_RESOLVED,
883 LOCATION_UPGRADE_CONFIGURATION,
884 ]
885 },
886 ],
887 };
888 };
889 var LocationUpgradeModule_1;
890 LocationUpgradeModule = LocationUpgradeModule_1 = __decorate([
891 NgModule({ imports: [CommonModule] })
892 ], LocationUpgradeModule);
893 return LocationUpgradeModule;
894}());
895function provideAppBaseHref(config, appBaseHref) {
896 if (config && config.appBaseHref != null) {
897 return config.appBaseHref;
898 }
899 else if (appBaseHref != null) {
900 return appBaseHref;
901 }
902 return '';
903}
904function provideUrlCodec(config) {
905 var codec = config && config.urlCodec || AngularJSUrlCodec;
906 return new codec();
907}
908function provideLocationStrategy(platformLocation, baseHref, options) {
909 if (options === void 0) { options = {}; }
910 return options.useHash ? new HashLocationStrategy(platformLocation, baseHref) :
911 new PathLocationStrategy(platformLocation, baseHref);
912}
913function provide$location(ngUpgrade, location, platformLocation, urlCodec, locationStrategy) {
914 var $locationProvider = new $locationShimProvider(ngUpgrade, location, platformLocation, urlCodec, locationStrategy);
915 return $locationProvider.$get();
916}
917
918/**
919 * @license
920 * Copyright Google Inc. All Rights Reserved.
921 *
922 * Use of this source code is governed by an MIT-style license that can be
923 * found in the LICENSE file at https://angular.io/license
924 */
925
926/**
927 * @license
928 * Copyright Google Inc. All Rights Reserved.
929 *
930 * Use of this source code is governed by an MIT-style license that can be
931 * found in the LICENSE file at https://angular.io/license
932 */
933// This file only reexports content of the `src` folder. Keep it that way.
934
935/**
936 * @license
937 * Copyright Google Inc. All Rights Reserved.
938 *
939 * Use of this source code is governed by an MIT-style license that can be
940 * found in the LICENSE file at https://angular.io/license
941 */
942
943/**
944 * Generated bundle index. Do not edit.
945 */
946
947export { $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 };
948//# sourceMappingURL=upgrade.js.map