UNPKG

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