upgrade.js 39 KB

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