source: trip-planner-front/node_modules/@angular/common/__ivy_ngcc__/fesm2015/common.js@ e29cc2e

Last change on this file since e29cc2e was e29cc2e, checked in by Ema <ema_spirova@…>, 3 years ago

primeNG components

  • Property mode set to 100644
File size: 224.4 KB
Line 
1/**
2 * @license Angular v12.2.13
3 * (c) 2010-2021 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { InjectionToken, ɵɵdefineInjectable, Injectable, ɵɵinject, Inject, Optional, EventEmitter, ɵfindLocaleData, ɵLocaleDataIndex, ɵgetLocaleCurrencyCode, ɵgetLocalePluralCase, LOCALE_ID, ɵregisterLocaleData, ɵisListLikeIterable, ɵstringify, Directive, IterableDiffers, KeyValueDiffers, ElementRef, Renderer2, Input, NgModuleRef, ComponentFactoryResolver, ViewContainerRef, TemplateRef, Host, ɵRuntimeError, Attribute, ɵisPromise, ɵisSubscribable, Pipe, ChangeDetectorRef, DEFAULT_CURRENCY_CODE, NgModule, Version } from '@angular/core';
8
9/**
10 * @license
11 * Copyright Google LLC All Rights Reserved.
12 *
13 * Use of this source code is governed by an MIT-style license that can be
14 * found in the LICENSE file at https://angular.io/license
15 */
16import * as ɵngcc0 from '@angular/core';
17let _DOM = null;
18function getDOM() {
19 return _DOM;
20}
21function setDOM(adapter) {
22 _DOM = adapter;
23}
24function setRootDomAdapter(adapter) {
25 if (!_DOM) {
26 _DOM = adapter;
27 }
28}
29/* tslint:disable:requireParameterType */
30/**
31 * Provides DOM operations in an environment-agnostic way.
32 *
33 * @security Tread carefully! Interacting with the DOM directly is dangerous and
34 * can introduce XSS risks.
35 */
36class DomAdapter {
37}
38
39/**
40 * @license
41 * Copyright Google LLC All Rights Reserved.
42 *
43 * Use of this source code is governed by an MIT-style license that can be
44 * found in the LICENSE file at https://angular.io/license
45 */
46/**
47 * A DI Token representing the main rendering context. In a browser this is the DOM Document.
48 *
49 * Note: Document might not be available in the Application Context when Application and Rendering
50 * Contexts are not the same (e.g. when running the application in a Web Worker).
51 *
52 * @publicApi
53 */
54const DOCUMENT = new InjectionToken('DocumentToken');
55
56/**
57 * @license
58 * Copyright Google LLC All Rights Reserved.
59 *
60 * Use of this source code is governed by an MIT-style license that can be
61 * found in the LICENSE file at https://angular.io/license
62 */
63/**
64 * This class should not be used directly by an application developer. Instead, use
65 * {@link Location}.
66 *
67 * `PlatformLocation` encapsulates all calls to DOM APIs, which allows the Router to be
68 * platform-agnostic.
69 * This means that we can have different implementation of `PlatformLocation` for the different
70 * platforms that Angular supports. For example, `@angular/platform-browser` provides an
71 * implementation specific to the browser environment, while `@angular/platform-server` provides
72 * one suitable for use with server-side rendering.
73 *
74 * The `PlatformLocation` class is used directly by all implementations of {@link LocationStrategy}
75 * when they need to interact with the DOM APIs like pushState, popState, etc.
76 *
77 * {@link LocationStrategy} in turn is used by the {@link Location} service which is used directly
78 * by the {@link Router} in order to navigate between routes. Since all interactions between {@link
79 * Router} /
80 * {@link Location} / {@link LocationStrategy} and DOM APIs flow through the `PlatformLocation`
81 * class, they are all platform-agnostic.
82 *
83 * @publicApi
84 */
85class PlatformLocation {
86 historyGo(relativePosition) {
87 throw new Error('Not implemented');
88 }
89}
90PlatformLocation.ɵfac = function PlatformLocation_Factory(t) { return new (t || PlatformLocation)(); };
91PlatformLocation.ɵprov = ɵɵdefineInjectable({ factory: useBrowserPlatformLocation, token: PlatformLocation, providedIn: "platform" });
92(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(PlatformLocation, [{
93 type: Injectable,
94 args: [{
95 providedIn: 'platform',
96 // See #23917
97 useFactory: useBrowserPlatformLocation
98 }]
99 }], null, null); })();
100function useBrowserPlatformLocation() {
101 return ɵɵinject(BrowserPlatformLocation);
102}
103/**
104 * @description
105 * Indicates when a location is initialized.
106 *
107 * @publicApi
108 */
109const LOCATION_INITIALIZED = new InjectionToken('Location Initialized');
110/**
111 * `PlatformLocation` encapsulates all of the direct calls to platform APIs.
112 * This class should not be used directly by an application developer. Instead, use
113 * {@link Location}.
114 */
115class BrowserPlatformLocation extends PlatformLocation {
116 constructor(_doc) {
117 super();
118 this._doc = _doc;
119 this._init();
120 }
121 // This is moved to its own method so that `MockPlatformLocationStrategy` can overwrite it
122 /** @internal */
123 _init() {
124 this.location = window.location;
125 this._history = window.history;
126 }
127 getBaseHrefFromDOM() {
128 return getDOM().getBaseHref(this._doc);
129 }
130 onPopState(fn) {
131 const window = getDOM().getGlobalEventTarget(this._doc, 'window');
132 window.addEventListener('popstate', fn, false);
133 return () => window.removeEventListener('popstate', fn);
134 }
135 onHashChange(fn) {
136 const window = getDOM().getGlobalEventTarget(this._doc, 'window');
137 window.addEventListener('hashchange', fn, false);
138 return () => window.removeEventListener('hashchange', fn);
139 }
140 get href() {
141 return this.location.href;
142 }
143 get protocol() {
144 return this.location.protocol;
145 }
146 get hostname() {
147 return this.location.hostname;
148 }
149 get port() {
150 return this.location.port;
151 }
152 get pathname() {
153 return this.location.pathname;
154 }
155 get search() {
156 return this.location.search;
157 }
158 get hash() {
159 return this.location.hash;
160 }
161 set pathname(newPath) {
162 this.location.pathname = newPath;
163 }
164 pushState(state, title, url) {
165 if (supportsState()) {
166 this._history.pushState(state, title, url);
167 }
168 else {
169 this.location.hash = url;
170 }
171 }
172 replaceState(state, title, url) {
173 if (supportsState()) {
174 this._history.replaceState(state, title, url);
175 }
176 else {
177 this.location.hash = url;
178 }
179 }
180 forward() {
181 this._history.forward();
182 }
183 back() {
184 this._history.back();
185 }
186 historyGo(relativePosition = 0) {
187 this._history.go(relativePosition);
188 }
189 getState() {
190 return this._history.state;
191 }
192}
193BrowserPlatformLocation.ɵfac = function BrowserPlatformLocation_Factory(t) { return new (t || BrowserPlatformLocation)(ɵngcc0.ɵɵinject(DOCUMENT)); };
194BrowserPlatformLocation.ɵprov = ɵɵdefineInjectable({ factory: createBrowserPlatformLocation, token: BrowserPlatformLocation, providedIn: "platform" });
195BrowserPlatformLocation.ctorParameters = () => [
196 { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
197];
198(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(BrowserPlatformLocation, [{
199 type: Injectable,
200 args: [{
201 providedIn: 'platform',
202 // See #23917
203 useFactory: createBrowserPlatformLocation
204 }]
205 }], function () { return [{ type: undefined, decorators: [{
206 type: Inject,
207 args: [DOCUMENT]
208 }] }]; }, null); })();
209function supportsState() {
210 return !!window.history.pushState;
211}
212function createBrowserPlatformLocation() {
213 return new BrowserPlatformLocation(ɵɵinject(DOCUMENT));
214}
215
216/**
217 * @license
218 * Copyright Google LLC All Rights Reserved.
219 *
220 * Use of this source code is governed by an MIT-style license that can be
221 * found in the LICENSE file at https://angular.io/license
222 */
223
224/**
225 * @license
226 * Copyright Google LLC All Rights Reserved.
227 *
228 * Use of this source code is governed by an MIT-style license that can be
229 * found in the LICENSE file at https://angular.io/license
230 */
231/**
232 * Joins two parts of a URL with a slash if needed.
233 *
234 * @param start URL string
235 * @param end URL string
236 *
237 *
238 * @returns The joined URL string.
239 */
240function joinWithSlash(start, end) {
241 if (start.length == 0) {
242 return end;
243 }
244 if (end.length == 0) {
245 return start;
246 }
247 let slashes = 0;
248 if (start.endsWith('/')) {
249 slashes++;
250 }
251 if (end.startsWith('/')) {
252 slashes++;
253 }
254 if (slashes == 2) {
255 return start + end.substring(1);
256 }
257 if (slashes == 1) {
258 return start + end;
259 }
260 return start + '/' + end;
261}
262/**
263 * Removes a trailing slash from a URL string if needed.
264 * Looks for the first occurrence of either `#`, `?`, or the end of the
265 * line as `/` characters and removes the trailing slash if one exists.
266 *
267 * @param url URL string.
268 *
269 * @returns The URL string, modified if needed.
270 */
271function stripTrailingSlash(url) {
272 const match = url.match(/#|\?|$/);
273 const pathEndIdx = match && match.index || url.length;
274 const droppedSlashIdx = pathEndIdx - (url[pathEndIdx - 1] === '/' ? 1 : 0);
275 return url.slice(0, droppedSlashIdx) + url.slice(pathEndIdx);
276}
277/**
278 * Normalizes URL parameters by prepending with `?` if needed.
279 *
280 * @param params String of URL parameters.
281 *
282 * @returns The normalized URL parameters string.
283 */
284function normalizeQueryParams(params) {
285 return params && params[0] !== '?' ? '?' + params : params;
286}
287
288/**
289 * @license
290 * Copyright Google LLC All Rights Reserved.
291 *
292 * Use of this source code is governed by an MIT-style license that can be
293 * found in the LICENSE file at https://angular.io/license
294 */
295/**
296 * Enables the `Location` service to read route state from the browser's URL.
297 * Angular provides two strategies:
298 * `HashLocationStrategy` and `PathLocationStrategy`.
299 *
300 * Applications should use the `Router` or `Location` services to
301 * interact with application route state.
302 *
303 * For instance, `HashLocationStrategy` produces URLs like
304 * <code class="no-auto-link">http://example.com#/foo</code>,
305 * and `PathLocationStrategy` produces
306 * <code class="no-auto-link">http://example.com/foo</code> as an equivalent URL.
307 *
308 * See these two classes for more.
309 *
310 * @publicApi
311 */
312class LocationStrategy {
313 historyGo(relativePosition) {
314 throw new Error('Not implemented');
315 }
316}
317LocationStrategy.ɵfac = function LocationStrategy_Factory(t) { return new (t || LocationStrategy)(); };
318LocationStrategy.ɵprov = ɵɵdefineInjectable({ factory: provideLocationStrategy, token: LocationStrategy, providedIn: "root" });
319(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(LocationStrategy, [{
320 type: Injectable,
321 args: [{ providedIn: 'root', useFactory: provideLocationStrategy }]
322 }], null, null); })();
323function provideLocationStrategy(platformLocation) {
324 // See #23917
325 const location = ɵɵinject(DOCUMENT).location;
326 return new PathLocationStrategy(ɵɵinject(PlatformLocation), location && location.origin || '');
327}
328/**
329 * A predefined [DI token](guide/glossary#di-token) for the base href
330 * to be used with the `PathLocationStrategy`.
331 * The base href is the URL prefix that should be preserved when generating
332 * and recognizing URLs.
333 *
334 * @usageNotes
335 *
336 * The following example shows how to use this token to configure the root app injector
337 * with a base href value, so that the DI framework can supply the dependency anywhere in the app.
338 *
339 * ```typescript
340 * import {Component, NgModule} from '@angular/core';
341 * import {APP_BASE_HREF} from '@angular/common';
342 *
343 * @NgModule({
344 * providers: [{provide: APP_BASE_HREF, useValue: '/my/app'}]
345 * })
346 * class AppModule {}
347 * ```
348 *
349 * @publicApi
350 */
351const APP_BASE_HREF = new InjectionToken('appBaseHref');
352/**
353 * @description
354 * A {@link LocationStrategy} used to configure the {@link Location} service to
355 * represent its state in the
356 * [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) of the
357 * browser's URL.
358 *
359 * If you're using `PathLocationStrategy`, you must provide a {@link APP_BASE_HREF}
360 * or add a `<base href>` element to the document.
361 *
362 * For instance, if you provide an `APP_BASE_HREF` of `'/my/app/'` and call
363 * `location.go('/foo')`, the browser's URL will become
364 * `example.com/my/app/foo`. To ensure all relative URIs resolve correctly,
365 * the `<base href>` and/or `APP_BASE_HREF` should end with a `/`.
366 *
367 * Similarly, if you add `<base href='/my/app/'/>` to the document and call
368 * `location.go('/foo')`, the browser's URL will become
369 * `example.com/my/app/foo`.
370 *
371 * Note that when using `PathLocationStrategy`, neither the query nor
372 * the fragment in the `<base href>` will be preserved, as outlined
373 * by the [RFC](https://tools.ietf.org/html/rfc3986#section-5.2.2).
374 *
375 * @usageNotes
376 *
377 * ### Example
378 *
379 * {@example common/location/ts/path_location_component.ts region='LocationComponent'}
380 *
381 * @publicApi
382 */
383class PathLocationStrategy extends LocationStrategy {
384 constructor(_platformLocation, href) {
385 super();
386 this._platformLocation = _platformLocation;
387 this._removeListenerFns = [];
388 if (href == null) {
389 href = this._platformLocation.getBaseHrefFromDOM();
390 }
391 if (href == null) {
392 throw new Error(`No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.`);
393 }
394 this._baseHref = href;
395 }
396 ngOnDestroy() {
397 while (this._removeListenerFns.length) {
398 this._removeListenerFns.pop()();
399 }
400 }
401 onPopState(fn) {
402 this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn));
403 }
404 getBaseHref() {
405 return this._baseHref;
406 }
407 prepareExternalUrl(internal) {
408 return joinWithSlash(this._baseHref, internal);
409 }
410 path(includeHash = false) {
411 const pathname = this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search);
412 const hash = this._platformLocation.hash;
413 return hash && includeHash ? `${pathname}${hash}` : pathname;
414 }
415 pushState(state, title, url, queryParams) {
416 const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
417 this._platformLocation.pushState(state, title, externalUrl);
418 }
419 replaceState(state, title, url, queryParams) {
420 const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
421 this._platformLocation.replaceState(state, title, externalUrl);
422 }
423 forward() {
424 this._platformLocation.forward();
425 }
426 back() {
427 this._platformLocation.back();
428 }
429 historyGo(relativePosition = 0) {
430 var _a, _b;
431 (_b = (_a = this._platformLocation).historyGo) === null || _b === void 0 ? void 0 : _b.call(_a, relativePosition);
432 }
433}
434PathLocationStrategy.ɵfac = function PathLocationStrategy_Factory(t) { return new (t || PathLocationStrategy)(ɵngcc0.ɵɵinject(PlatformLocation), ɵngcc0.ɵɵinject(APP_BASE_HREF, 8)); };
435PathLocationStrategy.ɵprov = /*@__PURE__*/ ɵngcc0.ɵɵdefineInjectable({ token: PathLocationStrategy, factory: PathLocationStrategy.ɵfac });
436PathLocationStrategy.ctorParameters = () => [
437 { type: PlatformLocation },
438 { type: String, decorators: [{ type: Optional }, { type: Inject, args: [APP_BASE_HREF,] }] }
439];
440(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(PathLocationStrategy, [{
441 type: Injectable
442 }], function () { return [{ type: PlatformLocation }, { type: String, decorators: [{
443 type: Optional
444 }, {
445 type: Inject,
446 args: [APP_BASE_HREF]
447 }] }]; }, null); })();
448
449/**
450 * @license
451 * Copyright Google LLC All Rights Reserved.
452 *
453 * Use of this source code is governed by an MIT-style license that can be
454 * found in the LICENSE file at https://angular.io/license
455 */
456/**
457 * @description
458 * A {@link LocationStrategy} used to configure the {@link Location} service to
459 * represent its state in the
460 * [hash fragment](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax)
461 * of the browser's URL.
462 *
463 * For instance, if you call `location.go('/foo')`, the browser's URL will become
464 * `example.com#/foo`.
465 *
466 * @usageNotes
467 *
468 * ### Example
469 *
470 * {@example common/location/ts/hash_location_component.ts region='LocationComponent'}
471 *
472 * @publicApi
473 */
474class HashLocationStrategy extends LocationStrategy {
475 constructor(_platformLocation, _baseHref) {
476 super();
477 this._platformLocation = _platformLocation;
478 this._baseHref = '';
479 this._removeListenerFns = [];
480 if (_baseHref != null) {
481 this._baseHref = _baseHref;
482 }
483 }
484 ngOnDestroy() {
485 while (this._removeListenerFns.length) {
486 this._removeListenerFns.pop()();
487 }
488 }
489 onPopState(fn) {
490 this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn));
491 }
492 getBaseHref() {
493 return this._baseHref;
494 }
495 path(includeHash = false) {
496 // the hash value is always prefixed with a `#`
497 // and if it is empty then it will stay empty
498 let path = this._platformLocation.hash;
499 if (path == null)
500 path = '#';
501 return path.length > 0 ? path.substring(1) : path;
502 }
503 prepareExternalUrl(internal) {
504 const url = joinWithSlash(this._baseHref, internal);
505 return url.length > 0 ? ('#' + url) : url;
506 }
507 pushState(state, title, path, queryParams) {
508 let url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams));
509 if (url.length == 0) {
510 url = this._platformLocation.pathname;
511 }
512 this._platformLocation.pushState(state, title, url);
513 }
514 replaceState(state, title, path, queryParams) {
515 let url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams));
516 if (url.length == 0) {
517 url = this._platformLocation.pathname;
518 }
519 this._platformLocation.replaceState(state, title, url);
520 }
521 forward() {
522 this._platformLocation.forward();
523 }
524 back() {
525 this._platformLocation.back();
526 }
527 historyGo(relativePosition = 0) {
528 var _a, _b;
529 (_b = (_a = this._platformLocation).historyGo) === null || _b === void 0 ? void 0 : _b.call(_a, relativePosition);
530 }
531}
532HashLocationStrategy.ɵfac = function HashLocationStrategy_Factory(t) { return new (t || HashLocationStrategy)(ɵngcc0.ɵɵinject(PlatformLocation), ɵngcc0.ɵɵinject(APP_BASE_HREF, 8)); };
533HashLocationStrategy.ɵprov = /*@__PURE__*/ ɵngcc0.ɵɵdefineInjectable({ token: HashLocationStrategy, factory: HashLocationStrategy.ɵfac });
534HashLocationStrategy.ctorParameters = () => [
535 { type: PlatformLocation },
536 { type: String, decorators: [{ type: Optional }, { type: Inject, args: [APP_BASE_HREF,] }] }
537];
538(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(HashLocationStrategy, [{
539 type: Injectable
540 }], function () { return [{ type: PlatformLocation }, { type: String, decorators: [{
541 type: Optional
542 }, {
543 type: Inject,
544 args: [APP_BASE_HREF]
545 }] }]; }, null); })();
546
547/**
548 * @license
549 * Copyright Google LLC All Rights Reserved.
550 *
551 * Use of this source code is governed by an MIT-style license that can be
552 * found in the LICENSE file at https://angular.io/license
553 */
554/**
555 * @description
556 *
557 * A service that applications can use to interact with a browser's URL.
558 *
559 * Depending on the `LocationStrategy` used, `Location` persists
560 * to the URL's path or the URL's hash segment.
561 *
562 * @usageNotes
563 *
564 * It's better to use the `Router.navigate()` service to trigger route changes. Use
565 * `Location` only if you need to interact with or create normalized URLs outside of
566 * routing.
567 *
568 * `Location` is responsible for normalizing the URL against the application's base href.
569 * A normalized URL is absolute from the URL host, includes the application's base href, and has no
570 * trailing slash:
571 * - `/my/app/user/123` is normalized
572 * - `my/app/user/123` **is not** normalized
573 * - `/my/app/user/123/` **is not** normalized
574 *
575 * ### Example
576 *
577 * <code-example path='common/location/ts/path_location_component.ts'
578 * region='LocationComponent'></code-example>
579 *
580 * @publicApi
581 */
582class Location {
583 constructor(platformStrategy, platformLocation) {
584 /** @internal */
585 this._subject = new EventEmitter();
586 /** @internal */
587 this._urlChangeListeners = [];
588 this._platformStrategy = platformStrategy;
589 const browserBaseHref = this._platformStrategy.getBaseHref();
590 this._platformLocation = platformLocation;
591 this._baseHref = stripTrailingSlash(_stripIndexHtml(browserBaseHref));
592 this._platformStrategy.onPopState((ev) => {
593 this._subject.emit({
594 'url': this.path(true),
595 'pop': true,
596 'state': ev.state,
597 'type': ev.type,
598 });
599 });
600 }
601 /**
602 * Normalizes the URL path for this location.
603 *
604 * @param includeHash True to include an anchor fragment in the path.
605 *
606 * @returns The normalized URL path.
607 */
608 // TODO: vsavkin. Remove the boolean flag and always include hash once the deprecated router is
609 // removed.
610 path(includeHash = false) {
611 return this.normalize(this._platformStrategy.path(includeHash));
612 }
613 /**
614 * Reports the current state of the location history.
615 * @returns The current value of the `history.state` object.
616 */
617 getState() {
618 return this._platformLocation.getState();
619 }
620 /**
621 * Normalizes the given path and compares to the current normalized path.
622 *
623 * @param path The given URL path.
624 * @param query Query parameters.
625 *
626 * @returns True if the given URL path is equal to the current normalized path, false
627 * otherwise.
628 */
629 isCurrentPathEqualTo(path, query = '') {
630 return this.path() == this.normalize(path + normalizeQueryParams(query));
631 }
632 /**
633 * Normalizes a URL path by stripping any trailing slashes.
634 *
635 * @param url String representing a URL.
636 *
637 * @returns The normalized URL string.
638 */
639 normalize(url) {
640 return Location.stripTrailingSlash(_stripBaseHref(this._baseHref, _stripIndexHtml(url)));
641 }
642 /**
643 * Normalizes an external URL path.
644 * If the given URL doesn't begin with a leading slash (`'/'`), adds one
645 * before normalizing. Adds a hash if `HashLocationStrategy` is
646 * in use, or the `APP_BASE_HREF` if the `PathLocationStrategy` is in use.
647 *
648 * @param url String representing a URL.
649 *
650 * @returns A normalized platform-specific URL.
651 */
652 prepareExternalUrl(url) {
653 if (url && url[0] !== '/') {
654 url = '/' + url;
655 }
656 return this._platformStrategy.prepareExternalUrl(url);
657 }
658 // TODO: rename this method to pushState
659 /**
660 * Changes the browser's URL to a normalized version of a given URL, and pushes a
661 * new item onto the platform's history.
662 *
663 * @param path URL path to normalize.
664 * @param query Query parameters.
665 * @param state Location history state.
666 *
667 */
668 go(path, query = '', state = null) {
669 this._platformStrategy.pushState(state, '', path, query);
670 this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state);
671 }
672 /**
673 * Changes the browser's URL to a normalized version of the given URL, and replaces
674 * the top item on the platform's history stack.
675 *
676 * @param path URL path to normalize.
677 * @param query Query parameters.
678 * @param state Location history state.
679 */
680 replaceState(path, query = '', state = null) {
681 this._platformStrategy.replaceState(state, '', path, query);
682 this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state);
683 }
684 /**
685 * Navigates forward in the platform's history.
686 */
687 forward() {
688 this._platformStrategy.forward();
689 }
690 /**
691 * Navigates back in the platform's history.
692 */
693 back() {
694 this._platformStrategy.back();
695 }
696 /**
697 * Navigate to a specific page from session history, identified by its relative position to the
698 * current page.
699 *
700 * @param relativePosition Position of the target page in the history relative to the current
701 * page.
702 * A negative value moves backwards, a positive value moves forwards, e.g. `location.historyGo(2)`
703 * moves forward two pages and `location.historyGo(-2)` moves back two pages. When we try to go
704 * beyond what's stored in the history session, we stay in the current page. Same behaviour occurs
705 * when `relativePosition` equals 0.
706 * @see https://developer.mozilla.org/en-US/docs/Web/API/History_API#Moving_to_a_specific_point_in_history
707 */
708 historyGo(relativePosition = 0) {
709 var _a, _b;
710 (_b = (_a = this._platformStrategy).historyGo) === null || _b === void 0 ? void 0 : _b.call(_a, relativePosition);
711 }
712 /**
713 * Registers a URL change listener. Use to catch updates performed by the Angular
714 * framework that are not detectible through "popstate" or "hashchange" events.
715 *
716 * @param fn The change handler function, which take a URL and a location history state.
717 */
718 onUrlChange(fn) {
719 this._urlChangeListeners.push(fn);
720 if (!this._urlChangeSubscription) {
721 this._urlChangeSubscription = this.subscribe(v => {
722 this._notifyUrlChangeListeners(v.url, v.state);
723 });
724 }
725 }
726 /** @internal */
727 _notifyUrlChangeListeners(url = '', state) {
728 this._urlChangeListeners.forEach(fn => fn(url, state));
729 }
730 /**
731 * Subscribes to the platform's `popState` events.
732 *
733 * Note: `Location.go()` does not trigger the `popState` event in the browser. Use
734 * `Location.onUrlChange()` to subscribe to URL changes instead.
735 *
736 * @param value Event that is triggered when the state history changes.
737 * @param exception The exception to throw.
738 *
739 * @see [onpopstate](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate)
740 *
741 * @returns Subscribed events.
742 */
743 subscribe(onNext, onThrow, onReturn) {
744 return this._subject.subscribe({ next: onNext, error: onThrow, complete: onReturn });
745 }
746}
747Location.ɵfac = function Location_Factory(t) { return new (t || Location)(ɵngcc0.ɵɵinject(LocationStrategy), ɵngcc0.ɵɵinject(PlatformLocation)); };
748/**
749 * Normalizes URL parameters by prepending with `?` if needed.
750 *
751 * @param params String of URL parameters.
752 *
753 * @returns The normalized URL parameters string.
754 */
755Location.normalizeQueryParams = normalizeQueryParams;
756/**
757 * Joins two parts of a URL with a slash if needed.
758 *
759 * @param start URL string
760 * @param end URL string
761 *
762 *
763 * @returns The joined URL string.
764 */
765Location.joinWithSlash = joinWithSlash;
766/**
767 * Removes a trailing slash from a URL string if needed.
768 * Looks for the first occurrence of either `#`, `?`, or the end of the
769 * line as `/` characters and removes the trailing slash if one exists.
770 *
771 * @param url URL string.
772 *
773 * @returns The URL string, modified if needed.
774 */
775Location.stripTrailingSlash = stripTrailingSlash;
776Location.ɵprov = ɵɵdefineInjectable({ factory: createLocation, token: Location, providedIn: "root" });
777Location.ctorParameters = () => [
778 { type: LocationStrategy },
779 { type: PlatformLocation }
780];
781(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(Location, [{
782 type: Injectable,
783 args: [{
784 providedIn: 'root',
785 // See #23917
786 useFactory: createLocation
787 }]
788 }], function () { return [{ type: LocationStrategy }, { type: PlatformLocation }]; }, null); })();
789function createLocation() {
790 return new Location(ɵɵinject(LocationStrategy), ɵɵinject(PlatformLocation));
791}
792function _stripBaseHref(baseHref, url) {
793 return baseHref && url.startsWith(baseHref) ? url.substring(baseHref.length) : url;
794}
795function _stripIndexHtml(url) {
796 return url.replace(/\/index.html$/, '');
797}
798
799/**
800 * @license
801 * Copyright Google LLC All Rights Reserved.
802 *
803 * Use of this source code is governed by an MIT-style license that can be
804 * found in the LICENSE file at https://angular.io/license
805 */
806
807/**
808 * @license
809 * Copyright Google LLC All Rights Reserved.
810 *
811 * Use of this source code is governed by an MIT-style license that can be
812 * found in the LICENSE file at https://angular.io/license
813 */
814/** @internal */
815const CURRENCIES_EN = { "ADP": [undefined, undefined, 0], "AFN": [undefined, undefined, 0], "ALL": [undefined, undefined, 0], "AMD": [undefined, undefined, 2], "AOA": [undefined, "Kz"], "ARS": [undefined, "$"], "AUD": ["A$", "$"], "BAM": [undefined, "KM"], "BBD": [undefined, "$"], "BDT": [undefined, "৳"], "BHD": [undefined, undefined, 3], "BIF": [undefined, undefined, 0], "BMD": [undefined, "$"], "BND": [undefined, "$"], "BOB": [undefined, "Bs"], "BRL": ["R$"], "BSD": [undefined, "$"], "BWP": [undefined, "P"], "BYN": [undefined, "р.", 2], "BYR": [undefined, undefined, 0], "BZD": [undefined, "$"], "CAD": ["CA$", "$", 2], "CHF": [undefined, undefined, 2], "CLF": [undefined, undefined, 4], "CLP": [undefined, "$", 0], "CNY": ["CN¥", "¥"], "COP": [undefined, "$", 2], "CRC": [undefined, "₡", 2], "CUC": [undefined, "$"], "CUP": [undefined, "$"], "CZK": [undefined, "Kč", 2], "DJF": [undefined, undefined, 0], "DKK": [undefined, "kr", 2], "DOP": [undefined, "$"], "EGP": [undefined, "E£"], "ESP": [undefined, "₧", 0], "EUR": ["€"], "FJD": [undefined, "$"], "FKP": [undefined, "£"], "GBP": ["£"], "GEL": [undefined, "₾"], "GIP": [undefined, "£"], "GNF": [undefined, "FG", 0], "GTQ": [undefined, "Q"], "GYD": [undefined, "$", 2], "HKD": ["HK$", "$"], "HNL": [undefined, "L"], "HRK": [undefined, "kn"], "HUF": [undefined, "Ft", 2], "IDR": [undefined, "Rp", 2], "ILS": ["₪"], "INR": ["₹"], "IQD": [undefined, undefined, 0], "IRR": [undefined, undefined, 0], "ISK": [undefined, "kr", 0], "ITL": [undefined, undefined, 0], "JMD": [undefined, "$"], "JOD": [undefined, undefined, 3], "JPY": ["¥", undefined, 0], "KHR": [undefined, "៛"], "KMF": [undefined, "CF", 0], "KPW": [undefined, "₩", 0], "KRW": ["₩", undefined, 0], "KWD": [undefined, undefined, 3], "KYD": [undefined, "$"], "KZT": [undefined, "₸"], "LAK": [undefined, "₭", 0], "LBP": [undefined, "L£", 0], "LKR": [undefined, "Rs"], "LRD": [undefined, "$"], "LTL": [undefined, "Lt"], "LUF": [undefined, undefined, 0], "LVL": [undefined, "Ls"], "LYD": [undefined, undefined, 3], "MGA": [undefined, "Ar", 0], "MGF": [undefined, undefined, 0], "MMK": [undefined, "K", 0], "MNT": [undefined, "₮", 2], "MRO": [undefined, undefined, 0], "MUR": [undefined, "Rs", 2], "MXN": ["MX$", "$"], "MYR": [undefined, "RM"], "NAD": [undefined, "$"], "NGN": [undefined, "₦"], "NIO": [undefined, "C$"], "NOK": [undefined, "kr", 2], "NPR": [undefined, "Rs"], "NZD": ["NZ$", "$"], "OMR": [undefined, undefined, 3], "PHP": [undefined, "₱"], "PKR": [undefined, "Rs", 2], "PLN": [undefined, "zł"], "PYG": [undefined, "₲", 0], "RON": [undefined, "lei"], "RSD": [undefined, undefined, 0], "RUB": [undefined, "₽"], "RUR": [undefined, "р."], "RWF": [undefined, "RF", 0], "SBD": [undefined, "$"], "SEK": [undefined, "kr", 2], "SGD": [undefined, "$"], "SHP": [undefined, "£"], "SLL": [undefined, undefined, 0], "SOS": [undefined, undefined, 0], "SRD": [undefined, "$"], "SSP": [undefined, "£"], "STD": [undefined, undefined, 0], "STN": [undefined, "Db"], "SYP": [undefined, "£", 0], "THB": [undefined, "฿"], "TMM": [undefined, undefined, 0], "TND": [undefined, undefined, 3], "TOP": [undefined, "T$"], "TRL": [undefined, undefined, 0], "TRY": [undefined, "₺"], "TTD": [undefined, "$"], "TWD": ["NT$", "$", 2], "TZS": [undefined, undefined, 2], "UAH": [undefined, "₴"], "UGX": [undefined, undefined, 0], "USD": ["$"], "UYI": [undefined, undefined, 0], "UYU": [undefined, "$"], "UYW": [undefined, undefined, 4], "UZS": [undefined, undefined, 2], "VEF": [undefined, "Bs", 2], "VND": ["₫", undefined, 0], "VUV": [undefined, undefined, 0], "XAF": ["FCFA", undefined, 0], "XCD": ["EC$", "$"], "XOF": ["CFA", undefined, 0], "XPF": ["CFPF", undefined, 0], "XXX": ["¤"], "YER": [undefined, undefined, 0], "ZAR": [undefined, "R"], "ZMK": [undefined, undefined, 0], "ZMW": [undefined, "ZK"], "ZWD": [undefined, undefined, 0] };
816
817/**
818 * @license
819 * Copyright Google LLC All Rights Reserved.
820 *
821 * Use of this source code is governed by an MIT-style license that can be
822 * found in the LICENSE file at https://angular.io/license
823 */
824/**
825 * Format styles that can be used to represent numbers.
826 * @see `getLocaleNumberFormat()`.
827 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
828 *
829 * @publicApi
830 */
831var NumberFormatStyle;
832(function (NumberFormatStyle) {
833 NumberFormatStyle[NumberFormatStyle["Decimal"] = 0] = "Decimal";
834 NumberFormatStyle[NumberFormatStyle["Percent"] = 1] = "Percent";
835 NumberFormatStyle[NumberFormatStyle["Currency"] = 2] = "Currency";
836 NumberFormatStyle[NumberFormatStyle["Scientific"] = 3] = "Scientific";
837})(NumberFormatStyle || (NumberFormatStyle = {}));
838/**
839 * Plurality cases used for translating plurals to different languages.
840 *
841 * @see `NgPlural`
842 * @see `NgPluralCase`
843 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
844 *
845 * @publicApi
846 */
847var Plural;
848(function (Plural) {
849 Plural[Plural["Zero"] = 0] = "Zero";
850 Plural[Plural["One"] = 1] = "One";
851 Plural[Plural["Two"] = 2] = "Two";
852 Plural[Plural["Few"] = 3] = "Few";
853 Plural[Plural["Many"] = 4] = "Many";
854 Plural[Plural["Other"] = 5] = "Other";
855})(Plural || (Plural = {}));
856/**
857 * Context-dependant translation forms for strings.
858 * Typically the standalone version is for the nominative form of the word,
859 * and the format version is used for the genitive case.
860 * @see [CLDR website](http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles)
861 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
862 *
863 * @publicApi
864 */
865var FormStyle;
866(function (FormStyle) {
867 FormStyle[FormStyle["Format"] = 0] = "Format";
868 FormStyle[FormStyle["Standalone"] = 1] = "Standalone";
869})(FormStyle || (FormStyle = {}));
870/**
871 * String widths available for translations.
872 * The specific character widths are locale-specific.
873 * Examples are given for the word "Sunday" in English.
874 *
875 * @publicApi
876 */
877var TranslationWidth;
878(function (TranslationWidth) {
879 /** 1 character for `en-US`. For example: 'S' */
880 TranslationWidth[TranslationWidth["Narrow"] = 0] = "Narrow";
881 /** 3 characters for `en-US`. For example: 'Sun' */
882 TranslationWidth[TranslationWidth["Abbreviated"] = 1] = "Abbreviated";
883 /** Full length for `en-US`. For example: "Sunday" */
884 TranslationWidth[TranslationWidth["Wide"] = 2] = "Wide";
885 /** 2 characters for `en-US`, For example: "Su" */
886 TranslationWidth[TranslationWidth["Short"] = 3] = "Short";
887})(TranslationWidth || (TranslationWidth = {}));
888/**
889 * String widths available for date-time formats.
890 * The specific character widths are locale-specific.
891 * Examples are given for `en-US`.
892 *
893 * @see `getLocaleDateFormat()`
894 * @see `getLocaleTimeFormat()`
895 * @see `getLocaleDateTimeFormat()`
896 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
897 * @publicApi
898 */
899var FormatWidth;
900(function (FormatWidth) {
901 /**
902 * For `en-US`, 'M/d/yy, h:mm a'`
903 * (Example: `6/15/15, 9:03 AM`)
904 */
905 FormatWidth[FormatWidth["Short"] = 0] = "Short";
906 /**
907 * For `en-US`, `'MMM d, y, h:mm:ss a'`
908 * (Example: `Jun 15, 2015, 9:03:01 AM`)
909 */
910 FormatWidth[FormatWidth["Medium"] = 1] = "Medium";
911 /**
912 * For `en-US`, `'MMMM d, y, h:mm:ss a z'`
913 * (Example: `June 15, 2015 at 9:03:01 AM GMT+1`)
914 */
915 FormatWidth[FormatWidth["Long"] = 2] = "Long";
916 /**
917 * For `en-US`, `'EEEE, MMMM d, y, h:mm:ss a zzzz'`
918 * (Example: `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00`)
919 */
920 FormatWidth[FormatWidth["Full"] = 3] = "Full";
921})(FormatWidth || (FormatWidth = {}));
922/**
923 * Symbols that can be used to replace placeholders in number patterns.
924 * Examples are based on `en-US` values.
925 *
926 * @see `getLocaleNumberSymbol()`
927 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
928 *
929 * @publicApi
930 */
931var NumberSymbol;
932(function (NumberSymbol) {
933 /**
934 * Decimal separator.
935 * For `en-US`, the dot character.
936 * Example: 2,345`.`67
937 */
938 NumberSymbol[NumberSymbol["Decimal"] = 0] = "Decimal";
939 /**
940 * Grouping separator, typically for thousands.
941 * For `en-US`, the comma character.
942 * Example: 2`,`345.67
943 */
944 NumberSymbol[NumberSymbol["Group"] = 1] = "Group";
945 /**
946 * List-item separator.
947 * Example: "one, two, and three"
948 */
949 NumberSymbol[NumberSymbol["List"] = 2] = "List";
950 /**
951 * Sign for percentage (out of 100).
952 * Example: 23.4%
953 */
954 NumberSymbol[NumberSymbol["PercentSign"] = 3] = "PercentSign";
955 /**
956 * Sign for positive numbers.
957 * Example: +23
958 */
959 NumberSymbol[NumberSymbol["PlusSign"] = 4] = "PlusSign";
960 /**
961 * Sign for negative numbers.
962 * Example: -23
963 */
964 NumberSymbol[NumberSymbol["MinusSign"] = 5] = "MinusSign";
965 /**
966 * Computer notation for exponential value (n times a power of 10).
967 * Example: 1.2E3
968 */
969 NumberSymbol[NumberSymbol["Exponential"] = 6] = "Exponential";
970 /**
971 * Human-readable format of exponential.
972 * Example: 1.2x103
973 */
974 NumberSymbol[NumberSymbol["SuperscriptingExponent"] = 7] = "SuperscriptingExponent";
975 /**
976 * Sign for permille (out of 1000).
977 * Example: 23.4‰
978 */
979 NumberSymbol[NumberSymbol["PerMille"] = 8] = "PerMille";
980 /**
981 * Infinity, can be used with plus and minus.
982 * Example: ∞, +∞, -∞
983 */
984 NumberSymbol[NumberSymbol["Infinity"] = 9] = "Infinity";
985 /**
986 * Not a number.
987 * Example: NaN
988 */
989 NumberSymbol[NumberSymbol["NaN"] = 10] = "NaN";
990 /**
991 * Symbol used between time units.
992 * Example: 10:52
993 */
994 NumberSymbol[NumberSymbol["TimeSeparator"] = 11] = "TimeSeparator";
995 /**
996 * Decimal separator for currency values (fallback to `Decimal`).
997 * Example: $2,345.67
998 */
999 NumberSymbol[NumberSymbol["CurrencyDecimal"] = 12] = "CurrencyDecimal";
1000 /**
1001 * Group separator for currency values (fallback to `Group`).
1002 * Example: $2,345.67
1003 */
1004 NumberSymbol[NumberSymbol["CurrencyGroup"] = 13] = "CurrencyGroup";
1005})(NumberSymbol || (NumberSymbol = {}));
1006/**
1007 * The value for each day of the week, based on the `en-US` locale
1008 *
1009 * @publicApi
1010 */
1011var WeekDay;
1012(function (WeekDay) {
1013 WeekDay[WeekDay["Sunday"] = 0] = "Sunday";
1014 WeekDay[WeekDay["Monday"] = 1] = "Monday";
1015 WeekDay[WeekDay["Tuesday"] = 2] = "Tuesday";
1016 WeekDay[WeekDay["Wednesday"] = 3] = "Wednesday";
1017 WeekDay[WeekDay["Thursday"] = 4] = "Thursday";
1018 WeekDay[WeekDay["Friday"] = 5] = "Friday";
1019 WeekDay[WeekDay["Saturday"] = 6] = "Saturday";
1020})(WeekDay || (WeekDay = {}));
1021/**
1022 * Retrieves the locale ID from the currently loaded locale.
1023 * The loaded locale could be, for example, a global one rather than a regional one.
1024 * @param locale A locale code, such as `fr-FR`.
1025 * @returns The locale code. For example, `fr`.
1026 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1027 *
1028 * @publicApi
1029 */
1030function getLocaleId(locale) {
1031 return ɵfindLocaleData(locale)[ɵLocaleDataIndex.LocaleId];
1032}
1033/**
1034 * Retrieves day period strings for the given locale.
1035 *
1036 * @param locale A locale code for the locale format rules to use.
1037 * @param formStyle The required grammatical form.
1038 * @param width The required character width.
1039 * @returns An array of localized period strings. For example, `[AM, PM]` for `en-US`.
1040 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1041 *
1042 * @publicApi
1043 */
1044function getLocaleDayPeriods(locale, formStyle, width) {
1045 const data = ɵfindLocaleData(locale);
1046 const amPmData = [
1047 data[ɵLocaleDataIndex.DayPeriodsFormat], data[ɵLocaleDataIndex.DayPeriodsStandalone]
1048 ];
1049 const amPm = getLastDefinedValue(amPmData, formStyle);
1050 return getLastDefinedValue(amPm, width);
1051}
1052/**
1053 * Retrieves days of the week for the given locale, using the Gregorian calendar.
1054 *
1055 * @param locale A locale code for the locale format rules to use.
1056 * @param formStyle The required grammatical form.
1057 * @param width The required character width.
1058 * @returns An array of localized name strings.
1059 * For example,`[Sunday, Monday, ... Saturday]` for `en-US`.
1060 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1061 *
1062 * @publicApi
1063 */
1064function getLocaleDayNames(locale, formStyle, width) {
1065 const data = ɵfindLocaleData(locale);
1066 const daysData = [data[ɵLocaleDataIndex.DaysFormat], data[ɵLocaleDataIndex.DaysStandalone]];
1067 const days = getLastDefinedValue(daysData, formStyle);
1068 return getLastDefinedValue(days, width);
1069}
1070/**
1071 * Retrieves months of the year for the given locale, using the Gregorian calendar.
1072 *
1073 * @param locale A locale code for the locale format rules to use.
1074 * @param formStyle The required grammatical form.
1075 * @param width The required character width.
1076 * @returns An array of localized name strings.
1077 * For example, `[January, February, ...]` for `en-US`.
1078 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1079 *
1080 * @publicApi
1081 */
1082function getLocaleMonthNames(locale, formStyle, width) {
1083 const data = ɵfindLocaleData(locale);
1084 const monthsData = [data[ɵLocaleDataIndex.MonthsFormat], data[ɵLocaleDataIndex.MonthsStandalone]];
1085 const months = getLastDefinedValue(monthsData, formStyle);
1086 return getLastDefinedValue(months, width);
1087}
1088/**
1089 * Retrieves Gregorian-calendar eras for the given locale.
1090 * @param locale A locale code for the locale format rules to use.
1091 * @param width The required character width.
1092
1093 * @returns An array of localized era strings.
1094 * For example, `[AD, BC]` for `en-US`.
1095 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1096 *
1097 * @publicApi
1098 */
1099function getLocaleEraNames(locale, width) {
1100 const data = ɵfindLocaleData(locale);
1101 const erasData = data[ɵLocaleDataIndex.Eras];
1102 return getLastDefinedValue(erasData, width);
1103}
1104/**
1105 * Retrieves the first day of the week for the given locale.
1106 *
1107 * @param locale A locale code for the locale format rules to use.
1108 * @returns A day index number, using the 0-based week-day index for `en-US`
1109 * (Sunday = 0, Monday = 1, ...).
1110 * For example, for `fr-FR`, returns 1 to indicate that the first day is Monday.
1111 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1112 *
1113 * @publicApi
1114 */
1115function getLocaleFirstDayOfWeek(locale) {
1116 const data = ɵfindLocaleData(locale);
1117 return data[ɵLocaleDataIndex.FirstDayOfWeek];
1118}
1119/**
1120 * Range of week days that are considered the week-end for the given locale.
1121 *
1122 * @param locale A locale code for the locale format rules to use.
1123 * @returns The range of day values, `[startDay, endDay]`.
1124 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1125 *
1126 * @publicApi
1127 */
1128function getLocaleWeekEndRange(locale) {
1129 const data = ɵfindLocaleData(locale);
1130 return data[ɵLocaleDataIndex.WeekendRange];
1131}
1132/**
1133 * Retrieves a localized date-value formating string.
1134 *
1135 * @param locale A locale code for the locale format rules to use.
1136 * @param width The format type.
1137 * @returns The localized formating string.
1138 * @see `FormatWidth`
1139 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1140 *
1141 * @publicApi
1142 */
1143function getLocaleDateFormat(locale, width) {
1144 const data = ɵfindLocaleData(locale);
1145 return getLastDefinedValue(data[ɵLocaleDataIndex.DateFormat], width);
1146}
1147/**
1148 * Retrieves a localized time-value formatting string.
1149 *
1150 * @param locale A locale code for the locale format rules to use.
1151 * @param width The format type.
1152 * @returns The localized formatting string.
1153 * @see `FormatWidth`
1154 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1155
1156 * @publicApi
1157 */
1158function getLocaleTimeFormat(locale, width) {
1159 const data = ɵfindLocaleData(locale);
1160 return getLastDefinedValue(data[ɵLocaleDataIndex.TimeFormat], width);
1161}
1162/**
1163 * Retrieves a localized date-time formatting string.
1164 *
1165 * @param locale A locale code for the locale format rules to use.
1166 * @param width The format type.
1167 * @returns The localized formatting string.
1168 * @see `FormatWidth`
1169 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1170 *
1171 * @publicApi
1172 */
1173function getLocaleDateTimeFormat(locale, width) {
1174 const data = ɵfindLocaleData(locale);
1175 const dateTimeFormatData = data[ɵLocaleDataIndex.DateTimeFormat];
1176 return getLastDefinedValue(dateTimeFormatData, width);
1177}
1178/**
1179 * Retrieves a localized number symbol that can be used to replace placeholders in number formats.
1180 * @param locale The locale code.
1181 * @param symbol The symbol to localize.
1182 * @returns The character for the localized symbol.
1183 * @see `NumberSymbol`
1184 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1185 *
1186 * @publicApi
1187 */
1188function getLocaleNumberSymbol(locale, symbol) {
1189 const data = ɵfindLocaleData(locale);
1190 const res = data[ɵLocaleDataIndex.NumberSymbols][symbol];
1191 if (typeof res === 'undefined') {
1192 if (symbol === NumberSymbol.CurrencyDecimal) {
1193 return data[ɵLocaleDataIndex.NumberSymbols][NumberSymbol.Decimal];
1194 }
1195 else if (symbol === NumberSymbol.CurrencyGroup) {
1196 return data[ɵLocaleDataIndex.NumberSymbols][NumberSymbol.Group];
1197 }
1198 }
1199 return res;
1200}
1201/**
1202 * Retrieves a number format for a given locale.
1203 *
1204 * Numbers are formatted using patterns, like `#,###.00`. For example, the pattern `#,###.00`
1205 * when used to format the number 12345.678 could result in "12'345,678". That would happen if the
1206 * grouping separator for your language is an apostrophe, and the decimal separator is a comma.
1207 *
1208 * <b>Important:</b> The characters `.` `,` `0` `#` (and others below) are special placeholders
1209 * that stand for the decimal separator, and so on, and are NOT real characters.
1210 * You must NOT "translate" the placeholders. For example, don't change `.` to `,` even though in
1211 * your language the decimal point is written with a comma. The symbols should be replaced by the
1212 * local equivalents, using the appropriate `NumberSymbol` for your language.
1213 *
1214 * Here are the special characters used in number patterns:
1215 *
1216 * | Symbol | Meaning |
1217 * |--------|---------|
1218 * | . | Replaced automatically by the character used for the decimal point. |
1219 * | , | Replaced by the "grouping" (thousands) separator. |
1220 * | 0 | Replaced by a digit (or zero if there aren't enough digits). |
1221 * | # | Replaced by a digit (or nothing if there aren't enough). |
1222 * | ¤ | Replaced by a currency symbol, such as $ or USD. |
1223 * | % | Marks a percent format. The % symbol may change position, but must be retained. |
1224 * | E | Marks a scientific format. The E symbol may change position, but must be retained. |
1225 * | ' | Special characters used as literal characters are quoted with ASCII single quotes. |
1226 *
1227 * @param locale A locale code for the locale format rules to use.
1228 * @param type The type of numeric value to be formatted (such as `Decimal` or `Currency`.)
1229 * @returns The localized format string.
1230 * @see `NumberFormatStyle`
1231 * @see [CLDR website](http://cldr.unicode.org/translation/number-patterns)
1232 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1233 *
1234 * @publicApi
1235 */
1236function getLocaleNumberFormat(locale, type) {
1237 const data = ɵfindLocaleData(locale);
1238 return data[ɵLocaleDataIndex.NumberFormats][type];
1239}
1240/**
1241 * Retrieves the symbol used to represent the currency for the main country
1242 * corresponding to a given locale. For example, '$' for `en-US`.
1243 *
1244 * @param locale A locale code for the locale format rules to use.
1245 * @returns The localized symbol character,
1246 * or `null` if the main country cannot be determined.
1247 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1248 *
1249 * @publicApi
1250 */
1251function getLocaleCurrencySymbol(locale) {
1252 const data = ɵfindLocaleData(locale);
1253 return data[ɵLocaleDataIndex.CurrencySymbol] || null;
1254}
1255/**
1256 * Retrieves the name of the currency for the main country corresponding
1257 * to a given locale. For example, 'US Dollar' for `en-US`.
1258 * @param locale A locale code for the locale format rules to use.
1259 * @returns The currency name,
1260 * or `null` if the main country cannot be determined.
1261 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1262 *
1263 * @publicApi
1264 */
1265function getLocaleCurrencyName(locale) {
1266 const data = ɵfindLocaleData(locale);
1267 return data[ɵLocaleDataIndex.CurrencyName] || null;
1268}
1269/**
1270 * Retrieves the default currency code for the given locale.
1271 *
1272 * The default is defined as the first currency which is still in use.
1273 *
1274 * @param locale The code of the locale whose currency code we want.
1275 * @returns The code of the default currency for the given locale.
1276 *
1277 * @publicApi
1278 */
1279function getLocaleCurrencyCode(locale) {
1280 return ɵgetLocaleCurrencyCode(locale);
1281}
1282/**
1283 * Retrieves the currency values for a given locale.
1284 * @param locale A locale code for the locale format rules to use.
1285 * @returns The currency values.
1286 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1287 */
1288function getLocaleCurrencies(locale) {
1289 const data = ɵfindLocaleData(locale);
1290 return data[ɵLocaleDataIndex.Currencies];
1291}
1292/**
1293 * @alias core/ɵgetLocalePluralCase
1294 * @publicApi
1295 */
1296const getLocalePluralCase = ɵgetLocalePluralCase;
1297function checkFullData(data) {
1298 if (!data[ɵLocaleDataIndex.ExtraData]) {
1299 throw new Error(`Missing extra locale data for the locale "${data[ɵLocaleDataIndex
1300 .LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`);
1301 }
1302}
1303/**
1304 * Retrieves locale-specific rules used to determine which day period to use
1305 * when more than one period is defined for a locale.
1306 *
1307 * There is a rule for each defined day period. The
1308 * first rule is applied to the first day period and so on.
1309 * Fall back to AM/PM when no rules are available.
1310 *
1311 * A rule can specify a period as time range, or as a single time value.
1312 *
1313 * This functionality is only available when you have loaded the full locale data.
1314 * See the ["I18n guide"](guide/i18n-common-format-data-locale).
1315 *
1316 * @param locale A locale code for the locale format rules to use.
1317 * @returns The rules for the locale, a single time value or array of *from-time, to-time*,
1318 * or null if no periods are available.
1319 *
1320 * @see `getLocaleExtraDayPeriods()`
1321 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1322 *
1323 * @publicApi
1324 */
1325function getLocaleExtraDayPeriodRules(locale) {
1326 const data = ɵfindLocaleData(locale);
1327 checkFullData(data);
1328 const rules = data[ɵLocaleDataIndex.ExtraData][2 /* ExtraDayPeriodsRules */] || [];
1329 return rules.map((rule) => {
1330 if (typeof rule === 'string') {
1331 return extractTime(rule);
1332 }
1333 return [extractTime(rule[0]), extractTime(rule[1])];
1334 });
1335}
1336/**
1337 * Retrieves locale-specific day periods, which indicate roughly how a day is broken up
1338 * in different languages.
1339 * For example, for `en-US`, periods are morning, noon, afternoon, evening, and midnight.
1340 *
1341 * This functionality is only available when you have loaded the full locale data.
1342 * See the ["I18n guide"](guide/i18n-common-format-data-locale).
1343 *
1344 * @param locale A locale code for the locale format rules to use.
1345 * @param formStyle The required grammatical form.
1346 * @param width The required character width.
1347 * @returns The translated day-period strings.
1348 * @see `getLocaleExtraDayPeriodRules()`
1349 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1350 *
1351 * @publicApi
1352 */
1353function getLocaleExtraDayPeriods(locale, formStyle, width) {
1354 const data = ɵfindLocaleData(locale);
1355 checkFullData(data);
1356 const dayPeriodsData = [
1357 data[ɵLocaleDataIndex.ExtraData][0 /* ExtraDayPeriodFormats */],
1358 data[ɵLocaleDataIndex.ExtraData][1 /* ExtraDayPeriodStandalone */]
1359 ];
1360 const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || [];
1361 return getLastDefinedValue(dayPeriods, width) || [];
1362}
1363/**
1364 * Retrieves the writing direction of a specified locale
1365 * @param locale A locale code for the locale format rules to use.
1366 * @publicApi
1367 * @returns 'rtl' or 'ltr'
1368 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1369 */
1370function getLocaleDirection(locale) {
1371 const data = ɵfindLocaleData(locale);
1372 return data[ɵLocaleDataIndex.Directionality];
1373}
1374/**
1375 * Retrieves the first value that is defined in an array, going backwards from an index position.
1376 *
1377 * To avoid repeating the same data (as when the "format" and "standalone" forms are the same)
1378 * add the first value to the locale data arrays, and add other values only if they are different.
1379 *
1380 * @param data The data array to retrieve from.
1381 * @param index A 0-based index into the array to start from.
1382 * @returns The value immediately before the given index position.
1383 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1384 *
1385 * @publicApi
1386 */
1387function getLastDefinedValue(data, index) {
1388 for (let i = index; i > -1; i--) {
1389 if (typeof data[i] !== 'undefined') {
1390 return data[i];
1391 }
1392 }
1393 throw new Error('Locale data API: locale data undefined');
1394}
1395/**
1396 * Extracts the hours and minutes from a string like "15:45"
1397 */
1398function extractTime(time) {
1399 const [h, m] = time.split(':');
1400 return { hours: +h, minutes: +m };
1401}
1402/**
1403 * Retrieves the currency symbol for a given currency code.
1404 *
1405 * For example, for the default `en-US` locale, the code `USD` can
1406 * be represented by the narrow symbol `$` or the wide symbol `US$`.
1407 *
1408 * @param code The currency code.
1409 * @param format The format, `wide` or `narrow`.
1410 * @param locale A locale code for the locale format rules to use.
1411 *
1412 * @returns The symbol, or the currency code if no symbol is available.
1413 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1414 *
1415 * @publicApi
1416 */
1417function getCurrencySymbol(code, format, locale = 'en') {
1418 const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || [];
1419 const symbolNarrow = currency[1 /* SymbolNarrow */];
1420 if (format === 'narrow' && typeof symbolNarrow === 'string') {
1421 return symbolNarrow;
1422 }
1423 return currency[0 /* Symbol */] || code;
1424}
1425// Most currencies have cents, that's why the default is 2
1426const DEFAULT_NB_OF_CURRENCY_DIGITS = 2;
1427/**
1428 * Reports the number of decimal digits for a given currency.
1429 * The value depends upon the presence of cents in that particular currency.
1430 *
1431 * @param code The currency code.
1432 * @returns The number of decimal digits, typically 0 or 2.
1433 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1434 *
1435 * @publicApi
1436 */
1437function getNumberOfCurrencyDigits(code) {
1438 let digits;
1439 const currency = CURRENCIES_EN[code];
1440 if (currency) {
1441 digits = currency[2 /* NbOfDigits */];
1442 }
1443 return typeof digits === 'number' ? digits : DEFAULT_NB_OF_CURRENCY_DIGITS;
1444}
1445
1446/**
1447 * @license
1448 * Copyright Google LLC All Rights Reserved.
1449 *
1450 * Use of this source code is governed by an MIT-style license that can be
1451 * found in the LICENSE file at https://angular.io/license
1452 */
1453const ISO8601_DATE_REGEX = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
1454// 1 2 3 4 5 6 7 8 9 10 11
1455const NAMED_FORMATS = {};
1456const DATE_FORMATS_SPLIT = /((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;
1457var ZoneWidth;
1458(function (ZoneWidth) {
1459 ZoneWidth[ZoneWidth["Short"] = 0] = "Short";
1460 ZoneWidth[ZoneWidth["ShortGMT"] = 1] = "ShortGMT";
1461 ZoneWidth[ZoneWidth["Long"] = 2] = "Long";
1462 ZoneWidth[ZoneWidth["Extended"] = 3] = "Extended";
1463})(ZoneWidth || (ZoneWidth = {}));
1464var DateType;
1465(function (DateType) {
1466 DateType[DateType["FullYear"] = 0] = "FullYear";
1467 DateType[DateType["Month"] = 1] = "Month";
1468 DateType[DateType["Date"] = 2] = "Date";
1469 DateType[DateType["Hours"] = 3] = "Hours";
1470 DateType[DateType["Minutes"] = 4] = "Minutes";
1471 DateType[DateType["Seconds"] = 5] = "Seconds";
1472 DateType[DateType["FractionalSeconds"] = 6] = "FractionalSeconds";
1473 DateType[DateType["Day"] = 7] = "Day";
1474})(DateType || (DateType = {}));
1475var TranslationType;
1476(function (TranslationType) {
1477 TranslationType[TranslationType["DayPeriods"] = 0] = "DayPeriods";
1478 TranslationType[TranslationType["Days"] = 1] = "Days";
1479 TranslationType[TranslationType["Months"] = 2] = "Months";
1480 TranslationType[TranslationType["Eras"] = 3] = "Eras";
1481})(TranslationType || (TranslationType = {}));
1482/**
1483 * @ngModule CommonModule
1484 * @description
1485 *
1486 * Formats a date according to locale rules.
1487 *
1488 * @param value The date to format, as a Date, or a number (milliseconds since UTC epoch)
1489 * or an [ISO date-time string](https://www.w3.org/TR/NOTE-datetime).
1490 * @param format The date-time components to include. See `DatePipe` for details.
1491 * @param locale A locale code for the locale format rules to use.
1492 * @param timezone The time zone. A time zone offset from GMT (such as `'+0430'`),
1493 * or a standard UTC/GMT or continental US time zone abbreviation.
1494 * If not specified, uses host system settings.
1495 *
1496 * @returns The formatted date string.
1497 *
1498 * @see `DatePipe`
1499 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
1500 *
1501 * @publicApi
1502 */
1503function formatDate(value, format, locale, timezone) {
1504 let date = toDate(value);
1505 const namedFormat = getNamedFormat(locale, format);
1506 format = namedFormat || format;
1507 let parts = [];
1508 let match;
1509 while (format) {
1510 match = DATE_FORMATS_SPLIT.exec(format);
1511 if (match) {
1512 parts = parts.concat(match.slice(1));
1513 const part = parts.pop();
1514 if (!part) {
1515 break;
1516 }
1517 format = part;
1518 }
1519 else {
1520 parts.push(format);
1521 break;
1522 }
1523 }
1524 let dateTimezoneOffset = date.getTimezoneOffset();
1525 if (timezone) {
1526 dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
1527 date = convertTimezoneToLocal(date, timezone, true);
1528 }
1529 let text = '';
1530 parts.forEach(value => {
1531 const dateFormatter = getDateFormatter(value);
1532 text += dateFormatter ?
1533 dateFormatter(date, locale, dateTimezoneOffset) :
1534 value === '\'\'' ? '\'' : value.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
1535 });
1536 return text;
1537}
1538/**
1539 * Create a new Date object with the given date value, and the time set to midnight.
1540 *
1541 * We cannot use `new Date(year, month, date)` because it maps years between 0 and 99 to 1900-1999.
1542 * See: https://github.com/angular/angular/issues/40377
1543 *
1544 * Note that this function returns a Date object whose time is midnight in the current locale's
1545 * timezone. In the future we might want to change this to be midnight in UTC, but this would be a
1546 * considerable breaking change.
1547 */
1548function createDate(year, month, date) {
1549 // The `newDate` is set to midnight (UTC) on January 1st 1970.
1550 // - In PST this will be December 31st 1969 at 4pm.
1551 // - In GMT this will be January 1st 1970 at 1am.
1552 // Note that they even have different years, dates and months!
1553 const newDate = new Date(0);
1554 // `setFullYear()` allows years like 0001 to be set correctly. This function does not
1555 // change the internal time of the date.
1556 // Consider calling `setFullYear(2019, 8, 20)` (September 20, 2019).
1557 // - In PST this will now be September 20, 2019 at 4pm
1558 // - In GMT this will now be September 20, 2019 at 1am
1559 newDate.setFullYear(year, month, date);
1560 // We want the final date to be at local midnight, so we reset the time.
1561 // - In PST this will now be September 20, 2019 at 12am
1562 // - In GMT this will now be September 20, 2019 at 12am
1563 newDate.setHours(0, 0, 0);
1564 return newDate;
1565}
1566function getNamedFormat(locale, format) {
1567 const localeId = getLocaleId(locale);
1568 NAMED_FORMATS[localeId] = NAMED_FORMATS[localeId] || {};
1569 if (NAMED_FORMATS[localeId][format]) {
1570 return NAMED_FORMATS[localeId][format];
1571 }
1572 let formatValue = '';
1573 switch (format) {
1574 case 'shortDate':
1575 formatValue = getLocaleDateFormat(locale, FormatWidth.Short);
1576 break;
1577 case 'mediumDate':
1578 formatValue = getLocaleDateFormat(locale, FormatWidth.Medium);
1579 break;
1580 case 'longDate':
1581 formatValue = getLocaleDateFormat(locale, FormatWidth.Long);
1582 break;
1583 case 'fullDate':
1584 formatValue = getLocaleDateFormat(locale, FormatWidth.Full);
1585 break;
1586 case 'shortTime':
1587 formatValue = getLocaleTimeFormat(locale, FormatWidth.Short);
1588 break;
1589 case 'mediumTime':
1590 formatValue = getLocaleTimeFormat(locale, FormatWidth.Medium);
1591 break;
1592 case 'longTime':
1593 formatValue = getLocaleTimeFormat(locale, FormatWidth.Long);
1594 break;
1595 case 'fullTime':
1596 formatValue = getLocaleTimeFormat(locale, FormatWidth.Full);
1597 break;
1598 case 'short':
1599 const shortTime = getNamedFormat(locale, 'shortTime');
1600 const shortDate = getNamedFormat(locale, 'shortDate');
1601 formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Short), [shortTime, shortDate]);
1602 break;
1603 case 'medium':
1604 const mediumTime = getNamedFormat(locale, 'mediumTime');
1605 const mediumDate = getNamedFormat(locale, 'mediumDate');
1606 formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Medium), [mediumTime, mediumDate]);
1607 break;
1608 case 'long':
1609 const longTime = getNamedFormat(locale, 'longTime');
1610 const longDate = getNamedFormat(locale, 'longDate');
1611 formatValue =
1612 formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Long), [longTime, longDate]);
1613 break;
1614 case 'full':
1615 const fullTime = getNamedFormat(locale, 'fullTime');
1616 const fullDate = getNamedFormat(locale, 'fullDate');
1617 formatValue =
1618 formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Full), [fullTime, fullDate]);
1619 break;
1620 }
1621 if (formatValue) {
1622 NAMED_FORMATS[localeId][format] = formatValue;
1623 }
1624 return formatValue;
1625}
1626function formatDateTime(str, opt_values) {
1627 if (opt_values) {
1628 str = str.replace(/\{([^}]+)}/g, function (match, key) {
1629 return (opt_values != null && key in opt_values) ? opt_values[key] : match;
1630 });
1631 }
1632 return str;
1633}
1634function padNumber(num, digits, minusSign = '-', trim, negWrap) {
1635 let neg = '';
1636 if (num < 0 || (negWrap && num <= 0)) {
1637 if (negWrap) {
1638 num = -num + 1;
1639 }
1640 else {
1641 num = -num;
1642 neg = minusSign;
1643 }
1644 }
1645 let strNum = String(num);
1646 while (strNum.length < digits) {
1647 strNum = '0' + strNum;
1648 }
1649 if (trim) {
1650 strNum = strNum.substr(strNum.length - digits);
1651 }
1652 return neg + strNum;
1653}
1654function formatFractionalSeconds(milliseconds, digits) {
1655 const strMs = padNumber(milliseconds, 3);
1656 return strMs.substr(0, digits);
1657}
1658/**
1659 * Returns a date formatter that transforms a date into its locale digit representation
1660 */
1661function dateGetter(name, size, offset = 0, trim = false, negWrap = false) {
1662 return function (date, locale) {
1663 let part = getDatePart(name, date);
1664 if (offset > 0 || part > -offset) {
1665 part += offset;
1666 }
1667 if (name === DateType.Hours) {
1668 if (part === 0 && offset === -12) {
1669 part = 12;
1670 }
1671 }
1672 else if (name === DateType.FractionalSeconds) {
1673 return formatFractionalSeconds(part, size);
1674 }
1675 const localeMinus = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);
1676 return padNumber(part, size, localeMinus, trim, negWrap);
1677 };
1678}
1679function getDatePart(part, date) {
1680 switch (part) {
1681 case DateType.FullYear:
1682 return date.getFullYear();
1683 case DateType.Month:
1684 return date.getMonth();
1685 case DateType.Date:
1686 return date.getDate();
1687 case DateType.Hours:
1688 return date.getHours();
1689 case DateType.Minutes:
1690 return date.getMinutes();
1691 case DateType.Seconds:
1692 return date.getSeconds();
1693 case DateType.FractionalSeconds:
1694 return date.getMilliseconds();
1695 case DateType.Day:
1696 return date.getDay();
1697 default:
1698 throw new Error(`Unknown DateType value "${part}".`);
1699 }
1700}
1701/**
1702 * Returns a date formatter that transforms a date into its locale string representation
1703 */
1704function dateStrGetter(name, width, form = FormStyle.Format, extended = false) {
1705 return function (date, locale) {
1706 return getDateTranslation(date, locale, name, width, form, extended);
1707 };
1708}
1709/**
1710 * Returns the locale translation of a date for a given form, type and width
1711 */
1712function getDateTranslation(date, locale, name, width, form, extended) {
1713 switch (name) {
1714 case TranslationType.Months:
1715 return getLocaleMonthNames(locale, form, width)[date.getMonth()];
1716 case TranslationType.Days:
1717 return getLocaleDayNames(locale, form, width)[date.getDay()];
1718 case TranslationType.DayPeriods:
1719 const currentHours = date.getHours();
1720 const currentMinutes = date.getMinutes();
1721 if (extended) {
1722 const rules = getLocaleExtraDayPeriodRules(locale);
1723 const dayPeriods = getLocaleExtraDayPeriods(locale, form, width);
1724 const index = rules.findIndex(rule => {
1725 if (Array.isArray(rule)) {
1726 // morning, afternoon, evening, night
1727 const [from, to] = rule;
1728 const afterFrom = currentHours >= from.hours && currentMinutes >= from.minutes;
1729 const beforeTo = (currentHours < to.hours ||
1730 (currentHours === to.hours && currentMinutes < to.minutes));
1731 // We must account for normal rules that span a period during the day (e.g. 6am-9am)
1732 // where `from` is less (earlier) than `to`. But also rules that span midnight (e.g.
1733 // 10pm - 5am) where `from` is greater (later!) than `to`.
1734 //
1735 // In the first case the current time must be BOTH after `from` AND before `to`
1736 // (e.g. 8am is after 6am AND before 10am).
1737 //
1738 // In the second case the current time must be EITHER after `from` OR before `to`
1739 // (e.g. 4am is before 5am but not after 10pm; and 11pm is not before 5am but it is
1740 // after 10pm).
1741 if (from.hours < to.hours) {
1742 if (afterFrom && beforeTo) {
1743 return true;
1744 }
1745 }
1746 else if (afterFrom || beforeTo) {
1747 return true;
1748 }
1749 }
1750 else { // noon or midnight
1751 if (rule.hours === currentHours && rule.minutes === currentMinutes) {
1752 return true;
1753 }
1754 }
1755 return false;
1756 });
1757 if (index !== -1) {
1758 return dayPeriods[index];
1759 }
1760 }
1761 // if no rules for the day periods, we use am/pm by default
1762 return getLocaleDayPeriods(locale, form, width)[currentHours < 12 ? 0 : 1];
1763 case TranslationType.Eras:
1764 return getLocaleEraNames(locale, width)[date.getFullYear() <= 0 ? 0 : 1];
1765 default:
1766 // This default case is not needed by TypeScript compiler, as the switch is exhaustive.
1767 // However Closure Compiler does not understand that and reports an error in typed mode.
1768 // The `throw new Error` below works around the problem, and the unexpected: never variable
1769 // makes sure tsc still checks this code is unreachable.
1770 const unexpected = name;
1771 throw new Error(`unexpected translation type ${unexpected}`);
1772 }
1773}
1774/**
1775 * Returns a date formatter that transforms a date and an offset into a timezone with ISO8601 or
1776 * GMT format depending on the width (eg: short = +0430, short:GMT = GMT+4, long = GMT+04:30,
1777 * extended = +04:30)
1778 */
1779function timeZoneGetter(width) {
1780 return function (date, locale, offset) {
1781 const zone = -1 * offset;
1782 const minusSign = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);
1783 const hours = zone > 0 ? Math.floor(zone / 60) : Math.ceil(zone / 60);
1784 switch (width) {
1785 case ZoneWidth.Short:
1786 return ((zone >= 0) ? '+' : '') + padNumber(hours, 2, minusSign) +
1787 padNumber(Math.abs(zone % 60), 2, minusSign);
1788 case ZoneWidth.ShortGMT:
1789 return 'GMT' + ((zone >= 0) ? '+' : '') + padNumber(hours, 1, minusSign);
1790 case ZoneWidth.Long:
1791 return 'GMT' + ((zone >= 0) ? '+' : '') + padNumber(hours, 2, minusSign) + ':' +
1792 padNumber(Math.abs(zone % 60), 2, minusSign);
1793 case ZoneWidth.Extended:
1794 if (offset === 0) {
1795 return 'Z';
1796 }
1797 else {
1798 return ((zone >= 0) ? '+' : '') + padNumber(hours, 2, minusSign) + ':' +
1799 padNumber(Math.abs(zone % 60), 2, minusSign);
1800 }
1801 default:
1802 throw new Error(`Unknown zone width "${width}"`);
1803 }
1804 };
1805}
1806const JANUARY = 0;
1807const THURSDAY = 4;
1808function getFirstThursdayOfYear(year) {
1809 const firstDayOfYear = createDate(year, JANUARY, 1).getDay();
1810 return createDate(year, 0, 1 + ((firstDayOfYear <= THURSDAY) ? THURSDAY : THURSDAY + 7) - firstDayOfYear);
1811}
1812function getThursdayThisWeek(datetime) {
1813 return createDate(datetime.getFullYear(), datetime.getMonth(), datetime.getDate() + (THURSDAY - datetime.getDay()));
1814}
1815function weekGetter(size, monthBased = false) {
1816 return function (date, locale) {
1817 let result;
1818 if (monthBased) {
1819 const nbDaysBefore1stDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1).getDay() - 1;
1820 const today = date.getDate();
1821 result = 1 + Math.floor((today + nbDaysBefore1stDayOfMonth) / 7);
1822 }
1823 else {
1824 const thisThurs = getThursdayThisWeek(date);
1825 // Some days of a year are part of next year according to ISO 8601.
1826 // Compute the firstThurs from the year of this week's Thursday
1827 const firstThurs = getFirstThursdayOfYear(thisThurs.getFullYear());
1828 const diff = thisThurs.getTime() - firstThurs.getTime();
1829 result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
1830 }
1831 return padNumber(result, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
1832 };
1833}
1834/**
1835 * Returns a date formatter that provides the week-numbering year for the input date.
1836 */
1837function weekNumberingYearGetter(size, trim = false) {
1838 return function (date, locale) {
1839 const thisThurs = getThursdayThisWeek(date);
1840 const weekNumberingYear = thisThurs.getFullYear();
1841 return padNumber(weekNumberingYear, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign), trim);
1842 };
1843}
1844const DATE_FORMATS = {};
1845// Based on CLDR formats:
1846// See complete list: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
1847// See also explanations: http://cldr.unicode.org/translation/date-time
1848// TODO(ocombe): support all missing cldr formats: U, Q, D, F, e, j, J, C, A, v, V, X, x
1849function getDateFormatter(format) {
1850 if (DATE_FORMATS[format]) {
1851 return DATE_FORMATS[format];
1852 }
1853 let formatter;
1854 switch (format) {
1855 // Era name (AD/BC)
1856 case 'G':
1857 case 'GG':
1858 case 'GGG':
1859 formatter = dateStrGetter(TranslationType.Eras, TranslationWidth.Abbreviated);
1860 break;
1861 case 'GGGG':
1862 formatter = dateStrGetter(TranslationType.Eras, TranslationWidth.Wide);
1863 break;
1864 case 'GGGGG':
1865 formatter = dateStrGetter(TranslationType.Eras, TranslationWidth.Narrow);
1866 break;
1867 // 1 digit representation of the year, e.g. (AD 1 => 1, AD 199 => 199)
1868 case 'y':
1869 formatter = dateGetter(DateType.FullYear, 1, 0, false, true);
1870 break;
1871 // 2 digit representation of the year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
1872 case 'yy':
1873 formatter = dateGetter(DateType.FullYear, 2, 0, true, true);
1874 break;
1875 // 3 digit representation of the year, padded (000-999). (e.g. AD 2001 => 01, AD 2010 => 10)
1876 case 'yyy':
1877 formatter = dateGetter(DateType.FullYear, 3, 0, false, true);
1878 break;
1879 // 4 digit representation of the year (e.g. AD 1 => 0001, AD 2010 => 2010)
1880 case 'yyyy':
1881 formatter = dateGetter(DateType.FullYear, 4, 0, false, true);
1882 break;
1883 // 1 digit representation of the week-numbering year, e.g. (AD 1 => 1, AD 199 => 199)
1884 case 'Y':
1885 formatter = weekNumberingYearGetter(1);
1886 break;
1887 // 2 digit representation of the week-numbering year, padded (00-99). (e.g. AD 2001 => 01, AD
1888 // 2010 => 10)
1889 case 'YY':
1890 formatter = weekNumberingYearGetter(2, true);
1891 break;
1892 // 3 digit representation of the week-numbering year, padded (000-999). (e.g. AD 1 => 001, AD
1893 // 2010 => 2010)
1894 case 'YYY':
1895 formatter = weekNumberingYearGetter(3);
1896 break;
1897 // 4 digit representation of the week-numbering year (e.g. AD 1 => 0001, AD 2010 => 2010)
1898 case 'YYYY':
1899 formatter = weekNumberingYearGetter(4);
1900 break;
1901 // Month of the year (1-12), numeric
1902 case 'M':
1903 case 'L':
1904 formatter = dateGetter(DateType.Month, 1, 1);
1905 break;
1906 case 'MM':
1907 case 'LL':
1908 formatter = dateGetter(DateType.Month, 2, 1);
1909 break;
1910 // Month of the year (January, ...), string, format
1911 case 'MMM':
1912 formatter = dateStrGetter(TranslationType.Months, TranslationWidth.Abbreviated);
1913 break;
1914 case 'MMMM':
1915 formatter = dateStrGetter(TranslationType.Months, TranslationWidth.Wide);
1916 break;
1917 case 'MMMMM':
1918 formatter = dateStrGetter(TranslationType.Months, TranslationWidth.Narrow);
1919 break;
1920 // Month of the year (January, ...), string, standalone
1921 case 'LLL':
1922 formatter =
1923 dateStrGetter(TranslationType.Months, TranslationWidth.Abbreviated, FormStyle.Standalone);
1924 break;
1925 case 'LLLL':
1926 formatter =
1927 dateStrGetter(TranslationType.Months, TranslationWidth.Wide, FormStyle.Standalone);
1928 break;
1929 case 'LLLLL':
1930 formatter =
1931 dateStrGetter(TranslationType.Months, TranslationWidth.Narrow, FormStyle.Standalone);
1932 break;
1933 // Week of the year (1, ... 52)
1934 case 'w':
1935 formatter = weekGetter(1);
1936 break;
1937 case 'ww':
1938 formatter = weekGetter(2);
1939 break;
1940 // Week of the month (1, ...)
1941 case 'W':
1942 formatter = weekGetter(1, true);
1943 break;
1944 // Day of the month (1-31)
1945 case 'd':
1946 formatter = dateGetter(DateType.Date, 1);
1947 break;
1948 case 'dd':
1949 formatter = dateGetter(DateType.Date, 2);
1950 break;
1951 // Day of the Week StandAlone (1, 1, Mon, Monday, M, Mo)
1952 case 'c':
1953 case 'cc':
1954 formatter = dateGetter(DateType.Day, 1);
1955 break;
1956 case 'ccc':
1957 formatter =
1958 dateStrGetter(TranslationType.Days, TranslationWidth.Abbreviated, FormStyle.Standalone);
1959 break;
1960 case 'cccc':
1961 formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Wide, FormStyle.Standalone);
1962 break;
1963 case 'ccccc':
1964 formatter =
1965 dateStrGetter(TranslationType.Days, TranslationWidth.Narrow, FormStyle.Standalone);
1966 break;
1967 case 'cccccc':
1968 formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Short, FormStyle.Standalone);
1969 break;
1970 // Day of the Week
1971 case 'E':
1972 case 'EE':
1973 case 'EEE':
1974 formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Abbreviated);
1975 break;
1976 case 'EEEE':
1977 formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Wide);
1978 break;
1979 case 'EEEEE':
1980 formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Narrow);
1981 break;
1982 case 'EEEEEE':
1983 formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Short);
1984 break;
1985 // Generic period of the day (am-pm)
1986 case 'a':
1987 case 'aa':
1988 case 'aaa':
1989 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Abbreviated);
1990 break;
1991 case 'aaaa':
1992 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Wide);
1993 break;
1994 case 'aaaaa':
1995 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Narrow);
1996 break;
1997 // Extended period of the day (midnight, at night, ...), standalone
1998 case 'b':
1999 case 'bb':
2000 case 'bbb':
2001 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Abbreviated, FormStyle.Standalone, true);
2002 break;
2003 case 'bbbb':
2004 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Wide, FormStyle.Standalone, true);
2005 break;
2006 case 'bbbbb':
2007 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Narrow, FormStyle.Standalone, true);
2008 break;
2009 // Extended period of the day (midnight, night, ...), standalone
2010 case 'B':
2011 case 'BB':
2012 case 'BBB':
2013 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Abbreviated, FormStyle.Format, true);
2014 break;
2015 case 'BBBB':
2016 formatter =
2017 dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Wide, FormStyle.Format, true);
2018 break;
2019 case 'BBBBB':
2020 formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Narrow, FormStyle.Format, true);
2021 break;
2022 // Hour in AM/PM, (1-12)
2023 case 'h':
2024 formatter = dateGetter(DateType.Hours, 1, -12);
2025 break;
2026 case 'hh':
2027 formatter = dateGetter(DateType.Hours, 2, -12);
2028 break;
2029 // Hour of the day (0-23)
2030 case 'H':
2031 formatter = dateGetter(DateType.Hours, 1);
2032 break;
2033 // Hour in day, padded (00-23)
2034 case 'HH':
2035 formatter = dateGetter(DateType.Hours, 2);
2036 break;
2037 // Minute of the hour (0-59)
2038 case 'm':
2039 formatter = dateGetter(DateType.Minutes, 1);
2040 break;
2041 case 'mm':
2042 formatter = dateGetter(DateType.Minutes, 2);
2043 break;
2044 // Second of the minute (0-59)
2045 case 's':
2046 formatter = dateGetter(DateType.Seconds, 1);
2047 break;
2048 case 'ss':
2049 formatter = dateGetter(DateType.Seconds, 2);
2050 break;
2051 // Fractional second
2052 case 'S':
2053 formatter = dateGetter(DateType.FractionalSeconds, 1);
2054 break;
2055 case 'SS':
2056 formatter = dateGetter(DateType.FractionalSeconds, 2);
2057 break;
2058 case 'SSS':
2059 formatter = dateGetter(DateType.FractionalSeconds, 3);
2060 break;
2061 // Timezone ISO8601 short format (-0430)
2062 case 'Z':
2063 case 'ZZ':
2064 case 'ZZZ':
2065 formatter = timeZoneGetter(ZoneWidth.Short);
2066 break;
2067 // Timezone ISO8601 extended format (-04:30)
2068 case 'ZZZZZ':
2069 formatter = timeZoneGetter(ZoneWidth.Extended);
2070 break;
2071 // Timezone GMT short format (GMT+4)
2072 case 'O':
2073 case 'OO':
2074 case 'OOO':
2075 // Should be location, but fallback to format O instead because we don't have the data yet
2076 case 'z':
2077 case 'zz':
2078 case 'zzz':
2079 formatter = timeZoneGetter(ZoneWidth.ShortGMT);
2080 break;
2081 // Timezone GMT long format (GMT+0430)
2082 case 'OOOO':
2083 case 'ZZZZ':
2084 // Should be location, but fallback to format O instead because we don't have the data yet
2085 case 'zzzz':
2086 formatter = timeZoneGetter(ZoneWidth.Long);
2087 break;
2088 default:
2089 return null;
2090 }
2091 DATE_FORMATS[format] = formatter;
2092 return formatter;
2093}
2094function timezoneToOffset(timezone, fallback) {
2095 // Support: IE 11 only, Edge 13-15+
2096 // IE/Edge do not "understand" colon (`:`) in timezone
2097 timezone = timezone.replace(/:/g, '');
2098 const requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
2099 return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
2100}
2101function addDateMinutes(date, minutes) {
2102 date = new Date(date.getTime());
2103 date.setMinutes(date.getMinutes() + minutes);
2104 return date;
2105}
2106function convertTimezoneToLocal(date, timezone, reverse) {
2107 const reverseValue = reverse ? -1 : 1;
2108 const dateTimezoneOffset = date.getTimezoneOffset();
2109 const timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
2110 return addDateMinutes(date, reverseValue * (timezoneOffset - dateTimezoneOffset));
2111}
2112/**
2113 * Converts a value to date.
2114 *
2115 * Supported input formats:
2116 * - `Date`
2117 * - number: timestamp
2118 * - string: numeric (e.g. "1234"), ISO and date strings in a format supported by
2119 * [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse).
2120 * Note: ISO strings without time return a date without timeoffset.
2121 *
2122 * Throws if unable to convert to a date.
2123 */
2124function toDate(value) {
2125 if (isDate(value)) {
2126 return value;
2127 }
2128 if (typeof value === 'number' && !isNaN(value)) {
2129 return new Date(value);
2130 }
2131 if (typeof value === 'string') {
2132 value = value.trim();
2133 if (/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(value)) {
2134 /* For ISO Strings without time the day, month and year must be extracted from the ISO String
2135 before Date creation to avoid time offset and errors in the new Date.
2136 If we only replace '-' with ',' in the ISO String ("2015,01,01"), and try to create a new
2137 date, some browsers (e.g. IE 9) will throw an invalid Date error.
2138 If we leave the '-' ("2015-01-01") and try to create a new Date("2015-01-01") the timeoffset
2139 is applied.
2140 Note: ISO months are 0 for January, 1 for February, ... */
2141 const [y, m = 1, d = 1] = value.split('-').map((val) => +val);
2142 return createDate(y, m - 1, d);
2143 }
2144 const parsedNb = parseFloat(value);
2145 // any string that only contains numbers, like "1234" but not like "1234hello"
2146 if (!isNaN(value - parsedNb)) {
2147 return new Date(parsedNb);
2148 }
2149 let match;
2150 if (match = value.match(ISO8601_DATE_REGEX)) {
2151 return isoStringToDate(match);
2152 }
2153 }
2154 const date = new Date(value);
2155 if (!isDate(date)) {
2156 throw new Error(`Unable to convert "${value}" into a date`);
2157 }
2158 return date;
2159}
2160/**
2161 * Converts a date in ISO8601 to a Date.
2162 * Used instead of `Date.parse` because of browser discrepancies.
2163 */
2164function isoStringToDate(match) {
2165 const date = new Date(0);
2166 let tzHour = 0;
2167 let tzMin = 0;
2168 // match[8] means that the string contains "Z" (UTC) or a timezone like "+01:00" or "+0100"
2169 const dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear;
2170 const timeSetter = match[8] ? date.setUTCHours : date.setHours;
2171 // if there is a timezone defined like "+01:00" or "+0100"
2172 if (match[9]) {
2173 tzHour = Number(match[9] + match[10]);
2174 tzMin = Number(match[9] + match[11]);
2175 }
2176 dateSetter.call(date, Number(match[1]), Number(match[2]) - 1, Number(match[3]));
2177 const h = Number(match[4] || 0) - tzHour;
2178 const m = Number(match[5] || 0) - tzMin;
2179 const s = Number(match[6] || 0);
2180 // The ECMAScript specification (https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.11)
2181 // defines that `DateTime` milliseconds should always be rounded down, so that `999.9ms`
2182 // becomes `999ms`.
2183 const ms = Math.floor(parseFloat('0.' + (match[7] || 0)) * 1000);
2184 timeSetter.call(date, h, m, s, ms);
2185 return date;
2186}
2187function isDate(value) {
2188 return value instanceof Date && !isNaN(value.valueOf());
2189}
2190
2191/**
2192 * @license
2193 * Copyright Google LLC All Rights Reserved.
2194 *
2195 * Use of this source code is governed by an MIT-style license that can be
2196 * found in the LICENSE file at https://angular.io/license
2197 */
2198const NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
2199const MAX_DIGITS = 22;
2200const DECIMAL_SEP = '.';
2201const ZERO_CHAR = '0';
2202const PATTERN_SEP = ';';
2203const GROUP_SEP = ',';
2204const DIGIT_CHAR = '#';
2205const CURRENCY_CHAR = '¤';
2206const PERCENT_CHAR = '%';
2207/**
2208 * Transforms a number to a locale string based on a style and a format.
2209 */
2210function formatNumberToLocaleString(value, pattern, locale, groupSymbol, decimalSymbol, digitsInfo, isPercent = false) {
2211 let formattedText = '';
2212 let isZero = false;
2213 if (!isFinite(value)) {
2214 formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity);
2215 }
2216 else {
2217 let parsedNumber = parseNumber(value);
2218 if (isPercent) {
2219 parsedNumber = toPercent(parsedNumber);
2220 }
2221 let minInt = pattern.minInt;
2222 let minFraction = pattern.minFrac;
2223 let maxFraction = pattern.maxFrac;
2224 if (digitsInfo) {
2225 const parts = digitsInfo.match(NUMBER_FORMAT_REGEXP);
2226 if (parts === null) {
2227 throw new Error(`${digitsInfo} is not a valid digit info`);
2228 }
2229 const minIntPart = parts[1];
2230 const minFractionPart = parts[3];
2231 const maxFractionPart = parts[5];
2232 if (minIntPart != null) {
2233 minInt = parseIntAutoRadix(minIntPart);
2234 }
2235 if (minFractionPart != null) {
2236 minFraction = parseIntAutoRadix(minFractionPart);
2237 }
2238 if (maxFractionPart != null) {
2239 maxFraction = parseIntAutoRadix(maxFractionPart);
2240 }
2241 else if (minFractionPart != null && minFraction > maxFraction) {
2242 maxFraction = minFraction;
2243 }
2244 }
2245 roundNumber(parsedNumber, minFraction, maxFraction);
2246 let digits = parsedNumber.digits;
2247 let integerLen = parsedNumber.integerLen;
2248 const exponent = parsedNumber.exponent;
2249 let decimals = [];
2250 isZero = digits.every(d => !d);
2251 // pad zeros for small numbers
2252 for (; integerLen < minInt; integerLen++) {
2253 digits.unshift(0);
2254 }
2255 // pad zeros for small numbers
2256 for (; integerLen < 0; integerLen++) {
2257 digits.unshift(0);
2258 }
2259 // extract decimals digits
2260 if (integerLen > 0) {
2261 decimals = digits.splice(integerLen, digits.length);
2262 }
2263 else {
2264 decimals = digits;
2265 digits = [0];
2266 }
2267 // format the integer digits with grouping separators
2268 const groups = [];
2269 if (digits.length >= pattern.lgSize) {
2270 groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
2271 }
2272 while (digits.length > pattern.gSize) {
2273 groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
2274 }
2275 if (digits.length) {
2276 groups.unshift(digits.join(''));
2277 }
2278 formattedText = groups.join(getLocaleNumberSymbol(locale, groupSymbol));
2279 // append the decimal digits
2280 if (decimals.length) {
2281 formattedText += getLocaleNumberSymbol(locale, decimalSymbol) + decimals.join('');
2282 }
2283 if (exponent) {
2284 formattedText += getLocaleNumberSymbol(locale, NumberSymbol.Exponential) + '+' + exponent;
2285 }
2286 }
2287 if (value < 0 && !isZero) {
2288 formattedText = pattern.negPre + formattedText + pattern.negSuf;
2289 }
2290 else {
2291 formattedText = pattern.posPre + formattedText + pattern.posSuf;
2292 }
2293 return formattedText;
2294}
2295/**
2296 * @ngModule CommonModule
2297 * @description
2298 *
2299 * Formats a number as currency using locale rules.
2300 *
2301 * @param value The number to format.
2302 * @param locale A locale code for the locale format rules to use.
2303 * @param currency A string containing the currency symbol or its name,
2304 * such as "$" or "Canadian Dollar". Used in output string, but does not affect the operation
2305 * of the function.
2306 * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217)
2307 * currency code, such as `USD` for the US dollar and `EUR` for the euro.
2308 * Used to determine the number of digits in the decimal part.
2309 * @param digitsInfo Decimal representation options, specified by a string in the following format:
2310 * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details.
2311 *
2312 * @returns The formatted currency value.
2313 *
2314 * @see `formatNumber()`
2315 * @see `DecimalPipe`
2316 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
2317 *
2318 * @publicApi
2319 */
2320function formatCurrency(value, locale, currency, currencyCode, digitsInfo) {
2321 const format = getLocaleNumberFormat(locale, NumberFormatStyle.Currency);
2322 const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
2323 pattern.minFrac = getNumberOfCurrencyDigits(currencyCode);
2324 pattern.maxFrac = pattern.minFrac;
2325 const res = formatNumberToLocaleString(value, pattern, locale, NumberSymbol.CurrencyGroup, NumberSymbol.CurrencyDecimal, digitsInfo);
2326 return res
2327 .replace(CURRENCY_CHAR, currency)
2328 // if we have 2 time the currency character, the second one is ignored
2329 .replace(CURRENCY_CHAR, '')
2330 // If there is a spacing between currency character and the value and
2331 // the currency character is supressed by passing an empty string, the
2332 // spacing character would remain as part of the string. Then we
2333 // should remove it.
2334 .trim();
2335}
2336/**
2337 * @ngModule CommonModule
2338 * @description
2339 *
2340 * Formats a number as a percentage according to locale rules.
2341 *
2342 * @param value The number to format.
2343 * @param locale A locale code for the locale format rules to use.
2344 * @param digitsInfo Decimal representation options, specified by a string in the following format:
2345 * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details.
2346 *
2347 * @returns The formatted percentage value.
2348 *
2349 * @see `formatNumber()`
2350 * @see `DecimalPipe`
2351 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
2352 * @publicApi
2353 *
2354 */
2355function formatPercent(value, locale, digitsInfo) {
2356 const format = getLocaleNumberFormat(locale, NumberFormatStyle.Percent);
2357 const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
2358 const res = formatNumberToLocaleString(value, pattern, locale, NumberSymbol.Group, NumberSymbol.Decimal, digitsInfo, true);
2359 return res.replace(new RegExp(PERCENT_CHAR, 'g'), getLocaleNumberSymbol(locale, NumberSymbol.PercentSign));
2360}
2361/**
2362 * @ngModule CommonModule
2363 * @description
2364 *
2365 * Formats a number as text, with group sizing, separator, and other
2366 * parameters based on the locale.
2367 *
2368 * @param value The number to format.
2369 * @param locale A locale code for the locale format rules to use.
2370 * @param digitsInfo Decimal representation options, specified by a string in the following format:
2371 * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details.
2372 *
2373 * @returns The formatted text string.
2374 * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n-overview)
2375 *
2376 * @publicApi
2377 */
2378function formatNumber(value, locale, digitsInfo) {
2379 const format = getLocaleNumberFormat(locale, NumberFormatStyle.Decimal);
2380 const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));
2381 return formatNumberToLocaleString(value, pattern, locale, NumberSymbol.Group, NumberSymbol.Decimal, digitsInfo);
2382}
2383function parseNumberFormat(format, minusSign = '-') {
2384 const p = {
2385 minInt: 1,
2386 minFrac: 0,
2387 maxFrac: 0,
2388 posPre: '',
2389 posSuf: '',
2390 negPre: '',
2391 negSuf: '',
2392 gSize: 0,
2393 lgSize: 0
2394 };
2395 const patternParts = format.split(PATTERN_SEP);
2396 const positive = patternParts[0];
2397 const negative = patternParts[1];
2398 const positiveParts = positive.indexOf(DECIMAL_SEP) !== -1 ?
2399 positive.split(DECIMAL_SEP) :
2400 [
2401 positive.substring(0, positive.lastIndexOf(ZERO_CHAR) + 1),
2402 positive.substring(positive.lastIndexOf(ZERO_CHAR) + 1)
2403 ], integer = positiveParts[0], fraction = positiveParts[1] || '';
2404 p.posPre = integer.substr(0, integer.indexOf(DIGIT_CHAR));
2405 for (let i = 0; i < fraction.length; i++) {
2406 const ch = fraction.charAt(i);
2407 if (ch === ZERO_CHAR) {
2408 p.minFrac = p.maxFrac = i + 1;
2409 }
2410 else if (ch === DIGIT_CHAR) {
2411 p.maxFrac = i + 1;
2412 }
2413 else {
2414 p.posSuf += ch;
2415 }
2416 }
2417 const groups = integer.split(GROUP_SEP);
2418 p.gSize = groups[1] ? groups[1].length : 0;
2419 p.lgSize = (groups[2] || groups[1]) ? (groups[2] || groups[1]).length : 0;
2420 if (negative) {
2421 const trunkLen = positive.length - p.posPre.length - p.posSuf.length, pos = negative.indexOf(DIGIT_CHAR);
2422 p.negPre = negative.substr(0, pos).replace(/'/g, '');
2423 p.negSuf = negative.substr(pos + trunkLen).replace(/'/g, '');
2424 }
2425 else {
2426 p.negPre = minusSign + p.posPre;
2427 p.negSuf = p.posSuf;
2428 }
2429 return p;
2430}
2431// Transforms a parsed number into a percentage by multiplying it by 100
2432function toPercent(parsedNumber) {
2433 // if the number is 0, don't do anything
2434 if (parsedNumber.digits[0] === 0) {
2435 return parsedNumber;
2436 }
2437 // Getting the current number of decimals
2438 const fractionLen = parsedNumber.digits.length - parsedNumber.integerLen;
2439 if (parsedNumber.exponent) {
2440 parsedNumber.exponent += 2;
2441 }
2442 else {
2443 if (fractionLen === 0) {
2444 parsedNumber.digits.push(0, 0);
2445 }
2446 else if (fractionLen === 1) {
2447 parsedNumber.digits.push(0);
2448 }
2449 parsedNumber.integerLen += 2;
2450 }
2451 return parsedNumber;
2452}
2453/**
2454 * Parses a number.
2455 * Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/
2456 */
2457function parseNumber(num) {
2458 let numStr = Math.abs(num) + '';
2459 let exponent = 0, digits, integerLen;
2460 let i, j, zeros;
2461 // Decimal point?
2462 if ((integerLen = numStr.indexOf(DECIMAL_SEP)) > -1) {
2463 numStr = numStr.replace(DECIMAL_SEP, '');
2464 }
2465 // Exponential form?
2466 if ((i = numStr.search(/e/i)) > 0) {
2467 // Work out the exponent.
2468 if (integerLen < 0)
2469 integerLen = i;
2470 integerLen += +numStr.slice(i + 1);
2471 numStr = numStr.substring(0, i);
2472 }
2473 else if (integerLen < 0) {
2474 // There was no decimal point or exponent so it is an integer.
2475 integerLen = numStr.length;
2476 }
2477 // Count the number of leading zeros.
2478 for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) { /* empty */
2479 }
2480 if (i === (zeros = numStr.length)) {
2481 // The digits are all zero.
2482 digits = [0];
2483 integerLen = 1;
2484 }
2485 else {
2486 // Count the number of trailing zeros
2487 zeros--;
2488 while (numStr.charAt(zeros) === ZERO_CHAR)
2489 zeros--;
2490 // Trailing zeros are insignificant so ignore them
2491 integerLen -= i;
2492 digits = [];
2493 // Convert string to array of digits without leading/trailing zeros.
2494 for (j = 0; i <= zeros; i++, j++) {
2495 digits[j] = Number(numStr.charAt(i));
2496 }
2497 }
2498 // If the number overflows the maximum allowed digits then use an exponent.
2499 if (integerLen > MAX_DIGITS) {
2500 digits = digits.splice(0, MAX_DIGITS - 1);
2501 exponent = integerLen - 1;
2502 integerLen = 1;
2503 }
2504 return { digits, exponent, integerLen };
2505}
2506/**
2507 * Round the parsed number to the specified number of decimal places
2508 * This function changes the parsedNumber in-place
2509 */
2510function roundNumber(parsedNumber, minFrac, maxFrac) {
2511 if (minFrac > maxFrac) {
2512 throw new Error(`The minimum number of digits after fraction (${minFrac}) is higher than the maximum (${maxFrac}).`);
2513 }
2514 let digits = parsedNumber.digits;
2515 let fractionLen = digits.length - parsedNumber.integerLen;
2516 const fractionSize = Math.min(Math.max(minFrac, fractionLen), maxFrac);
2517 // The index of the digit to where rounding is to occur
2518 let roundAt = fractionSize + parsedNumber.integerLen;
2519 let digit = digits[roundAt];
2520 if (roundAt > 0) {
2521 // Drop fractional digits beyond `roundAt`
2522 digits.splice(Math.max(parsedNumber.integerLen, roundAt));
2523 // Set non-fractional digits beyond `roundAt` to 0
2524 for (let j = roundAt; j < digits.length; j++) {
2525 digits[j] = 0;
2526 }
2527 }
2528 else {
2529 // We rounded to zero so reset the parsedNumber
2530 fractionLen = Math.max(0, fractionLen);
2531 parsedNumber.integerLen = 1;
2532 digits.length = Math.max(1, roundAt = fractionSize + 1);
2533 digits[0] = 0;
2534 for (let i = 1; i < roundAt; i++)
2535 digits[i] = 0;
2536 }
2537 if (digit >= 5) {
2538 if (roundAt - 1 < 0) {
2539 for (let k = 0; k > roundAt; k--) {
2540 digits.unshift(0);
2541 parsedNumber.integerLen++;
2542 }
2543 digits.unshift(1);
2544 parsedNumber.integerLen++;
2545 }
2546 else {
2547 digits[roundAt - 1]++;
2548 }
2549 }
2550 // Pad out with zeros to get the required fraction length
2551 for (; fractionLen < Math.max(0, fractionSize); fractionLen++)
2552 digits.push(0);
2553 let dropTrailingZeros = fractionSize !== 0;
2554 // Minimal length = nb of decimals required + current nb of integers
2555 // Any number besides that is optional and can be removed if it's a trailing 0
2556 const minLen = minFrac + parsedNumber.integerLen;
2557 // Do any carrying, e.g. a digit was rounded up to 10
2558 const carry = digits.reduceRight(function (carry, d, i, digits) {
2559 d = d + carry;
2560 digits[i] = d < 10 ? d : d - 10; // d % 10
2561 if (dropTrailingZeros) {
2562 // Do not keep meaningless fractional trailing zeros (e.g. 15.52000 --> 15.52)
2563 if (digits[i] === 0 && i >= minLen) {
2564 digits.pop();
2565 }
2566 else {
2567 dropTrailingZeros = false;
2568 }
2569 }
2570 return d >= 10 ? 1 : 0; // Math.floor(d / 10);
2571 }, 0);
2572 if (carry) {
2573 digits.unshift(carry);
2574 parsedNumber.integerLen++;
2575 }
2576}
2577function parseIntAutoRadix(text) {
2578 const result = parseInt(text);
2579 if (isNaN(result)) {
2580 throw new Error('Invalid integer literal when parsing ' + text);
2581 }
2582 return result;
2583}
2584
2585/**
2586 * @license
2587 * Copyright Google LLC All Rights Reserved.
2588 *
2589 * Use of this source code is governed by an MIT-style license that can be
2590 * found in the LICENSE file at https://angular.io/license
2591 */
2592/**
2593 * @publicApi
2594 */
2595class NgLocalization {
2596}
2597/**
2598 * Returns the plural category for a given value.
2599 * - "=value" when the case exists,
2600 * - the plural category otherwise
2601 */
2602function getPluralCategory(value, cases, ngLocalization, locale) {
2603 let key = `=${value}`;
2604 if (cases.indexOf(key) > -1) {
2605 return key;
2606 }
2607 key = ngLocalization.getPluralCategory(value, locale);
2608 if (cases.indexOf(key) > -1) {
2609 return key;
2610 }
2611 if (cases.indexOf('other') > -1) {
2612 return 'other';
2613 }
2614 throw new Error(`No plural message found for value "${value}"`);
2615}
2616/**
2617 * Returns the plural case based on the locale
2618 *
2619 * @publicApi
2620 */
2621class NgLocaleLocalization extends NgLocalization {
2622 constructor(locale) {
2623 super();
2624 this.locale = locale;
2625 }
2626 getPluralCategory(value, locale) {
2627 const plural = getLocalePluralCase(locale || this.locale)(value);
2628 switch (plural) {
2629 case Plural.Zero:
2630 return 'zero';
2631 case Plural.One:
2632 return 'one';
2633 case Plural.Two:
2634 return 'two';
2635 case Plural.Few:
2636 return 'few';
2637 case Plural.Many:
2638 return 'many';
2639 default:
2640 return 'other';
2641 }
2642 }
2643}
2644NgLocaleLocalization.ɵfac = function NgLocaleLocalization_Factory(t) { return new (t || NgLocaleLocalization)(ɵngcc0.ɵɵinject(LOCALE_ID)); };
2645NgLocaleLocalization.ɵprov = /*@__PURE__*/ ɵngcc0.ɵɵdefineInjectable({ token: NgLocaleLocalization, factory: NgLocaleLocalization.ɵfac });
2646NgLocaleLocalization.ctorParameters = () => [
2647 { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] }
2648];
2649(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgLocaleLocalization, [{
2650 type: Injectable
2651 }], function () { return [{ type: String, decorators: [{
2652 type: Inject,
2653 args: [LOCALE_ID]
2654 }] }]; }, null); })();
2655
2656/**
2657 * @license
2658 * Copyright Google LLC All Rights Reserved.
2659 *
2660 * Use of this source code is governed by an MIT-style license that can be
2661 * found in the LICENSE file at https://angular.io/license
2662 */
2663/**
2664 * Register global data to be used internally by Angular. See the
2665 * ["I18n guide"](guide/i18n-common-format-data-locale) to know how to import additional locale
2666 * data.
2667 *
2668 * The signature registerLocaleData(data: any, extraData?: any) is deprecated since v5.1
2669 *
2670 * @publicApi
2671 */
2672function registerLocaleData(data, localeId, extraData) {
2673 return ɵregisterLocaleData(data, localeId, extraData);
2674}
2675
2676/**
2677 * @license
2678 * Copyright Google LLC All Rights Reserved.
2679 *
2680 * Use of this source code is governed by an MIT-style license that can be
2681 * found in the LICENSE file at https://angular.io/license
2682 */
2683function parseCookieValue(cookieStr, name) {
2684 name = encodeURIComponent(name);
2685 for (const cookie of cookieStr.split(';')) {
2686 const eqIndex = cookie.indexOf('=');
2687 const [cookieName, cookieValue] = eqIndex == -1 ? [cookie, ''] : [cookie.slice(0, eqIndex), cookie.slice(eqIndex + 1)];
2688 if (cookieName.trim() === name) {
2689 return decodeURIComponent(cookieValue);
2690 }
2691 }
2692 return null;
2693}
2694
2695/**
2696 * @license
2697 * Copyright Google LLC All Rights Reserved.
2698 *
2699 * Use of this source code is governed by an MIT-style license that can be
2700 * found in the LICENSE file at https://angular.io/license
2701 */
2702/**
2703 * @ngModule CommonModule
2704 *
2705 * @usageNotes
2706 * ```
2707 * <some-element [ngClass]="'first second'">...</some-element>
2708 *
2709 * <some-element [ngClass]="['first', 'second']">...</some-element>
2710 *
2711 * <some-element [ngClass]="{'first': true, 'second': true, 'third': false}">...</some-element>
2712 *
2713 * <some-element [ngClass]="stringExp|arrayExp|objExp">...</some-element>
2714 *
2715 * <some-element [ngClass]="{'class1 class2 class3' : true}">...</some-element>
2716 * ```
2717 *
2718 * @description
2719 *
2720 * Adds and removes CSS classes on an HTML element.
2721 *
2722 * The CSS classes are updated as follows, depending on the type of the expression evaluation:
2723 * - `string` - the CSS classes listed in the string (space delimited) are added,
2724 * - `Array` - the CSS classes declared as Array elements are added,
2725 * - `Object` - keys are CSS classes that get added when the expression given in the value
2726 * evaluates to a truthy value, otherwise they are removed.
2727 *
2728 * @publicApi
2729 */
2730class NgClass {
2731 constructor(_iterableDiffers, _keyValueDiffers, _ngEl, _renderer) {
2732 this._iterableDiffers = _iterableDiffers;
2733 this._keyValueDiffers = _keyValueDiffers;
2734 this._ngEl = _ngEl;
2735 this._renderer = _renderer;
2736 this._iterableDiffer = null;
2737 this._keyValueDiffer = null;
2738 this._initialClasses = [];
2739 this._rawClass = null;
2740 }
2741 set klass(value) {
2742 this._removeClasses(this._initialClasses);
2743 this._initialClasses = typeof value === 'string' ? value.split(/\s+/) : [];
2744 this._applyClasses(this._initialClasses);
2745 this._applyClasses(this._rawClass);
2746 }
2747 set ngClass(value) {
2748 this._removeClasses(this._rawClass);
2749 this._applyClasses(this._initialClasses);
2750 this._iterableDiffer = null;
2751 this._keyValueDiffer = null;
2752 this._rawClass = typeof value === 'string' ? value.split(/\s+/) : value;
2753 if (this._rawClass) {
2754 if (ɵisListLikeIterable(this._rawClass)) {
2755 this._iterableDiffer = this._iterableDiffers.find(this._rawClass).create();
2756 }
2757 else {
2758 this._keyValueDiffer = this._keyValueDiffers.find(this._rawClass).create();
2759 }
2760 }
2761 }
2762 ngDoCheck() {
2763 if (this._iterableDiffer) {
2764 const iterableChanges = this._iterableDiffer.diff(this._rawClass);
2765 if (iterableChanges) {
2766 this._applyIterableChanges(iterableChanges);
2767 }
2768 }
2769 else if (this._keyValueDiffer) {
2770 const keyValueChanges = this._keyValueDiffer.diff(this._rawClass);
2771 if (keyValueChanges) {
2772 this._applyKeyValueChanges(keyValueChanges);
2773 }
2774 }
2775 }
2776 _applyKeyValueChanges(changes) {
2777 changes.forEachAddedItem((record) => this._toggleClass(record.key, record.currentValue));
2778 changes.forEachChangedItem((record) => this._toggleClass(record.key, record.currentValue));
2779 changes.forEachRemovedItem((record) => {
2780 if (record.previousValue) {
2781 this._toggleClass(record.key, false);
2782 }
2783 });
2784 }
2785 _applyIterableChanges(changes) {
2786 changes.forEachAddedItem((record) => {
2787 if (typeof record.item === 'string') {
2788 this._toggleClass(record.item, true);
2789 }
2790 else {
2791 throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${ɵstringify(record.item)}`);
2792 }
2793 });
2794 changes.forEachRemovedItem((record) => this._toggleClass(record.item, false));
2795 }
2796 /**
2797 * Applies a collection of CSS classes to the DOM element.
2798 *
2799 * For argument of type Set and Array CSS class names contained in those collections are always
2800 * added.
2801 * For argument of type Map CSS class name in the map's key is toggled based on the value (added
2802 * for truthy and removed for falsy).
2803 */
2804 _applyClasses(rawClassVal) {
2805 if (rawClassVal) {
2806 if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) {
2807 rawClassVal.forEach((klass) => this._toggleClass(klass, true));
2808 }
2809 else {
2810 Object.keys(rawClassVal).forEach(klass => this._toggleClass(klass, !!rawClassVal[klass]));
2811 }
2812 }
2813 }
2814 /**
2815 * Removes a collection of CSS classes from the DOM element. This is mostly useful for cleanup
2816 * purposes.
2817 */
2818 _removeClasses(rawClassVal) {
2819 if (rawClassVal) {
2820 if (Array.isArray(rawClassVal) || rawClassVal instanceof Set) {
2821 rawClassVal.forEach((klass) => this._toggleClass(klass, false));
2822 }
2823 else {
2824 Object.keys(rawClassVal).forEach(klass => this._toggleClass(klass, false));
2825 }
2826 }
2827 }
2828 _toggleClass(klass, enabled) {
2829 klass = klass.trim();
2830 if (klass) {
2831 klass.split(/\s+/g).forEach(klass => {
2832 if (enabled) {
2833 this._renderer.addClass(this._ngEl.nativeElement, klass);
2834 }
2835 else {
2836 this._renderer.removeClass(this._ngEl.nativeElement, klass);
2837 }
2838 });
2839 }
2840 }
2841}
2842NgClass.ɵfac = function NgClass_Factory(t) { return new (t || NgClass)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.IterableDiffers), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.KeyValueDiffers), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ElementRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.Renderer2)); };
2843NgClass.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgClass, selectors: [["", "ngClass", ""]], inputs: { klass: ["class", "klass"], ngClass: "ngClass" } });
2844NgClass.ctorParameters = () => [
2845 { type: IterableDiffers },
2846 { type: KeyValueDiffers },
2847 { type: ElementRef },
2848 { type: Renderer2 }
2849];
2850NgClass.propDecorators = {
2851 klass: [{ type: Input, args: ['class',] }],
2852 ngClass: [{ type: Input, args: ['ngClass',] }]
2853};
2854(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgClass, [{
2855 type: Directive,
2856 args: [{ selector: '[ngClass]' }]
2857 }], function () { return [{ type: ɵngcc0.IterableDiffers }, { type: ɵngcc0.KeyValueDiffers }, { type: ɵngcc0.ElementRef }, { type: ɵngcc0.Renderer2 }]; }, { klass: [{
2858 type: Input,
2859 args: ['class']
2860 }], ngClass: [{
2861 type: Input,
2862 args: ['ngClass']
2863 }] }); })();
2864
2865/**
2866 * @license
2867 * Copyright Google LLC All Rights Reserved.
2868 *
2869 * Use of this source code is governed by an MIT-style license that can be
2870 * found in the LICENSE file at https://angular.io/license
2871 */
2872/**
2873 * Instantiates a {@link Component} type and inserts its Host View into the current View.
2874 * `NgComponentOutlet` provides a declarative approach for dynamic component creation.
2875 *
2876 * `NgComponentOutlet` requires a component type, if a falsy value is set the view will clear and
2877 * any existing component will be destroyed.
2878 *
2879 * @usageNotes
2880 *
2881 * ### Fine tune control
2882 *
2883 * You can control the component creation process by using the following optional attributes:
2884 *
2885 * * `ngComponentOutletInjector`: Optional custom {@link Injector} that will be used as parent for
2886 * the Component. Defaults to the injector of the current view container.
2887 *
2888 * * `ngComponentOutletContent`: Optional list of projectable nodes to insert into the content
2889 * section of the component, if it exists.
2890 *
2891 * * `ngComponentOutletNgModuleFactory`: Optional module factory to allow loading another
2892 * module dynamically, then loading a component from that module.
2893 *
2894 * ### Syntax
2895 *
2896 * Simple
2897 * ```
2898 * <ng-container *ngComponentOutlet="componentTypeExpression"></ng-container>
2899 * ```
2900 *
2901 * Customized injector/content
2902 * ```
2903 * <ng-container *ngComponentOutlet="componentTypeExpression;
2904 * injector: injectorExpression;
2905 * content: contentNodesExpression;">
2906 * </ng-container>
2907 * ```
2908 *
2909 * Customized ngModuleFactory
2910 * ```
2911 * <ng-container *ngComponentOutlet="componentTypeExpression;
2912 * ngModuleFactory: moduleFactory;">
2913 * </ng-container>
2914 * ```
2915 *
2916 * ### A simple example
2917 *
2918 * {@example common/ngComponentOutlet/ts/module.ts region='SimpleExample'}
2919 *
2920 * A more complete example with additional options:
2921 *
2922 * {@example common/ngComponentOutlet/ts/module.ts region='CompleteExample'}
2923 *
2924 * @publicApi
2925 * @ngModule CommonModule
2926 */
2927class NgComponentOutlet {
2928 constructor(_viewContainerRef) {
2929 this._viewContainerRef = _viewContainerRef;
2930 this._componentRef = null;
2931 this._moduleRef = null;
2932 }
2933 ngOnChanges(changes) {
2934 this._viewContainerRef.clear();
2935 this._componentRef = null;
2936 if (this.ngComponentOutlet) {
2937 const elInjector = this.ngComponentOutletInjector || this._viewContainerRef.parentInjector;
2938 if (changes['ngComponentOutletNgModuleFactory']) {
2939 if (this._moduleRef)
2940 this._moduleRef.destroy();
2941 if (this.ngComponentOutletNgModuleFactory) {
2942 const parentModule = elInjector.get(NgModuleRef);
2943 this._moduleRef = this.ngComponentOutletNgModuleFactory.create(parentModule.injector);
2944 }
2945 else {
2946 this._moduleRef = null;
2947 }
2948 }
2949 const componentFactoryResolver = this._moduleRef ? this._moduleRef.componentFactoryResolver :
2950 elInjector.get(ComponentFactoryResolver);
2951 const componentFactory = componentFactoryResolver.resolveComponentFactory(this.ngComponentOutlet);
2952 this._componentRef = this._viewContainerRef.createComponent(componentFactory, this._viewContainerRef.length, elInjector, this.ngComponentOutletContent);
2953 }
2954 }
2955 ngOnDestroy() {
2956 if (this._moduleRef)
2957 this._moduleRef.destroy();
2958 }
2959}
2960NgComponentOutlet.ɵfac = function NgComponentOutlet_Factory(t) { return new (t || NgComponentOutlet)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef)); };
2961NgComponentOutlet.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgComponentOutlet, selectors: [["", "ngComponentOutlet", ""]], inputs: { ngComponentOutlet: "ngComponentOutlet", ngComponentOutletInjector: "ngComponentOutletInjector", ngComponentOutletContent: "ngComponentOutletContent", ngComponentOutletNgModuleFactory: "ngComponentOutletNgModuleFactory" }, features: [ɵngcc0.ɵɵNgOnChangesFeature] });
2962NgComponentOutlet.ctorParameters = () => [
2963 { type: ViewContainerRef }
2964];
2965NgComponentOutlet.propDecorators = {
2966 ngComponentOutlet: [{ type: Input }],
2967 ngComponentOutletInjector: [{ type: Input }],
2968 ngComponentOutletContent: [{ type: Input }],
2969 ngComponentOutletNgModuleFactory: [{ type: Input }]
2970};
2971(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgComponentOutlet, [{
2972 type: Directive,
2973 args: [{ selector: '[ngComponentOutlet]' }]
2974 }], function () { return [{ type: ɵngcc0.ViewContainerRef }]; }, { ngComponentOutlet: [{
2975 type: Input
2976 }], ngComponentOutletInjector: [{
2977 type: Input
2978 }], ngComponentOutletContent: [{
2979 type: Input
2980 }], ngComponentOutletNgModuleFactory: [{
2981 type: Input
2982 }] }); })();
2983
2984/**
2985 * @license
2986 * Copyright Google LLC All Rights Reserved.
2987 *
2988 * Use of this source code is governed by an MIT-style license that can be
2989 * found in the LICENSE file at https://angular.io/license
2990 */
2991/**
2992 * @publicApi
2993 */
2994class NgForOfContext {
2995 constructor($implicit, ngForOf, index, count) {
2996 this.$implicit = $implicit;
2997 this.ngForOf = ngForOf;
2998 this.index = index;
2999 this.count = count;
3000 }
3001 get first() {
3002 return this.index === 0;
3003 }
3004 get last() {
3005 return this.index === this.count - 1;
3006 }
3007 get even() {
3008 return this.index % 2 === 0;
3009 }
3010 get odd() {
3011 return !this.even;
3012 }
3013}
3014/**
3015 * A [structural directive](guide/structural-directives) that renders
3016 * a template for each item in a collection.
3017 * The directive is placed on an element, which becomes the parent
3018 * of the cloned templates.
3019 *
3020 * The `ngForOf` directive is generally used in the
3021 * [shorthand form](guide/structural-directives#asterisk) `*ngFor`.
3022 * In this form, the template to be rendered for each iteration is the content
3023 * of an anchor element containing the directive.
3024 *
3025 * The following example shows the shorthand syntax with some options,
3026 * contained in an `<li>` element.
3027 *
3028 * ```
3029 * <li *ngFor="let item of items; index as i; trackBy: trackByFn">...</li>
3030 * ```
3031 *
3032 * The shorthand form expands into a long form that uses the `ngForOf` selector
3033 * on an `<ng-template>` element.
3034 * The content of the `<ng-template>` element is the `<li>` element that held the
3035 * short-form directive.
3036 *
3037 * Here is the expanded version of the short-form example.
3038 *
3039 * ```
3040 * <ng-template ngFor let-item [ngForOf]="items" let-i="index" [ngForTrackBy]="trackByFn">
3041 * <li>...</li>
3042 * </ng-template>
3043 * ```
3044 *
3045 * Angular automatically expands the shorthand syntax as it compiles the template.
3046 * The context for each embedded view is logically merged to the current component
3047 * context according to its lexical position.
3048 *
3049 * When using the shorthand syntax, Angular allows only [one structural directive
3050 * on an element](guide/built-in-directives#one-per-element).
3051 * If you want to iterate conditionally, for example,
3052 * put the `*ngIf` on a container element that wraps the `*ngFor` element.
3053 * For futher discussion, see
3054 * [Structural Directives](guide/built-in-directives#one-per-element).
3055 *
3056 * @usageNotes
3057 *
3058 * ### Local variables
3059 *
3060 * `NgForOf` provides exported values that can be aliased to local variables.
3061 * For example:
3062 *
3063 * ```
3064 * <li *ngFor="let user of users; index as i; first as isFirst">
3065 * {{i}}/{{users.length}}. {{user}} <span *ngIf="isFirst">default</span>
3066 * </li>
3067 * ```
3068 *
3069 * The following exported values can be aliased to local variables:
3070 *
3071 * - `$implicit: T`: The value of the individual items in the iterable (`ngForOf`).
3072 * - `ngForOf: NgIterable<T>`: The value of the iterable expression. Useful when the expression is
3073 * more complex then a property access, for example when using the async pipe (`userStreams |
3074 * async`).
3075 * - `index: number`: The index of the current item in the iterable.
3076 * - `count: number`: The length of the iterable.
3077 * - `first: boolean`: True when the item is the first item in the iterable.
3078 * - `last: boolean`: True when the item is the last item in the iterable.
3079 * - `even: boolean`: True when the item has an even index in the iterable.
3080 * - `odd: boolean`: True when the item has an odd index in the iterable.
3081 *
3082 * ### Change propagation
3083 *
3084 * When the contents of the iterator changes, `NgForOf` makes the corresponding changes to the DOM:
3085 *
3086 * * When an item is added, a new instance of the template is added to the DOM.
3087 * * When an item is removed, its template instance is removed from the DOM.
3088 * * When items are reordered, their respective templates are reordered in the DOM.
3089 *
3090 * Angular uses object identity to track insertions and deletions within the iterator and reproduce
3091 * those changes in the DOM. This has important implications for animations and any stateful
3092 * controls that are present, such as `<input>` elements that accept user input. Inserted rows can
3093 * be animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state
3094 * such as user input.
3095 * For more on animations, see [Transitions and Triggers](guide/transition-and-triggers).
3096 *
3097 * The identities of elements in the iterator can change while the data does not.
3098 * This can happen, for example, if the iterator is produced from an RPC to the server, and that
3099 * RPC is re-run. Even if the data hasn't changed, the second response produces objects with
3100 * different identities, and Angular must tear down the entire DOM and rebuild it (as if all old
3101 * elements were deleted and all new elements inserted).
3102 *
3103 * To avoid this expensive operation, you can customize the default tracking algorithm.
3104 * by supplying the `trackBy` option to `NgForOf`.
3105 * `trackBy` takes a function that has two arguments: `index` and `item`.
3106 * If `trackBy` is given, Angular tracks changes by the return value of the function.
3107 *
3108 * @see [Structural Directives](guide/structural-directives)
3109 * @ngModule CommonModule
3110 * @publicApi
3111 */
3112class NgForOf {
3113 constructor(_viewContainer, _template, _differs) {
3114 this._viewContainer = _viewContainer;
3115 this._template = _template;
3116 this._differs = _differs;
3117 this._ngForOf = null;
3118 this._ngForOfDirty = true;
3119 this._differ = null;
3120 }
3121 /**
3122 * The value of the iterable expression, which can be used as a
3123 * [template input variable](guide/structural-directives#shorthand).
3124 */
3125 set ngForOf(ngForOf) {
3126 this._ngForOf = ngForOf;
3127 this._ngForOfDirty = true;
3128 }
3129 /**
3130 * Specifies a custom `TrackByFunction` to compute the identity of items in an iterable.
3131 *
3132 * If a custom `TrackByFunction` is not provided, `NgForOf` will use the item's [object
3133 * identity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)
3134 * as the key.
3135 *
3136 * `NgForOf` uses the computed key to associate items in an iterable with DOM elements
3137 * it produces for these items.
3138 *
3139 * A custom `TrackByFunction` is useful to provide good user experience in cases when items in an
3140 * iterable rendered using `NgForOf` have a natural identifier (for example, custom ID or a
3141 * primary key), and this iterable could be updated with new object instances that still
3142 * represent the same underlying entity (for example, when data is re-fetched from the server,
3143 * and the iterable is recreated and re-rendered, but most of the data is still the same).
3144 *
3145 * @see `TrackByFunction`
3146 */
3147 set ngForTrackBy(fn) {
3148 if ((typeof ngDevMode === 'undefined' || ngDevMode) && fn != null && typeof fn !== 'function') {
3149 // TODO(vicb): use a log service once there is a public one available
3150 if (console && console.warn) {
3151 console.warn(`trackBy must be a function, but received ${JSON.stringify(fn)}. ` +
3152 `See https://angular.io/api/common/NgForOf#change-propagation for more information.`);
3153 }
3154 }
3155 this._trackByFn = fn;
3156 }
3157 get ngForTrackBy() {
3158 return this._trackByFn;
3159 }
3160 /**
3161 * A reference to the template that is stamped out for each item in the iterable.
3162 * @see [template reference variable](guide/template-reference-variables)
3163 */
3164 set ngForTemplate(value) {
3165 // TODO(TS2.1): make TemplateRef<Partial<NgForRowOf<T>>> once we move to TS v2.1
3166 // The current type is too restrictive; a template that just uses index, for example,
3167 // should be acceptable.
3168 if (value) {
3169 this._template = value;
3170 }
3171 }
3172 /**
3173 * Applies the changes when needed.
3174 */
3175 ngDoCheck() {
3176 if (this._ngForOfDirty) {
3177 this._ngForOfDirty = false;
3178 // React on ngForOf changes only once all inputs have been initialized
3179 const value = this._ngForOf;
3180 if (!this._differ && value) {
3181 try {
3182 this._differ = this._differs.find(value).create(this.ngForTrackBy);
3183 }
3184 catch (_a) {
3185 throw new Error(`Cannot find a differ supporting object '${value}' of type '${getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
3186 }
3187 }
3188 }
3189 if (this._differ) {
3190 const changes = this._differ.diff(this._ngForOf);
3191 if (changes)
3192 this._applyChanges(changes);
3193 }
3194 }
3195 _applyChanges(changes) {
3196 const insertTuples = [];
3197 changes.forEachOperation((item, adjustedPreviousIndex, currentIndex) => {
3198 if (item.previousIndex == null) {
3199 // NgForOf is never "null" or "undefined" here because the differ detected
3200 // that a new item needs to be inserted from the iterable. This implies that
3201 // there is an iterable value for "_ngForOf".
3202 const view = this._viewContainer.createEmbeddedView(this._template, new NgForOfContext(null, this._ngForOf, -1, -1), currentIndex === null ? undefined : currentIndex);
3203 const tuple = new RecordViewTuple(item, view);
3204 insertTuples.push(tuple);
3205 }
3206 else if (currentIndex == null) {
3207 this._viewContainer.remove(adjustedPreviousIndex === null ? undefined : adjustedPreviousIndex);
3208 }
3209 else if (adjustedPreviousIndex !== null) {
3210 const view = this._viewContainer.get(adjustedPreviousIndex);
3211 this._viewContainer.move(view, currentIndex);
3212 const tuple = new RecordViewTuple(item, view);
3213 insertTuples.push(tuple);
3214 }
3215 });
3216 for (let i = 0; i < insertTuples.length; i++) {
3217 this._perViewChange(insertTuples[i].view, insertTuples[i].record);
3218 }
3219 for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
3220 const viewRef = this._viewContainer.get(i);
3221 viewRef.context.index = i;
3222 viewRef.context.count = ilen;
3223 viewRef.context.ngForOf = this._ngForOf;
3224 }
3225 changes.forEachIdentityChange((record) => {
3226 const viewRef = this._viewContainer.get(record.currentIndex);
3227 viewRef.context.$implicit = record.item;
3228 });
3229 }
3230 _perViewChange(view, record) {
3231 view.context.$implicit = record.item;
3232 }
3233 /**
3234 * Asserts the correct type of the context for the template that `NgForOf` will render.
3235 *
3236 * The presence of this method is a signal to the Ivy template type-check compiler that the
3237 * `NgForOf` structural directive renders its template with a specific context type.
3238 */
3239 static ngTemplateContextGuard(dir, ctx) {
3240 return true;
3241 }
3242}
3243NgForOf.ɵfac = function NgForOf_Factory(t) { return new (t || NgForOf)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.TemplateRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.IterableDiffers)); };
3244NgForOf.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgForOf, selectors: [["", "ngFor", "", "ngForOf", ""]], inputs: { ngForOf: "ngForOf", ngForTrackBy: "ngForTrackBy", ngForTemplate: "ngForTemplate" } });
3245NgForOf.ctorParameters = () => [
3246 { type: ViewContainerRef },
3247 { type: TemplateRef },
3248 { type: IterableDiffers }
3249];
3250NgForOf.propDecorators = {
3251 ngForOf: [{ type: Input }],
3252 ngForTrackBy: [{ type: Input }],
3253 ngForTemplate: [{ type: Input }]
3254};
3255(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgForOf, [{
3256 type: Directive,
3257 args: [{ selector: '[ngFor][ngForOf]' }]
3258 }], function () { return [{ type: ɵngcc0.ViewContainerRef }, { type: ɵngcc0.TemplateRef }, { type: ɵngcc0.IterableDiffers }]; }, { ngForOf: [{
3259 type: Input
3260 }], ngForTrackBy: [{
3261 type: Input
3262 }], ngForTemplate: [{
3263 type: Input
3264 }] }); })();
3265class RecordViewTuple {
3266 constructor(record, view) {
3267 this.record = record;
3268 this.view = view;
3269 }
3270}
3271function getTypeName(type) {
3272 return type['name'] || typeof type;
3273}
3274
3275/**
3276 * @license
3277 * Copyright Google LLC All Rights Reserved.
3278 *
3279 * Use of this source code is governed by an MIT-style license that can be
3280 * found in the LICENSE file at https://angular.io/license
3281 */
3282/**
3283 * A structural directive that conditionally includes a template based on the value of
3284 * an expression coerced to Boolean.
3285 * When the expression evaluates to true, Angular renders the template
3286 * provided in a `then` clause, and when false or null,
3287 * Angular renders the template provided in an optional `else` clause. The default
3288 * template for the `else` clause is blank.
3289 *
3290 * A [shorthand form](guide/structural-directives#asterisk) of the directive,
3291 * `*ngIf="condition"`, is generally used, provided
3292 * as an attribute of the anchor element for the inserted template.
3293 * Angular expands this into a more explicit version, in which the anchor element
3294 * is contained in an `<ng-template>` element.
3295 *
3296 * Simple form with shorthand syntax:
3297 *
3298 * ```
3299 * <div *ngIf="condition">Content to render when condition is true.</div>
3300 * ```
3301 *
3302 * Simple form with expanded syntax:
3303 *
3304 * ```
3305 * <ng-template [ngIf]="condition"><div>Content to render when condition is
3306 * true.</div></ng-template>
3307 * ```
3308 *
3309 * Form with an "else" block:
3310 *
3311 * ```
3312 * <div *ngIf="condition; else elseBlock">Content to render when condition is true.</div>
3313 * <ng-template #elseBlock>Content to render when condition is false.</ng-template>
3314 * ```
3315 *
3316 * Shorthand form with "then" and "else" blocks:
3317 *
3318 * ```
3319 * <div *ngIf="condition; then thenBlock else elseBlock"></div>
3320 * <ng-template #thenBlock>Content to render when condition is true.</ng-template>
3321 * <ng-template #elseBlock>Content to render when condition is false.</ng-template>
3322 * ```
3323 *
3324 * Form with storing the value locally:
3325 *
3326 * ```
3327 * <div *ngIf="condition as value; else elseBlock">{{value}}</div>
3328 * <ng-template #elseBlock>Content to render when value is null.</ng-template>
3329 * ```
3330 *
3331 * @usageNotes
3332 *
3333 * The `*ngIf` directive is most commonly used to conditionally show an inline template,
3334 * as seen in the following example.
3335 * The default `else` template is blank.
3336 *
3337 * {@example common/ngIf/ts/module.ts region='NgIfSimple'}
3338 *
3339 * ### Showing an alternative template using `else`
3340 *
3341 * To display a template when `expression` evaluates to false, use an `else` template
3342 * binding as shown in the following example.
3343 * The `else` binding points to an `<ng-template>` element labeled `#elseBlock`.
3344 * The template can be defined anywhere in the component view, but is typically placed right after
3345 * `ngIf` for readability.
3346 *
3347 * {@example common/ngIf/ts/module.ts region='NgIfElse'}
3348 *
3349 * ### Using an external `then` template
3350 *
3351 * In the previous example, the then-clause template is specified inline, as the content of the
3352 * tag that contains the `ngIf` directive. You can also specify a template that is defined
3353 * externally, by referencing a labeled `<ng-template>` element. When you do this, you can
3354 * change which template to use at runtime, as shown in the following example.
3355 *
3356 * {@example common/ngIf/ts/module.ts region='NgIfThenElse'}
3357 *
3358 * ### Storing a conditional result in a variable
3359 *
3360 * You might want to show a set of properties from the same object. If you are waiting
3361 * for asynchronous data, the object can be undefined.
3362 * In this case, you can use `ngIf` and store the result of the condition in a local
3363 * variable as shown in the following example.
3364 *
3365 * {@example common/ngIf/ts/module.ts region='NgIfAs'}
3366 *
3367 * This code uses only one `AsyncPipe`, so only one subscription is created.
3368 * The conditional statement stores the result of `userStream|async` in the local variable `user`.
3369 * You can then bind the local `user` repeatedly.
3370 *
3371 * The conditional displays the data only if `userStream` returns a value,
3372 * so you don't need to use the
3373 * safe-navigation-operator (`?.`)
3374 * to guard against null values when accessing properties.
3375 * You can display an alternative template while waiting for the data.
3376 *
3377 * ### Shorthand syntax
3378 *
3379 * The shorthand syntax `*ngIf` expands into two separate template specifications
3380 * for the "then" and "else" clauses. For example, consider the following shorthand statement,
3381 * that is meant to show a loading page while waiting for data to be loaded.
3382 *
3383 * ```
3384 * <div class="hero-list" *ngIf="heroes else loading">
3385 * ...
3386 * </div>
3387 *
3388 * <ng-template #loading>
3389 * <div>Loading...</div>
3390 * </ng-template>
3391 * ```
3392 *
3393 * You can see that the "else" clause references the `<ng-template>`
3394 * with the `#loading` label, and the template for the "then" clause
3395 * is provided as the content of the anchor element.
3396 *
3397 * However, when Angular expands the shorthand syntax, it creates
3398 * another `<ng-template>` tag, with `ngIf` and `ngIfElse` directives.
3399 * The anchor element containing the template for the "then" clause becomes
3400 * the content of this unlabeled `<ng-template>` tag.
3401 *
3402 * ```
3403 * <ng-template [ngIf]="heroes" [ngIfElse]="loading">
3404 * <div class="hero-list">
3405 * ...
3406 * </div>
3407 * </ng-template>
3408 *
3409 * <ng-template #loading>
3410 * <div>Loading...</div>
3411 * </ng-template>
3412 * ```
3413 *
3414 * The presence of the implicit template object has implications for the nesting of
3415 * structural directives. For more on this subject, see
3416 * [Structural Directives](https://angular.io/guide/built-in-directives#one-per-element).
3417 *
3418 * @ngModule CommonModule
3419 * @publicApi
3420 */
3421class NgIf {
3422 constructor(_viewContainer, templateRef) {
3423 this._viewContainer = _viewContainer;
3424 this._context = new NgIfContext();
3425 this._thenTemplateRef = null;
3426 this._elseTemplateRef = null;
3427 this._thenViewRef = null;
3428 this._elseViewRef = null;
3429 this._thenTemplateRef = templateRef;
3430 }
3431 /**
3432 * The Boolean expression to evaluate as the condition for showing a template.
3433 */
3434 set ngIf(condition) {
3435 this._context.$implicit = this._context.ngIf = condition;
3436 this._updateView();
3437 }
3438 /**
3439 * A template to show if the condition expression evaluates to true.
3440 */
3441 set ngIfThen(templateRef) {
3442 assertTemplate('ngIfThen', templateRef);
3443 this._thenTemplateRef = templateRef;
3444 this._thenViewRef = null; // clear previous view if any.
3445 this._updateView();
3446 }
3447 /**
3448 * A template to show if the condition expression evaluates to false.
3449 */
3450 set ngIfElse(templateRef) {
3451 assertTemplate('ngIfElse', templateRef);
3452 this._elseTemplateRef = templateRef;
3453 this._elseViewRef = null; // clear previous view if any.
3454 this._updateView();
3455 }
3456 _updateView() {
3457 if (this._context.$implicit) {
3458 if (!this._thenViewRef) {
3459 this._viewContainer.clear();
3460 this._elseViewRef = null;
3461 if (this._thenTemplateRef) {
3462 this._thenViewRef =
3463 this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
3464 }
3465 }
3466 }
3467 else {
3468 if (!this._elseViewRef) {
3469 this._viewContainer.clear();
3470 this._thenViewRef = null;
3471 if (this._elseTemplateRef) {
3472 this._elseViewRef =
3473 this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context);
3474 }
3475 }
3476 }
3477 }
3478 /**
3479 * Asserts the correct type of the context for the template that `NgIf` will render.
3480 *
3481 * The presence of this method is a signal to the Ivy template type-check compiler that the
3482 * `NgIf` structural directive renders its template with a specific context type.
3483 */
3484 static ngTemplateContextGuard(dir, ctx) {
3485 return true;
3486 }
3487}
3488NgIf.ɵfac = function NgIf_Factory(t) { return new (t || NgIf)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.TemplateRef)); };
3489NgIf.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgIf, selectors: [["", "ngIf", ""]], inputs: { ngIf: "ngIf", ngIfThen: "ngIfThen", ngIfElse: "ngIfElse" } });
3490NgIf.ctorParameters = () => [
3491 { type: ViewContainerRef },
3492 { type: TemplateRef }
3493];
3494NgIf.propDecorators = {
3495 ngIf: [{ type: Input }],
3496 ngIfThen: [{ type: Input }],
3497 ngIfElse: [{ type: Input }]
3498};
3499(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgIf, [{
3500 type: Directive,
3501 args: [{ selector: '[ngIf]' }]
3502 }], function () { return [{ type: ɵngcc0.ViewContainerRef }, { type: ɵngcc0.TemplateRef }]; }, { ngIf: [{
3503 type: Input
3504 }], ngIfThen: [{
3505 type: Input
3506 }], ngIfElse: [{
3507 type: Input
3508 }] }); })();
3509/**
3510 * @publicApi
3511 */
3512class NgIfContext {
3513 constructor() {
3514 this.$implicit = null;
3515 this.ngIf = null;
3516 }
3517}
3518function assertTemplate(property, templateRef) {
3519 const isTemplateRefOrNull = !!(!templateRef || templateRef.createEmbeddedView);
3520 if (!isTemplateRefOrNull) {
3521 throw new Error(`${property} must be a TemplateRef, but received '${ɵstringify(templateRef)}'.`);
3522 }
3523}
3524
3525/**
3526 * @license
3527 * Copyright Google LLC All Rights Reserved.
3528 *
3529 * Use of this source code is governed by an MIT-style license that can be
3530 * found in the LICENSE file at https://angular.io/license
3531 */
3532class SwitchView {
3533 constructor(_viewContainerRef, _templateRef) {
3534 this._viewContainerRef = _viewContainerRef;
3535 this._templateRef = _templateRef;
3536 this._created = false;
3537 }
3538 create() {
3539 this._created = true;
3540 this._viewContainerRef.createEmbeddedView(this._templateRef);
3541 }
3542 destroy() {
3543 this._created = false;
3544 this._viewContainerRef.clear();
3545 }
3546 enforceState(created) {
3547 if (created && !this._created) {
3548 this.create();
3549 }
3550 else if (!created && this._created) {
3551 this.destroy();
3552 }
3553 }
3554}
3555/**
3556 * @ngModule CommonModule
3557 *
3558 * @description
3559 * The `[ngSwitch]` directive on a container specifies an expression to match against.
3560 * The expressions to match are provided by `ngSwitchCase` directives on views within the container.
3561 * - Every view that matches is rendered.
3562 * - If there are no matches, a view with the `ngSwitchDefault` directive is rendered.
3563 * - Elements within the `[NgSwitch]` statement but outside of any `NgSwitchCase`
3564 * or `ngSwitchDefault` directive are preserved at the location.
3565 *
3566 * @usageNotes
3567 * Define a container element for the directive, and specify the switch expression
3568 * to match against as an attribute:
3569 *
3570 * ```
3571 * <container-element [ngSwitch]="switch_expression">
3572 * ```
3573 *
3574 * Within the container, `*ngSwitchCase` statements specify the match expressions
3575 * as attributes. Include `*ngSwitchDefault` as the final case.
3576 *
3577 * ```
3578 * <container-element [ngSwitch]="switch_expression">
3579 * <some-element *ngSwitchCase="match_expression_1">...</some-element>
3580 * ...
3581 * <some-element *ngSwitchDefault>...</some-element>
3582 * </container-element>
3583 * ```
3584 *
3585 * ### Usage Examples
3586 *
3587 * The following example shows how to use more than one case to display the same view:
3588 *
3589 * ```
3590 * <container-element [ngSwitch]="switch_expression">
3591 * <!-- the same view can be shown in more than one case -->
3592 * <some-element *ngSwitchCase="match_expression_1">...</some-element>
3593 * <some-element *ngSwitchCase="match_expression_2">...</some-element>
3594 * <some-other-element *ngSwitchCase="match_expression_3">...</some-other-element>
3595 * <!--default case when there are no matches -->
3596 * <some-element *ngSwitchDefault>...</some-element>
3597 * </container-element>
3598 * ```
3599 *
3600 * The following example shows how cases can be nested:
3601 * ```
3602 * <container-element [ngSwitch]="switch_expression">
3603 * <some-element *ngSwitchCase="match_expression_1">...</some-element>
3604 * <some-element *ngSwitchCase="match_expression_2">...</some-element>
3605 * <some-other-element *ngSwitchCase="match_expression_3">...</some-other-element>
3606 * <ng-container *ngSwitchCase="match_expression_3">
3607 * <!-- use a ng-container to group multiple root nodes -->
3608 * <inner-element></inner-element>
3609 * <inner-other-element></inner-other-element>
3610 * </ng-container>
3611 * <some-element *ngSwitchDefault>...</some-element>
3612 * </container-element>
3613 * ```
3614 *
3615 * @publicApi
3616 * @see `NgSwitchCase`
3617 * @see `NgSwitchDefault`
3618 * @see [Structural Directives](guide/structural-directives)
3619 *
3620 */
3621class NgSwitch {
3622 constructor() {
3623 this._defaultUsed = false;
3624 this._caseCount = 0;
3625 this._lastCaseCheckIndex = 0;
3626 this._lastCasesMatched = false;
3627 }
3628 set ngSwitch(newValue) {
3629 this._ngSwitch = newValue;
3630 if (this._caseCount === 0) {
3631 this._updateDefaultCases(true);
3632 }
3633 }
3634 /** @internal */
3635 _addCase() {
3636 return this._caseCount++;
3637 }
3638 /** @internal */
3639 _addDefault(view) {
3640 if (!this._defaultViews) {
3641 this._defaultViews = [];
3642 }
3643 this._defaultViews.push(view);
3644 }
3645 /** @internal */
3646 _matchCase(value) {
3647 const matched = value == this._ngSwitch;
3648 this._lastCasesMatched = this._lastCasesMatched || matched;
3649 this._lastCaseCheckIndex++;
3650 if (this._lastCaseCheckIndex === this._caseCount) {
3651 this._updateDefaultCases(!this._lastCasesMatched);
3652 this._lastCaseCheckIndex = 0;
3653 this._lastCasesMatched = false;
3654 }
3655 return matched;
3656 }
3657 _updateDefaultCases(useDefault) {
3658 if (this._defaultViews && useDefault !== this._defaultUsed) {
3659 this._defaultUsed = useDefault;
3660 for (let i = 0; i < this._defaultViews.length; i++) {
3661 const defaultView = this._defaultViews[i];
3662 defaultView.enforceState(useDefault);
3663 }
3664 }
3665 }
3666}
3667NgSwitch.ɵfac = function NgSwitch_Factory(t) { return new (t || NgSwitch)(); };
3668NgSwitch.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgSwitch, selectors: [["", "ngSwitch", ""]], inputs: { ngSwitch: "ngSwitch" } });
3669NgSwitch.propDecorators = {
3670 ngSwitch: [{ type: Input }]
3671};
3672(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgSwitch, [{
3673 type: Directive,
3674 args: [{ selector: '[ngSwitch]' }]
3675 }], function () { return []; }, { ngSwitch: [{
3676 type: Input
3677 }] }); })();
3678/**
3679 * @ngModule CommonModule
3680 *
3681 * @description
3682 * Provides a switch case expression to match against an enclosing `ngSwitch` expression.
3683 * When the expressions match, the given `NgSwitchCase` template is rendered.
3684 * If multiple match expressions match the switch expression value, all of them are displayed.
3685 *
3686 * @usageNotes
3687 *
3688 * Within a switch container, `*ngSwitchCase` statements specify the match expressions
3689 * as attributes. Include `*ngSwitchDefault` as the final case.
3690 *
3691 * ```
3692 * <container-element [ngSwitch]="switch_expression">
3693 * <some-element *ngSwitchCase="match_expression_1">...</some-element>
3694 * ...
3695 * <some-element *ngSwitchDefault>...</some-element>
3696 * </container-element>
3697 * ```
3698 *
3699 * Each switch-case statement contains an in-line HTML template or template reference
3700 * that defines the subtree to be selected if the value of the match expression
3701 * matches the value of the switch expression.
3702 *
3703 * Unlike JavaScript, which uses strict equality, Angular uses loose equality.
3704 * This means that the empty string, `""` matches 0.
3705 *
3706 * @publicApi
3707 * @see `NgSwitch`
3708 * @see `NgSwitchDefault`
3709 *
3710 */
3711class NgSwitchCase {
3712 constructor(viewContainer, templateRef, ngSwitch) {
3713 this.ngSwitch = ngSwitch;
3714 if ((typeof ngDevMode === 'undefined' || ngDevMode) && !ngSwitch) {
3715 throwNgSwitchProviderNotFoundError('ngSwitchCase', 'NgSwitchCase');
3716 }
3717 ngSwitch._addCase();
3718 this._view = new SwitchView(viewContainer, templateRef);
3719 }
3720 /**
3721 * Performs case matching. For internal use only.
3722 */
3723 ngDoCheck() {
3724 this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase));
3725 }
3726}
3727NgSwitchCase.ɵfac = function NgSwitchCase_Factory(t) { return new (t || NgSwitchCase)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.TemplateRef), ɵngcc0.ɵɵdirectiveInject(NgSwitch, 9)); };
3728NgSwitchCase.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgSwitchCase, selectors: [["", "ngSwitchCase", ""]], inputs: { ngSwitchCase: "ngSwitchCase" } });
3729NgSwitchCase.ctorParameters = () => [
3730 { type: ViewContainerRef },
3731 { type: TemplateRef },
3732 { type: NgSwitch, decorators: [{ type: Optional }, { type: Host }] }
3733];
3734NgSwitchCase.propDecorators = {
3735 ngSwitchCase: [{ type: Input }]
3736};
3737(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgSwitchCase, [{
3738 type: Directive,
3739 args: [{ selector: '[ngSwitchCase]' }]
3740 }], function () { return [{ type: ɵngcc0.ViewContainerRef }, { type: ɵngcc0.TemplateRef }, { type: NgSwitch, decorators: [{
3741 type: Optional
3742 }, {
3743 type: Host
3744 }] }]; }, { ngSwitchCase: [{
3745 type: Input
3746 }] }); })();
3747/**
3748 * @ngModule CommonModule
3749 *
3750 * @description
3751 *
3752 * Creates a view that is rendered when no `NgSwitchCase` expressions
3753 * match the `NgSwitch` expression.
3754 * This statement should be the final case in an `NgSwitch`.
3755 *
3756 * @publicApi
3757 * @see `NgSwitch`
3758 * @see `NgSwitchCase`
3759 *
3760 */
3761class NgSwitchDefault {
3762 constructor(viewContainer, templateRef, ngSwitch) {
3763 if ((typeof ngDevMode === 'undefined' || ngDevMode) && !ngSwitch) {
3764 throwNgSwitchProviderNotFoundError('ngSwitchDefault', 'NgSwitchDefault');
3765 }
3766 ngSwitch._addDefault(new SwitchView(viewContainer, templateRef));
3767 }
3768}
3769NgSwitchDefault.ɵfac = function NgSwitchDefault_Factory(t) { return new (t || NgSwitchDefault)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.TemplateRef), ɵngcc0.ɵɵdirectiveInject(NgSwitch, 9)); };
3770NgSwitchDefault.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgSwitchDefault, selectors: [["", "ngSwitchDefault", ""]] });
3771NgSwitchDefault.ctorParameters = () => [
3772 { type: ViewContainerRef },
3773 { type: TemplateRef },
3774 { type: NgSwitch, decorators: [{ type: Optional }, { type: Host }] }
3775];
3776(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgSwitchDefault, [{
3777 type: Directive,
3778 args: [{ selector: '[ngSwitchDefault]' }]
3779 }], function () { return [{ type: ɵngcc0.ViewContainerRef }, { type: ɵngcc0.TemplateRef }, { type: NgSwitch, decorators: [{
3780 type: Optional
3781 }, {
3782 type: Host
3783 }] }]; }, null); })();
3784function throwNgSwitchProviderNotFoundError(attrName, directiveName) {
3785 throw new ɵRuntimeError("305" /* TEMPLATE_STRUCTURE_ERROR */, `An element with the "${attrName}" attribute ` +
3786 `(matching the "${directiveName}" directive) must be located inside an element with the "ngSwitch" attribute ` +
3787 `(matching "NgSwitch" directive)`);
3788}
3789
3790/**
3791 * @license
3792 * Copyright Google LLC All Rights Reserved.
3793 *
3794 * Use of this source code is governed by an MIT-style license that can be
3795 * found in the LICENSE file at https://angular.io/license
3796 */
3797/**
3798 * @ngModule CommonModule
3799 *
3800 * @usageNotes
3801 * ```
3802 * <some-element [ngPlural]="value">
3803 * <ng-template ngPluralCase="=0">there is nothing</ng-template>
3804 * <ng-template ngPluralCase="=1">there is one</ng-template>
3805 * <ng-template ngPluralCase="few">there are a few</ng-template>
3806 * </some-element>
3807 * ```
3808 *
3809 * @description
3810 *
3811 * Adds / removes DOM sub-trees based on a numeric value. Tailored for pluralization.
3812 *
3813 * Displays DOM sub-trees that match the switch expression value, or failing that, DOM sub-trees
3814 * that match the switch expression's pluralization category.
3815 *
3816 * To use this directive you must provide a container element that sets the `[ngPlural]` attribute
3817 * to a switch expression. Inner elements with a `[ngPluralCase]` will display based on their
3818 * expression:
3819 * - if `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value
3820 * matches the switch expression exactly,
3821 * - otherwise, the view will be treated as a "category match", and will only display if exact
3822 * value matches aren't found and the value maps to its category for the defined locale.
3823 *
3824 * See http://cldr.unicode.org/index/cldr-spec/plural-rules
3825 *
3826 * @publicApi
3827 */
3828class NgPlural {
3829 constructor(_localization) {
3830 this._localization = _localization;
3831 this._caseViews = {};
3832 }
3833 set ngPlural(value) {
3834 this._switchValue = value;
3835 this._updateView();
3836 }
3837 addCase(value, switchView) {
3838 this._caseViews[value] = switchView;
3839 }
3840 _updateView() {
3841 this._clearViews();
3842 const cases = Object.keys(this._caseViews);
3843 const key = getPluralCategory(this._switchValue, cases, this._localization);
3844 this._activateView(this._caseViews[key]);
3845 }
3846 _clearViews() {
3847 if (this._activeView)
3848 this._activeView.destroy();
3849 }
3850 _activateView(view) {
3851 if (view) {
3852 this._activeView = view;
3853 this._activeView.create();
3854 }
3855 }
3856}
3857NgPlural.ɵfac = function NgPlural_Factory(t) { return new (t || NgPlural)(ɵngcc0.ɵɵdirectiveInject(NgLocalization)); };
3858NgPlural.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgPlural, selectors: [["", "ngPlural", ""]], inputs: { ngPlural: "ngPlural" } });
3859NgPlural.ctorParameters = () => [
3860 { type: NgLocalization }
3861];
3862NgPlural.propDecorators = {
3863 ngPlural: [{ type: Input }]
3864};
3865(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgPlural, [{
3866 type: Directive,
3867 args: [{ selector: '[ngPlural]' }]
3868 }], function () { return [{ type: NgLocalization }]; }, { ngPlural: [{
3869 type: Input
3870 }] }); })();
3871/**
3872 * @ngModule CommonModule
3873 *
3874 * @description
3875 *
3876 * Creates a view that will be added/removed from the parent {@link NgPlural} when the
3877 * given expression matches the plural expression according to CLDR rules.
3878 *
3879 * @usageNotes
3880 * ```
3881 * <some-element [ngPlural]="value">
3882 * <ng-template ngPluralCase="=0">...</ng-template>
3883 * <ng-template ngPluralCase="other">...</ng-template>
3884 * </some-element>
3885 *```
3886 *
3887 * See {@link NgPlural} for more details and example.
3888 *
3889 * @publicApi
3890 */
3891class NgPluralCase {
3892 constructor(value, template, viewContainer, ngPlural) {
3893 this.value = value;
3894 const isANumber = !isNaN(Number(value));
3895 ngPlural.addCase(isANumber ? `=${value}` : value, new SwitchView(viewContainer, template));
3896 }
3897}
3898NgPluralCase.ɵfac = function NgPluralCase_Factory(t) { return new (t || NgPluralCase)(ɵngcc0.ɵɵinjectAttribute('ngPluralCase'), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.TemplateRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef), ɵngcc0.ɵɵdirectiveInject(NgPlural, 1)); };
3899NgPluralCase.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgPluralCase, selectors: [["", "ngPluralCase", ""]] });
3900NgPluralCase.ctorParameters = () => [
3901 { type: String, decorators: [{ type: Attribute, args: ['ngPluralCase',] }] },
3902 { type: TemplateRef },
3903 { type: ViewContainerRef },
3904 { type: NgPlural, decorators: [{ type: Host }] }
3905];
3906(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgPluralCase, [{
3907 type: Directive,
3908 args: [{ selector: '[ngPluralCase]' }]
3909 }], function () { return [{ type: String, decorators: [{
3910 type: Attribute,
3911 args: ['ngPluralCase']
3912 }] }, { type: ɵngcc0.TemplateRef }, { type: ɵngcc0.ViewContainerRef }, { type: NgPlural, decorators: [{
3913 type: Host
3914 }] }]; }, null); })();
3915
3916/**
3917 * @license
3918 * Copyright Google LLC All Rights Reserved.
3919 *
3920 * Use of this source code is governed by an MIT-style license that can be
3921 * found in the LICENSE file at https://angular.io/license
3922 */
3923/**
3924 * @ngModule CommonModule
3925 *
3926 * @usageNotes
3927 *
3928 * Set the font of the containing element to the result of an expression.
3929 *
3930 * ```
3931 * <some-element [ngStyle]="{'font-style': styleExp}">...</some-element>
3932 * ```
3933 *
3934 * Set the width of the containing element to a pixel value returned by an expression.
3935 *
3936 * ```
3937 * <some-element [ngStyle]="{'max-width.px': widthExp}">...</some-element>
3938 * ```
3939 *
3940 * Set a collection of style values using an expression that returns key-value pairs.
3941 *
3942 * ```
3943 * <some-element [ngStyle]="objExp">...</some-element>
3944 * ```
3945 *
3946 * @description
3947 *
3948 * An attribute directive that updates styles for the containing HTML element.
3949 * Sets one or more style properties, specified as colon-separated key-value pairs.
3950 * The key is a style name, with an optional `.<unit>` suffix
3951 * (such as 'top.px', 'font-style.em').
3952 * The value is an expression to be evaluated.
3953 * The resulting non-null value, expressed in the given unit,
3954 * is assigned to the given style property.
3955 * If the result of evaluation is null, the corresponding style is removed.
3956 *
3957 * @publicApi
3958 */
3959class NgStyle {
3960 constructor(_ngEl, _differs, _renderer) {
3961 this._ngEl = _ngEl;
3962 this._differs = _differs;
3963 this._renderer = _renderer;
3964 this._ngStyle = null;
3965 this._differ = null;
3966 }
3967 set ngStyle(values) {
3968 this._ngStyle = values;
3969 if (!this._differ && values) {
3970 this._differ = this._differs.find(values).create();
3971 }
3972 }
3973 ngDoCheck() {
3974 if (this._differ) {
3975 const changes = this._differ.diff(this._ngStyle);
3976 if (changes) {
3977 this._applyChanges(changes);
3978 }
3979 }
3980 }
3981 _setStyle(nameAndUnit, value) {
3982 const [name, unit] = nameAndUnit.split('.');
3983 value = value != null && unit ? `${value}${unit}` : value;
3984 if (value != null) {
3985 this._renderer.setStyle(this._ngEl.nativeElement, name, value);
3986 }
3987 else {
3988 this._renderer.removeStyle(this._ngEl.nativeElement, name);
3989 }
3990 }
3991 _applyChanges(changes) {
3992 changes.forEachRemovedItem((record) => this._setStyle(record.key, null));
3993 changes.forEachAddedItem((record) => this._setStyle(record.key, record.currentValue));
3994 changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue));
3995 }
3996}
3997NgStyle.ɵfac = function NgStyle_Factory(t) { return new (t || NgStyle)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ElementRef), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.KeyValueDiffers), ɵngcc0.ɵɵdirectiveInject(ɵngcc0.Renderer2)); };
3998NgStyle.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgStyle, selectors: [["", "ngStyle", ""]], inputs: { ngStyle: "ngStyle" } });
3999NgStyle.ctorParameters = () => [
4000 { type: ElementRef },
4001 { type: KeyValueDiffers },
4002 { type: Renderer2 }
4003];
4004NgStyle.propDecorators = {
4005 ngStyle: [{ type: Input, args: ['ngStyle',] }]
4006};
4007(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgStyle, [{
4008 type: Directive,
4009 args: [{ selector: '[ngStyle]' }]
4010 }], function () { return [{ type: ɵngcc0.ElementRef }, { type: ɵngcc0.KeyValueDiffers }, { type: ɵngcc0.Renderer2 }]; }, { ngStyle: [{
4011 type: Input,
4012 args: ['ngStyle']
4013 }] }); })();
4014
4015/**
4016 * @license
4017 * Copyright Google LLC All Rights Reserved.
4018 *
4019 * Use of this source code is governed by an MIT-style license that can be
4020 * found in the LICENSE file at https://angular.io/license
4021 */
4022/**
4023 * @ngModule CommonModule
4024 *
4025 * @description
4026 *
4027 * Inserts an embedded view from a prepared `TemplateRef`.
4028 *
4029 * You can attach a context object to the `EmbeddedViewRef` by setting `[ngTemplateOutletContext]`.
4030 * `[ngTemplateOutletContext]` should be an object, the object's keys will be available for binding
4031 * by the local template `let` declarations.
4032 *
4033 * @usageNotes
4034 * ```
4035 * <ng-container *ngTemplateOutlet="templateRefExp; context: contextExp"></ng-container>
4036 * ```
4037 *
4038 * Using the key `$implicit` in the context object will set its value as default.
4039 *
4040 * ### Example
4041 *
4042 * {@example common/ngTemplateOutlet/ts/module.ts region='NgTemplateOutlet'}
4043 *
4044 * @publicApi
4045 */
4046class NgTemplateOutlet {
4047 constructor(_viewContainerRef) {
4048 this._viewContainerRef = _viewContainerRef;
4049 this._viewRef = null;
4050 /**
4051 * A context object to attach to the {@link EmbeddedViewRef}. This should be an
4052 * object, the object's keys will be available for binding by the local template `let`
4053 * declarations.
4054 * Using the key `$implicit` in the context object will set its value as default.
4055 */
4056 this.ngTemplateOutletContext = null;
4057 /**
4058 * A string defining the template reference and optionally the context object for the template.
4059 */
4060 this.ngTemplateOutlet = null;
4061 }
4062 ngOnChanges(changes) {
4063 if (changes['ngTemplateOutlet']) {
4064 const viewContainerRef = this._viewContainerRef;
4065 if (this._viewRef) {
4066 viewContainerRef.remove(viewContainerRef.indexOf(this._viewRef));
4067 }
4068 this._viewRef = this.ngTemplateOutlet ?
4069 viewContainerRef.createEmbeddedView(this.ngTemplateOutlet, this.ngTemplateOutletContext) :
4070 null;
4071 }
4072 else if (this._viewRef && changes['ngTemplateOutletContext'] && this.ngTemplateOutletContext) {
4073 this._viewRef.context = this.ngTemplateOutletContext;
4074 }
4075 }
4076}
4077NgTemplateOutlet.ɵfac = function NgTemplateOutlet_Factory(t) { return new (t || NgTemplateOutlet)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ViewContainerRef)); };
4078NgTemplateOutlet.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: NgTemplateOutlet, selectors: [["", "ngTemplateOutlet", ""]], inputs: { ngTemplateOutletContext: "ngTemplateOutletContext", ngTemplateOutlet: "ngTemplateOutlet" }, features: [ɵngcc0.ɵɵNgOnChangesFeature] });
4079NgTemplateOutlet.ctorParameters = () => [
4080 { type: ViewContainerRef }
4081];
4082NgTemplateOutlet.propDecorators = {
4083 ngTemplateOutletContext: [{ type: Input }],
4084 ngTemplateOutlet: [{ type: Input }]
4085};
4086(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(NgTemplateOutlet, [{
4087 type: Directive,
4088 args: [{ selector: '[ngTemplateOutlet]' }]
4089 }], function () { return [{ type: ɵngcc0.ViewContainerRef }]; }, { ngTemplateOutletContext: [{
4090 type: Input
4091 }], ngTemplateOutlet: [{
4092 type: Input
4093 }] }); })();
4094
4095/**
4096 * @license
4097 * Copyright Google LLC All Rights Reserved.
4098 *
4099 * Use of this source code is governed by an MIT-style license that can be
4100 * found in the LICENSE file at https://angular.io/license
4101 */
4102/**
4103 * A collection of Angular directives that are likely to be used in each and every Angular
4104 * application.
4105 */
4106const COMMON_DIRECTIVES = [
4107 NgClass,
4108 NgComponentOutlet,
4109 NgForOf,
4110 NgIf,
4111 NgTemplateOutlet,
4112 NgStyle,
4113 NgSwitch,
4114 NgSwitchCase,
4115 NgSwitchDefault,
4116 NgPlural,
4117 NgPluralCase,
4118];
4119
4120/**
4121 * @license
4122 * Copyright Google LLC All Rights Reserved.
4123 *
4124 * Use of this source code is governed by an MIT-style license that can be
4125 * found in the LICENSE file at https://angular.io/license
4126 */
4127function invalidPipeArgumentError(type, value) {
4128 return Error(`InvalidPipeArgument: '${value}' for pipe '${ɵstringify(type)}'`);
4129}
4130
4131/**
4132 * @license
4133 * Copyright Google LLC All Rights Reserved.
4134 *
4135 * Use of this source code is governed by an MIT-style license that can be
4136 * found in the LICENSE file at https://angular.io/license
4137 */
4138class SubscribableStrategy {
4139 createSubscription(async, updateLatestValue) {
4140 return async.subscribe({
4141 next: updateLatestValue,
4142 error: (e) => {
4143 throw e;
4144 }
4145 });
4146 }
4147 dispose(subscription) {
4148 subscription.unsubscribe();
4149 }
4150 onDestroy(subscription) {
4151 subscription.unsubscribe();
4152 }
4153}
4154class PromiseStrategy {
4155 createSubscription(async, updateLatestValue) {
4156 return async.then(updateLatestValue, e => {
4157 throw e;
4158 });
4159 }
4160 dispose(subscription) { }
4161 onDestroy(subscription) { }
4162}
4163const _promiseStrategy = new PromiseStrategy();
4164const _subscribableStrategy = new SubscribableStrategy();
4165/**
4166 * @ngModule CommonModule
4167 * @description
4168 *
4169 * Unwraps a value from an asynchronous primitive.
4170 *
4171 * The `async` pipe subscribes to an `Observable` or `Promise` and returns the latest value it has
4172 * emitted. When a new value is emitted, the `async` pipe marks the component to be checked for
4173 * changes. When the component gets destroyed, the `async` pipe unsubscribes automatically to avoid
4174 * potential memory leaks. When the reference of the expression changes, the `async` pipe
4175 * automatically unsubscribes from the old `Observable` or `Promise` and subscribes to the new one.
4176 *
4177 * @usageNotes
4178 *
4179 * ### Examples
4180 *
4181 * This example binds a `Promise` to the view. Clicking the `Resolve` button resolves the
4182 * promise.
4183 *
4184 * {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'}
4185 *
4186 * It's also possible to use `async` with Observables. The example below binds the `time` Observable
4187 * to the view. The Observable continuously updates the view with the current time.
4188 *
4189 * {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'}
4190 *
4191 * @publicApi
4192 */
4193class AsyncPipe {
4194 constructor(_ref) {
4195 this._ref = _ref;
4196 this._latestValue = null;
4197 this._subscription = null;
4198 this._obj = null;
4199 this._strategy = null;
4200 }
4201 ngOnDestroy() {
4202 if (this._subscription) {
4203 this._dispose();
4204 }
4205 }
4206 transform(obj) {
4207 if (!this._obj) {
4208 if (obj) {
4209 this._subscribe(obj);
4210 }
4211 return this._latestValue;
4212 }
4213 if (obj !== this._obj) {
4214 this._dispose();
4215 return this.transform(obj);
4216 }
4217 return this._latestValue;
4218 }
4219 _subscribe(obj) {
4220 this._obj = obj;
4221 this._strategy = this._selectStrategy(obj);
4222 this._subscription = this._strategy.createSubscription(obj, (value) => this._updateLatestValue(obj, value));
4223 }
4224 _selectStrategy(obj) {
4225 if (ɵisPromise(obj)) {
4226 return _promiseStrategy;
4227 }
4228 if (ɵisSubscribable(obj)) {
4229 return _subscribableStrategy;
4230 }
4231 throw invalidPipeArgumentError(AsyncPipe, obj);
4232 }
4233 _dispose() {
4234 this._strategy.dispose(this._subscription);
4235 this._latestValue = null;
4236 this._subscription = null;
4237 this._obj = null;
4238 }
4239 _updateLatestValue(async, value) {
4240 if (async === this._obj) {
4241 this._latestValue = value;
4242 this._ref.markForCheck();
4243 }
4244 }
4245}
4246AsyncPipe.ɵfac = function AsyncPipe_Factory(t) { return new (t || AsyncPipe)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.ChangeDetectorRef, 16)); };
4247AsyncPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "async", type: AsyncPipe, pure: false });
4248AsyncPipe.ctorParameters = () => [
4249 { type: ChangeDetectorRef }
4250];
4251(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(AsyncPipe, [{
4252 type: Pipe,
4253 args: [{ name: 'async', pure: false }]
4254 }], function () { return [{ type: ɵngcc0.ChangeDetectorRef }]; }, null); })();
4255
4256/**
4257 * @license
4258 * Copyright Google LLC All Rights Reserved.
4259 *
4260 * Use of this source code is governed by an MIT-style license that can be
4261 * found in the LICENSE file at https://angular.io/license
4262 */
4263/**
4264 * Transforms text to all lower case.
4265 *
4266 * @see `UpperCasePipe`
4267 * @see `TitleCasePipe`
4268 * @usageNotes
4269 *
4270 * The following example defines a view that allows the user to enter
4271 * text, and then uses the pipe to convert the input text to all lower case.
4272 *
4273 * <code-example path="common/pipes/ts/lowerupper_pipe.ts" region='LowerUpperPipe'></code-example>
4274 *
4275 * @ngModule CommonModule
4276 * @publicApi
4277 */
4278class LowerCasePipe {
4279 transform(value) {
4280 if (value == null)
4281 return null;
4282 if (typeof value !== 'string') {
4283 throw invalidPipeArgumentError(LowerCasePipe, value);
4284 }
4285 return value.toLowerCase();
4286 }
4287}
4288LowerCasePipe.ɵfac = function LowerCasePipe_Factory(t) { return new (t || LowerCasePipe)(); };
4289LowerCasePipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "lowercase", type: LowerCasePipe, pure: true });
4290(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(LowerCasePipe, [{
4291 type: Pipe,
4292 args: [{ name: 'lowercase' }]
4293 }], null, null); })();
4294//
4295// Regex below matches any Unicode word and number compatible with ES5. In ES2018 the same result
4296// can be achieved by using /[0-9\p{L}]\S*/gu and also known as Unicode Property Escapes
4297// (https://2ality.com/2017/07/regexp-unicode-property-escapes.html). Since there is no
4298// transpilation of this functionality down to ES5 without external tool, the only solution is
4299// to use already transpiled form. Example can be found here -
4300// https://mothereff.in/regexpu#input=var+regex+%3D+%2F%5B0-9%5Cp%7BL%7D%5D%5CS*%2Fgu%3B%0A%0A&unicodePropertyEscape=1
4301//
4302const unicodeWordMatch = /(?:[0-9A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A\uDF40-\uDF46]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEB0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD837[\uDF00-\uDF1E]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF38\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])\S*/g;
4303/**
4304 * Transforms text to title case.
4305 * Capitalizes the first letter of each word and transforms the
4306 * rest of the word to lower case.
4307 * Words are delimited by any whitespace character, such as a space, tab, or line-feed character.
4308 *
4309 * @see `LowerCasePipe`
4310 * @see `UpperCasePipe`
4311 *
4312 * @usageNotes
4313 * The following example shows the result of transforming various strings into title case.
4314 *
4315 * <code-example path="common/pipes/ts/titlecase_pipe.ts" region='TitleCasePipe'></code-example>
4316 *
4317 * @ngModule CommonModule
4318 * @publicApi
4319 */
4320class TitleCasePipe {
4321 transform(value) {
4322 if (value == null)
4323 return null;
4324 if (typeof value !== 'string') {
4325 throw invalidPipeArgumentError(TitleCasePipe, value);
4326 }
4327 return value.replace(unicodeWordMatch, (txt => txt[0].toUpperCase() + txt.substr(1).toLowerCase()));
4328 }
4329}
4330TitleCasePipe.ɵfac = function TitleCasePipe_Factory(t) { return new (t || TitleCasePipe)(); };
4331TitleCasePipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "titlecase", type: TitleCasePipe, pure: true });
4332(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(TitleCasePipe, [{
4333 type: Pipe,
4334 args: [{ name: 'titlecase' }]
4335 }], null, null); })();
4336/**
4337 * Transforms text to all upper case.
4338 * @see `LowerCasePipe`
4339 * @see `TitleCasePipe`
4340 *
4341 * @ngModule CommonModule
4342 * @publicApi
4343 */
4344class UpperCasePipe {
4345 transform(value) {
4346 if (value == null)
4347 return null;
4348 if (typeof value !== 'string') {
4349 throw invalidPipeArgumentError(UpperCasePipe, value);
4350 }
4351 return value.toUpperCase();
4352 }
4353}
4354UpperCasePipe.ɵfac = function UpperCasePipe_Factory(t) { return new (t || UpperCasePipe)(); };
4355UpperCasePipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "uppercase", type: UpperCasePipe, pure: true });
4356(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(UpperCasePipe, [{
4357 type: Pipe,
4358 args: [{ name: 'uppercase' }]
4359 }], null, null); })();
4360
4361/**
4362 * @license
4363 * Copyright Google LLC All Rights Reserved.
4364 *
4365 * Use of this source code is governed by an MIT-style license that can be
4366 * found in the LICENSE file at https://angular.io/license
4367 */
4368// clang-format off
4369/**
4370 * @ngModule CommonModule
4371 * @description
4372 *
4373 * Formats a date value according to locale rules.
4374 *
4375 * `DatePipe` is executed only when it detects a pure change to the input value.
4376 * A pure change is either a change to a primitive input value
4377 * (such as `String`, `Number`, `Boolean`, or `Symbol`),
4378 * or a changed object reference (such as `Date`, `Array`, `Function`, or `Object`).
4379 *
4380 * Note that mutating a `Date` object does not cause the pipe to be rendered again.
4381 * To ensure that the pipe is executed, you must create a new `Date` object.
4382 *
4383 * Only the `en-US` locale data comes with Angular. To localize dates
4384 * in another language, you must import the corresponding locale data.
4385 * See the [I18n guide](guide/i18n-common-format-data-locale) for more information.
4386 *
4387 * @see `formatDate()`
4388 *
4389 *
4390 * @usageNotes
4391 *
4392 * The result of this pipe is not reevaluated when the input is mutated. To avoid the need to
4393 * reformat the date on every change-detection cycle, treat the date as an immutable object
4394 * and change the reference when the pipe needs to run again.
4395 *
4396 * ### Pre-defined format options
4397 *
4398 * | Option | Equivalent to | Examples (given in `en-US` locale) |
4399 * |---------------|-------------------------------------|-------------------------------------------------|
4400 * | `'short'` | `'M/d/yy, h:mm a'` | `6/15/15, 9:03 AM` |
4401 * | `'medium'` | `'MMM d, y, h:mm:ss a'` | `Jun 15, 2015, 9:03:01 AM` |
4402 * | `'long'` | `'MMMM d, y, h:mm:ss a z'` | `June 15, 2015 at 9:03:01 AM GMT+1` |
4403 * | `'full'` | `'EEEE, MMMM d, y, h:mm:ss a zzzz'` | `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00` |
4404 * | `'shortDate'` | `'M/d/yy'` | `6/15/15` |
4405 * | `'mediumDate'`| `'MMM d, y'` | `Jun 15, 2015` |
4406 * | `'longDate'` | `'MMMM d, y'` | `June 15, 2015` |
4407 * | `'fullDate'` | `'EEEE, MMMM d, y'` | `Monday, June 15, 2015` |
4408 * | `'shortTime'` | `'h:mm a'` | `9:03 AM` |
4409 * | `'mediumTime'`| `'h:mm:ss a'` | `9:03:01 AM` |
4410 * | `'longTime'` | `'h:mm:ss a z'` | `9:03:01 AM GMT+1` |
4411 * | `'fullTime'` | `'h:mm:ss a zzzz'` | `9:03:01 AM GMT+01:00` |
4412 *
4413 * ### Custom format options
4414 *
4415 * You can construct a format string using symbols to specify the components
4416 * of a date-time value, as described in the following table.
4417 * Format details depend on the locale.
4418 * Fields marked with (*) are only available in the extra data set for the given locale.
4419 *
4420 * | Field type | Format | Description | Example Value |
4421 * |-------------------- |-------------|---------------------------------------------------------------|------------------------------------------------------------|
4422 * | Era | G, GG & GGG | Abbreviated | AD |
4423 * | | GGGG | Wide | Anno Domini |
4424 * | | GGGGG | Narrow | A |
4425 * | Year | y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 |
4426 * | | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 |
4427 * | | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 |
4428 * | | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 |
4429 * | Week-numbering year | Y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 |
4430 * | | YY | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 |
4431 * | | YYY | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 |
4432 * | | YYYY | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 |
4433 * | Month | M | Numeric: 1 digit | 9, 12 |
4434 * | | MM | Numeric: 2 digits + zero padded | 09, 12 |
4435 * | | MMM | Abbreviated | Sep |
4436 * | | MMMM | Wide | September |
4437 * | | MMMMM | Narrow | S |
4438 * | Month standalone | L | Numeric: 1 digit | 9, 12 |
4439 * | | LL | Numeric: 2 digits + zero padded | 09, 12 |
4440 * | | LLL | Abbreviated | Sep |
4441 * | | LLLL | Wide | September |
4442 * | | LLLLL | Narrow | S |
4443 * | Week of year | w | Numeric: minimum digits | 1... 53 |
4444 * | | ww | Numeric: 2 digits + zero padded | 01... 53 |
4445 * | Week of month | W | Numeric: 1 digit | 1... 5 |
4446 * | Day of month | d | Numeric: minimum digits | 1 |
4447 * | | dd | Numeric: 2 digits + zero padded | 01 |
4448 * | Week day | E, EE & EEE | Abbreviated | Tue |
4449 * | | EEEE | Wide | Tuesday |
4450 * | | EEEEE | Narrow | T |
4451 * | | EEEEEE | Short | Tu |
4452 * | Week day standalone | c, cc | Numeric: 1 digit | 2 |
4453 * | | ccc | Abbreviated | Tue |
4454 * | | cccc | Wide | Tuesday |
4455 * | | ccccc | Narrow | T |
4456 * | | cccccc | Short | Tu |
4457 * | Period | a, aa & aaa | Abbreviated | am/pm or AM/PM |
4458 * | | aaaa | Wide (fallback to `a` when missing) | ante meridiem/post meridiem |
4459 * | | aaaaa | Narrow | a/p |
4460 * | Period* | B, BB & BBB | Abbreviated | mid. |
4461 * | | BBBB | Wide | am, pm, midnight, noon, morning, afternoon, evening, night |
4462 * | | BBBBB | Narrow | md |
4463 * | Period standalone* | b, bb & bbb | Abbreviated | mid. |
4464 * | | bbbb | Wide | am, pm, midnight, noon, morning, afternoon, evening, night |
4465 * | | bbbbb | Narrow | md |
4466 * | Hour 1-12 | h | Numeric: minimum digits | 1, 12 |
4467 * | | hh | Numeric: 2 digits + zero padded | 01, 12 |
4468 * | Hour 0-23 | H | Numeric: minimum digits | 0, 23 |
4469 * | | HH | Numeric: 2 digits + zero padded | 00, 23 |
4470 * | Minute | m | Numeric: minimum digits | 8, 59 |
4471 * | | mm | Numeric: 2 digits + zero padded | 08, 59 |
4472 * | Second | s | Numeric: minimum digits | 0... 59 |
4473 * | | ss | Numeric: 2 digits + zero padded | 00... 59 |
4474 * | Fractional seconds | S | Numeric: 1 digit | 0... 9 |
4475 * | | SS | Numeric: 2 digits + zero padded | 00... 99 |
4476 * | | SSS | Numeric: 3 digits + zero padded (= milliseconds) | 000... 999 |
4477 * | Zone | z, zz & zzz | Short specific non location format (fallback to O) | GMT-8 |
4478 * | | zzzz | Long specific non location format (fallback to OOOO) | GMT-08:00 |
4479 * | | Z, ZZ & ZZZ | ISO8601 basic format | -0800 |
4480 * | | ZZZZ | Long localized GMT format | GMT-8:00 |
4481 * | | ZZZZZ | ISO8601 extended format + Z indicator for offset 0 (= XXXXX) | -08:00 |
4482 * | | O, OO & OOO | Short localized GMT format | GMT-8 |
4483 * | | OOOO | Long localized GMT format | GMT-08:00 |
4484 *
4485 *
4486 * ### Format examples
4487 *
4488 * These examples transform a date into various formats,
4489 * assuming that `dateObj` is a JavaScript `Date` object for
4490 * year: 2015, month: 6, day: 15, hour: 21, minute: 43, second: 11,
4491 * given in the local time for the `en-US` locale.
4492 *
4493 * ```
4494 * {{ dateObj | date }} // output is 'Jun 15, 2015'
4495 * {{ dateObj | date:'medium' }} // output is 'Jun 15, 2015, 9:43:11 PM'
4496 * {{ dateObj | date:'shortTime' }} // output is '9:43 PM'
4497 * {{ dateObj | date:'mm:ss' }} // output is '43:11'
4498 * ```
4499 *
4500 * ### Usage example
4501 *
4502 * The following component uses a date pipe to display the current date in different formats.
4503 *
4504 * ```
4505 * @Component({
4506 * selector: 'date-pipe',
4507 * template: `<div>
4508 * <p>Today is {{today | date}}</p>
4509 * <p>Or if you prefer, {{today | date:'fullDate'}}</p>
4510 * <p>The time is {{today | date:'h:mm a z'}}</p>
4511 * </div>`
4512 * })
4513 * // Get the current date and time as a date-time value.
4514 * export class DatePipeComponent {
4515 * today: number = Date.now();
4516 * }
4517 * ```
4518 *
4519 * @publicApi
4520 */
4521// clang-format on
4522class DatePipe {
4523 constructor(locale) {
4524 this.locale = locale;
4525 }
4526 transform(value, format = 'mediumDate', timezone, locale) {
4527 if (value == null || value === '' || value !== value)
4528 return null;
4529 try {
4530 return formatDate(value, format, locale || this.locale, timezone);
4531 }
4532 catch (error) {
4533 throw invalidPipeArgumentError(DatePipe, error.message);
4534 }
4535 }
4536}
4537DatePipe.ɵfac = function DatePipe_Factory(t) { return new (t || DatePipe)(ɵngcc0.ɵɵdirectiveInject(LOCALE_ID, 16)); };
4538DatePipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "date", type: DatePipe, pure: true });
4539DatePipe.ctorParameters = () => [
4540 { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] }
4541];
4542(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(DatePipe, [{
4543 type: Pipe,
4544 args: [{ name: 'date', pure: true }]
4545 }], function () { return [{ type: String, decorators: [{
4546 type: Inject,
4547 args: [LOCALE_ID]
4548 }] }]; }, null); })();
4549
4550/**
4551 * @license
4552 * Copyright Google LLC All Rights Reserved.
4553 *
4554 * Use of this source code is governed by an MIT-style license that can be
4555 * found in the LICENSE file at https://angular.io/license
4556 */
4557const _INTERPOLATION_REGEXP = /#/g;
4558/**
4559 * @ngModule CommonModule
4560 * @description
4561 *
4562 * Maps a value to a string that pluralizes the value according to locale rules.
4563 *
4564 * @usageNotes
4565 *
4566 * ### Example
4567 *
4568 * {@example common/pipes/ts/i18n_pipe.ts region='I18nPluralPipeComponent'}
4569 *
4570 * @publicApi
4571 */
4572class I18nPluralPipe {
4573 constructor(_localization) {
4574 this._localization = _localization;
4575 }
4576 /**
4577 * @param value the number to be formatted
4578 * @param pluralMap an object that mimics the ICU format, see
4579 * http://userguide.icu-project.org/formatparse/messages.
4580 * @param locale a `string` defining the locale to use (uses the current {@link LOCALE_ID} by
4581 * default).
4582 */
4583 transform(value, pluralMap, locale) {
4584 if (value == null)
4585 return '';
4586 if (typeof pluralMap !== 'object' || pluralMap === null) {
4587 throw invalidPipeArgumentError(I18nPluralPipe, pluralMap);
4588 }
4589 const key = getPluralCategory(value, Object.keys(pluralMap), this._localization, locale);
4590 return pluralMap[key].replace(_INTERPOLATION_REGEXP, value.toString());
4591 }
4592}
4593I18nPluralPipe.ɵfac = function I18nPluralPipe_Factory(t) { return new (t || I18nPluralPipe)(ɵngcc0.ɵɵdirectiveInject(NgLocalization, 16)); };
4594I18nPluralPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "i18nPlural", type: I18nPluralPipe, pure: true });
4595I18nPluralPipe.ctorParameters = () => [
4596 { type: NgLocalization }
4597];
4598(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(I18nPluralPipe, [{
4599 type: Pipe,
4600 args: [{ name: 'i18nPlural', pure: true }]
4601 }], function () { return [{ type: NgLocalization }]; }, null); })();
4602
4603/**
4604 * @license
4605 * Copyright Google LLC All Rights Reserved.
4606 *
4607 * Use of this source code is governed by an MIT-style license that can be
4608 * found in the LICENSE file at https://angular.io/license
4609 */
4610/**
4611 * @ngModule CommonModule
4612 * @description
4613 *
4614 * Generic selector that displays the string that matches the current value.
4615 *
4616 * If none of the keys of the `mapping` match the `value`, then the content
4617 * of the `other` key is returned when present, otherwise an empty string is returned.
4618 *
4619 * @usageNotes
4620 *
4621 * ### Example
4622 *
4623 * {@example common/pipes/ts/i18n_pipe.ts region='I18nSelectPipeComponent'}
4624 *
4625 * @publicApi
4626 */
4627class I18nSelectPipe {
4628 /**
4629 * @param value a string to be internationalized.
4630 * @param mapping an object that indicates the text that should be displayed
4631 * for different values of the provided `value`.
4632 */
4633 transform(value, mapping) {
4634 if (value == null)
4635 return '';
4636 if (typeof mapping !== 'object' || typeof value !== 'string') {
4637 throw invalidPipeArgumentError(I18nSelectPipe, mapping);
4638 }
4639 if (mapping.hasOwnProperty(value)) {
4640 return mapping[value];
4641 }
4642 if (mapping.hasOwnProperty('other')) {
4643 return mapping['other'];
4644 }
4645 return '';
4646 }
4647}
4648I18nSelectPipe.ɵfac = function I18nSelectPipe_Factory(t) { return new (t || I18nSelectPipe)(); };
4649I18nSelectPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "i18nSelect", type: I18nSelectPipe, pure: true });
4650(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(I18nSelectPipe, [{
4651 type: Pipe,
4652 args: [{ name: 'i18nSelect', pure: true }]
4653 }], null, null); })();
4654
4655/**
4656 * @license
4657 * Copyright Google LLC All Rights Reserved.
4658 *
4659 * Use of this source code is governed by an MIT-style license that can be
4660 * found in the LICENSE file at https://angular.io/license
4661 */
4662/**
4663 * @ngModule CommonModule
4664 * @description
4665 *
4666 * Converts a value into its JSON-format representation. Useful for debugging.
4667 *
4668 * @usageNotes
4669 *
4670 * The following component uses a JSON pipe to convert an object
4671 * to JSON format, and displays the string in both formats for comparison.
4672 *
4673 * {@example common/pipes/ts/json_pipe.ts region='JsonPipe'}
4674 *
4675 * @publicApi
4676 */
4677class JsonPipe {
4678 /**
4679 * @param value A value of any type to convert into a JSON-format string.
4680 */
4681 transform(value) {
4682 return JSON.stringify(value, null, 2);
4683 }
4684}
4685JsonPipe.ɵfac = function JsonPipe_Factory(t) { return new (t || JsonPipe)(); };
4686JsonPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "json", type: JsonPipe, pure: false });
4687(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(JsonPipe, [{
4688 type: Pipe,
4689 args: [{ name: 'json', pure: false }]
4690 }], null, null); })();
4691
4692/**
4693 * @license
4694 * Copyright Google LLC All Rights Reserved.
4695 *
4696 * Use of this source code is governed by an MIT-style license that can be
4697 * found in the LICENSE file at https://angular.io/license
4698 */
4699function makeKeyValuePair(key, value) {
4700 return { key: key, value: value };
4701}
4702/**
4703 * @ngModule CommonModule
4704 * @description
4705 *
4706 * Transforms Object or Map into an array of key value pairs.
4707 *
4708 * The output array will be ordered by keys.
4709 * By default the comparator will be by Unicode point value.
4710 * You can optionally pass a compareFn if your keys are complex types.
4711 *
4712 * @usageNotes
4713 * ### Examples
4714 *
4715 * This examples show how an Object or a Map can be iterated by ngFor with the use of this
4716 * keyvalue pipe.
4717 *
4718 * {@example common/pipes/ts/keyvalue_pipe.ts region='KeyValuePipe'}
4719 *
4720 * @publicApi
4721 */
4722class KeyValuePipe {
4723 constructor(differs) {
4724 this.differs = differs;
4725 this.keyValues = [];
4726 this.compareFn = defaultComparator;
4727 }
4728 transform(input, compareFn = defaultComparator) {
4729 if (!input || (!(input instanceof Map) && typeof input !== 'object')) {
4730 return null;
4731 }
4732 if (!this.differ) {
4733 // make a differ for whatever type we've been passed in
4734 this.differ = this.differs.find(input).create();
4735 }
4736 const differChanges = this.differ.diff(input);
4737 const compareFnChanged = compareFn !== this.compareFn;
4738 if (differChanges) {
4739 this.keyValues = [];
4740 differChanges.forEachItem((r) => {
4741 this.keyValues.push(makeKeyValuePair(r.key, r.currentValue));
4742 });
4743 }
4744 if (differChanges || compareFnChanged) {
4745 this.keyValues.sort(compareFn);
4746 this.compareFn = compareFn;
4747 }
4748 return this.keyValues;
4749 }
4750}
4751KeyValuePipe.ɵfac = function KeyValuePipe_Factory(t) { return new (t || KeyValuePipe)(ɵngcc0.ɵɵdirectiveInject(ɵngcc0.KeyValueDiffers, 16)); };
4752KeyValuePipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "keyvalue", type: KeyValuePipe, pure: false });
4753KeyValuePipe.ctorParameters = () => [
4754 { type: KeyValueDiffers }
4755];
4756(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(KeyValuePipe, [{
4757 type: Pipe,
4758 args: [{ name: 'keyvalue', pure: false }]
4759 }], function () { return [{ type: ɵngcc0.KeyValueDiffers }]; }, null); })();
4760function defaultComparator(keyValueA, keyValueB) {
4761 const a = keyValueA.key;
4762 const b = keyValueB.key;
4763 // if same exit with 0;
4764 if (a === b)
4765 return 0;
4766 // make sure that undefined are at the end of the sort.
4767 if (a === undefined)
4768 return 1;
4769 if (b === undefined)
4770 return -1;
4771 // make sure that nulls are at the end of the sort.
4772 if (a === null)
4773 return 1;
4774 if (b === null)
4775 return -1;
4776 if (typeof a == 'string' && typeof b == 'string') {
4777 return a < b ? -1 : 1;
4778 }
4779 if (typeof a == 'number' && typeof b == 'number') {
4780 return a - b;
4781 }
4782 if (typeof a == 'boolean' && typeof b == 'boolean') {
4783 return a < b ? -1 : 1;
4784 }
4785 // `a` and `b` are of different types. Compare their string values.
4786 const aString = String(a);
4787 const bString = String(b);
4788 return aString == bString ? 0 : aString < bString ? -1 : 1;
4789}
4790
4791/**
4792 * @license
4793 * Copyright Google LLC All Rights Reserved.
4794 *
4795 * Use of this source code is governed by an MIT-style license that can be
4796 * found in the LICENSE file at https://angular.io/license
4797 */
4798/**
4799 * @ngModule CommonModule
4800 * @description
4801 *
4802 * Formats a value according to digit options and locale rules.
4803 * Locale determines group sizing and separator,
4804 * decimal point character, and other locale-specific configurations.
4805 *
4806 * @see `formatNumber()`
4807 *
4808 * @usageNotes
4809 *
4810 * ### digitsInfo
4811 *
4812 * The value's decimal representation is specified by the `digitsInfo`
4813 * parameter, written in the following format:<br>
4814 *
4815 * ```
4816 * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}
4817 * ```
4818 *
4819 * - `minIntegerDigits`:
4820 * The minimum number of integer digits before the decimal point.
4821 * Default is 1.
4822 *
4823 * - `minFractionDigits`:
4824 * The minimum number of digits after the decimal point.
4825 * Default is 0.
4826 *
4827 * - `maxFractionDigits`:
4828 * The maximum number of digits after the decimal point.
4829 * Default is 3.
4830 *
4831 * If the formatted value is truncated it will be rounded using the "to-nearest" method:
4832 *
4833 * ```
4834 * {{3.6 | number: '1.0-0'}}
4835 * <!--will output '4'-->
4836 *
4837 * {{-3.6 | number:'1.0-0'}}
4838 * <!--will output '-4'-->
4839 * ```
4840 *
4841 * ### locale
4842 *
4843 * `locale` will format a value according to locale rules.
4844 * Locale determines group sizing and separator,
4845 * decimal point character, and other locale-specific configurations.
4846 *
4847 * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.
4848 *
4849 * See [Setting your app locale](guide/i18n-common-locale-id).
4850 *
4851 * ### Example
4852 *
4853 * The following code shows how the pipe transforms values
4854 * according to various format specifications,
4855 * where the caller's default locale is `en-US`.
4856 *
4857 * <code-example path="common/pipes/ts/number_pipe.ts" region='NumberPipe'></code-example>
4858 *
4859 * @publicApi
4860 */
4861class DecimalPipe {
4862 constructor(_locale) {
4863 this._locale = _locale;
4864 }
4865 /**
4866 * @param value The value to be formatted.
4867 * @param digitsInfo Sets digit and decimal representation.
4868 * [See more](#digitsinfo).
4869 * @param locale Specifies what locale format rules to use.
4870 * [See more](#locale).
4871 */
4872 transform(value, digitsInfo, locale) {
4873 if (!isValue(value))
4874 return null;
4875 locale = locale || this._locale;
4876 try {
4877 const num = strToNumber(value);
4878 return formatNumber(num, locale, digitsInfo);
4879 }
4880 catch (error) {
4881 throw invalidPipeArgumentError(DecimalPipe, error.message);
4882 }
4883 }
4884}
4885DecimalPipe.ɵfac = function DecimalPipe_Factory(t) { return new (t || DecimalPipe)(ɵngcc0.ɵɵdirectiveInject(LOCALE_ID, 16)); };
4886DecimalPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "number", type: DecimalPipe, pure: true });
4887DecimalPipe.ctorParameters = () => [
4888 { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] }
4889];
4890(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(DecimalPipe, [{
4891 type: Pipe,
4892 args: [{ name: 'number' }]
4893 }], function () { return [{ type: String, decorators: [{
4894 type: Inject,
4895 args: [LOCALE_ID]
4896 }] }]; }, null); })();
4897/**
4898 * @ngModule CommonModule
4899 * @description
4900 *
4901 * Transforms a number to a percentage
4902 * string, formatted according to locale rules that determine group sizing and
4903 * separator, decimal-point character, and other locale-specific
4904 * configurations.
4905 *
4906 * @see `formatPercent()`
4907 *
4908 * @usageNotes
4909 * The following code shows how the pipe transforms numbers
4910 * into text strings, according to various format specifications,
4911 * where the caller's default locale is `en-US`.
4912 *
4913 * <code-example path="common/pipes/ts/percent_pipe.ts" region='PercentPipe'></code-example>
4914 *
4915 * @publicApi
4916 */
4917class PercentPipe {
4918 constructor(_locale) {
4919 this._locale = _locale;
4920 }
4921 /**
4922 *
4923 * @param value The number to be formatted as a percentage.
4924 * @param digitsInfo Decimal representation options, specified by a string
4925 * in the following format:<br>
4926 * <code>{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}</code>.
4927 * - `minIntegerDigits`: The minimum number of integer digits before the decimal point.
4928 * Default is `1`.
4929 * - `minFractionDigits`: The minimum number of digits after the decimal point.
4930 * Default is `0`.
4931 * - `maxFractionDigits`: The maximum number of digits after the decimal point.
4932 * Default is `0`.
4933 * @param locale A locale code for the locale format rules to use.
4934 * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.
4935 * See [Setting your app locale](guide/i18n-common-locale-id).
4936 */
4937 transform(value, digitsInfo, locale) {
4938 if (!isValue(value))
4939 return null;
4940 locale = locale || this._locale;
4941 try {
4942 const num = strToNumber(value);
4943 return formatPercent(num, locale, digitsInfo);
4944 }
4945 catch (error) {
4946 throw invalidPipeArgumentError(PercentPipe, error.message);
4947 }
4948 }
4949}
4950PercentPipe.ɵfac = function PercentPipe_Factory(t) { return new (t || PercentPipe)(ɵngcc0.ɵɵdirectiveInject(LOCALE_ID, 16)); };
4951PercentPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "percent", type: PercentPipe, pure: true });
4952PercentPipe.ctorParameters = () => [
4953 { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] }
4954];
4955(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(PercentPipe, [{
4956 type: Pipe,
4957 args: [{ name: 'percent' }]
4958 }], function () { return [{ type: String, decorators: [{
4959 type: Inject,
4960 args: [LOCALE_ID]
4961 }] }]; }, null); })();
4962/**
4963 * @ngModule CommonModule
4964 * @description
4965 *
4966 * Transforms a number to a currency string, formatted according to locale rules
4967 * that determine group sizing and separator, decimal-point character,
4968 * and other locale-specific configurations.
4969 *
4970 * {@a currency-code-deprecation}
4971 * <div class="alert is-helpful">
4972 *
4973 * **Deprecation notice:**
4974 *
4975 * The default currency code is currently always `USD` but this is deprecated from v9.
4976 *
4977 * **In v11 the default currency code will be taken from the current locale identified by
4978 * the `LOCALE_ID` token. See the [i18n guide](guide/i18n-common-locale-id) for
4979 * more information.**
4980 *
4981 * If you need the previous behavior then set it by creating a `DEFAULT_CURRENCY_CODE` provider in
4982 * your application `NgModule`:
4983 *
4984 * ```ts
4985 * {provide: DEFAULT_CURRENCY_CODE, useValue: 'USD'}
4986 * ```
4987 *
4988 * </div>
4989 *
4990 * @see `getCurrencySymbol()`
4991 * @see `formatCurrency()`
4992 *
4993 * @usageNotes
4994 * The following code shows how the pipe transforms numbers
4995 * into text strings, according to various format specifications,
4996 * where the caller's default locale is `en-US`.
4997 *
4998 * <code-example path="common/pipes/ts/currency_pipe.ts" region='CurrencyPipe'></code-example>
4999 *
5000 * @publicApi
5001 */
5002class CurrencyPipe {
5003 constructor(_locale, _defaultCurrencyCode = 'USD') {
5004 this._locale = _locale;
5005 this._defaultCurrencyCode = _defaultCurrencyCode;
5006 }
5007 /**
5008 *
5009 * @param value The number to be formatted as currency.
5010 * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code,
5011 * such as `USD` for the US dollar and `EUR` for the euro. The default currency code can be
5012 * configured using the `DEFAULT_CURRENCY_CODE` injection token.
5013 * @param display The format for the currency indicator. One of the following:
5014 * - `code`: Show the code (such as `USD`).
5015 * - `symbol`(default): Show the symbol (such as `$`).
5016 * - `symbol-narrow`: Use the narrow symbol for locales that have two symbols for their
5017 * currency.
5018 * For example, the Canadian dollar CAD has the symbol `CA$` and the symbol-narrow `$`. If the
5019 * locale has no narrow symbol, uses the standard symbol for the locale.
5020 * - String: Use the given string value instead of a code or a symbol.
5021 * For example, an empty string will suppress the currency & symbol.
5022 * - Boolean (marked deprecated in v5): `true` for symbol and false for `code`.
5023 *
5024 * @param digitsInfo Decimal representation options, specified by a string
5025 * in the following format:<br>
5026 * <code>{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}</code>.
5027 * - `minIntegerDigits`: The minimum number of integer digits before the decimal point.
5028 * Default is `1`.
5029 * - `minFractionDigits`: The minimum number of digits after the decimal point.
5030 * Default is `2`.
5031 * - `maxFractionDigits`: The maximum number of digits after the decimal point.
5032 * Default is `2`.
5033 * If not provided, the number will be formatted with the proper amount of digits,
5034 * depending on what the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) specifies.
5035 * For example, the Canadian dollar has 2 digits, whereas the Chilean peso has none.
5036 * @param locale A locale code for the locale format rules to use.
5037 * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.
5038 * See [Setting your app locale](guide/i18n-common-locale-id).
5039 */
5040 transform(value, currencyCode = this._defaultCurrencyCode, display = 'symbol', digitsInfo, locale) {
5041 if (!isValue(value))
5042 return null;
5043 locale = locale || this._locale;
5044 if (typeof display === 'boolean') {
5045 if ((typeof ngDevMode === 'undefined' || ngDevMode) && console && console.warn) {
5046 console.warn(`Warning: the currency pipe has been changed in Angular v5. The symbolDisplay option (third parameter) is now a string instead of a boolean. The accepted values are "code", "symbol" or "symbol-narrow".`);
5047 }
5048 display = display ? 'symbol' : 'code';
5049 }
5050 let currency = currencyCode || this._defaultCurrencyCode;
5051 if (display !== 'code') {
5052 if (display === 'symbol' || display === 'symbol-narrow') {
5053 currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow', locale);
5054 }
5055 else {
5056 currency = display;
5057 }
5058 }
5059 try {
5060 const num = strToNumber(value);
5061 return formatCurrency(num, locale, currency, currencyCode, digitsInfo);
5062 }
5063 catch (error) {
5064 throw invalidPipeArgumentError(CurrencyPipe, error.message);
5065 }
5066 }
5067}
5068CurrencyPipe.ɵfac = function CurrencyPipe_Factory(t) { return new (t || CurrencyPipe)(ɵngcc0.ɵɵdirectiveInject(LOCALE_ID, 16), ɵngcc0.ɵɵdirectiveInject(DEFAULT_CURRENCY_CODE, 16)); };
5069CurrencyPipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "currency", type: CurrencyPipe, pure: true });
5070CurrencyPipe.ctorParameters = () => [
5071 { type: String, decorators: [{ type: Inject, args: [LOCALE_ID,] }] },
5072 { type: String, decorators: [{ type: Inject, args: [DEFAULT_CURRENCY_CODE,] }] }
5073];
5074(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(CurrencyPipe, [{
5075 type: Pipe,
5076 args: [{ name: 'currency' }]
5077 }], function () { return [{ type: String, decorators: [{
5078 type: Inject,
5079 args: [LOCALE_ID]
5080 }] }, { type: String, decorators: [{
5081 type: Inject,
5082 args: [DEFAULT_CURRENCY_CODE]
5083 }] }]; }, null); })();
5084function isValue(value) {
5085 return !(value == null || value === '' || value !== value);
5086}
5087/**
5088 * Transforms a string into a number (if needed).
5089 */
5090function strToNumber(value) {
5091 // Convert strings to numbers
5092 if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) {
5093 return Number(value);
5094 }
5095 if (typeof value !== 'number') {
5096 throw new Error(`${value} is not a number`);
5097 }
5098 return value;
5099}
5100
5101/**
5102 * @license
5103 * Copyright Google LLC All Rights Reserved.
5104 *
5105 * Use of this source code is governed by an MIT-style license that can be
5106 * found in the LICENSE file at https://angular.io/license
5107 */
5108/**
5109 * @ngModule CommonModule
5110 * @description
5111 *
5112 * Creates a new `Array` or `String` containing a subset (slice) of the elements.
5113 *
5114 * @usageNotes
5115 *
5116 * All behavior is based on the expected behavior of the JavaScript API `Array.prototype.slice()`
5117 * and `String.prototype.slice()`.
5118 *
5119 * When operating on an `Array`, the returned `Array` is always a copy even when all
5120 * the elements are being returned.
5121 *
5122 * When operating on a blank value, the pipe returns the blank value.
5123 *
5124 * ### List Example
5125 *
5126 * This `ngFor` example:
5127 *
5128 * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_list'}
5129 *
5130 * produces the following:
5131 *
5132 * ```html
5133 * <li>b</li>
5134 * <li>c</li>
5135 * ```
5136 *
5137 * ### String Examples
5138 *
5139 * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_string'}
5140 *
5141 * @publicApi
5142 */
5143class SlicePipe {
5144 transform(value, start, end) {
5145 if (value == null)
5146 return null;
5147 if (!this.supports(value)) {
5148 throw invalidPipeArgumentError(SlicePipe, value);
5149 }
5150 return value.slice(start, end);
5151 }
5152 supports(obj) {
5153 return typeof obj === 'string' || Array.isArray(obj);
5154 }
5155}
5156SlicePipe.ɵfac = function SlicePipe_Factory(t) { return new (t || SlicePipe)(); };
5157SlicePipe.ɵpipe = /*@__PURE__*/ ɵngcc0.ɵɵdefinePipe({ name: "slice", type: SlicePipe, pure: false });
5158(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(SlicePipe, [{
5159 type: Pipe,
5160 args: [{ name: 'slice', pure: false }]
5161 }], null, null); })();
5162
5163/**
5164 * @license
5165 * Copyright Google LLC All Rights Reserved.
5166 *
5167 * Use of this source code is governed by an MIT-style license that can be
5168 * found in the LICENSE file at https://angular.io/license
5169 */
5170/**
5171 * A collection of Angular pipes that are likely to be used in each and every application.
5172 */
5173const COMMON_PIPES = [
5174 AsyncPipe,
5175 UpperCasePipe,
5176 LowerCasePipe,
5177 JsonPipe,
5178 SlicePipe,
5179 DecimalPipe,
5180 PercentPipe,
5181 TitleCasePipe,
5182 CurrencyPipe,
5183 DatePipe,
5184 I18nPluralPipe,
5185 I18nSelectPipe,
5186 KeyValuePipe,
5187];
5188
5189/**
5190 * @license
5191 * Copyright Google LLC All Rights Reserved.
5192 *
5193 * Use of this source code is governed by an MIT-style license that can be
5194 * found in the LICENSE file at https://angular.io/license
5195 */
5196// Note: This does not contain the location providers,
5197// as they need some platform specific implementations to work.
5198/**
5199 * Exports all the basic Angular directives and pipes,
5200 * such as `NgIf`, `NgForOf`, `DecimalPipe`, and so on.
5201 * Re-exported by `BrowserModule`, which is included automatically in the root
5202 * `AppModule` when you create a new app with the CLI `new` command.
5203 *
5204 * * The `providers` options configure the NgModule's injector to provide
5205 * localization dependencies to members.
5206 * * The `exports` options make the declared directives and pipes available for import
5207 * by other NgModules.
5208 *
5209 * @publicApi
5210 */
5211class CommonModule {
5212}
5213CommonModule.ɵfac = function CommonModule_Factory(t) { return new (t || CommonModule)(); };
5214CommonModule.ɵmod = /*@__PURE__*/ ɵngcc0.ɵɵdefineNgModule({ type: CommonModule });
5215CommonModule.ɵinj = /*@__PURE__*/ ɵngcc0.ɵɵdefineInjector({ providers: [
5216 { provide: NgLocalization, useClass: NgLocaleLocalization },
5217 ] });
5218(function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(CommonModule, [{
5219 type: NgModule,
5220 args: [{
5221 declarations: [COMMON_DIRECTIVES, COMMON_PIPES],
5222 exports: [COMMON_DIRECTIVES, COMMON_PIPES],
5223 providers: [
5224 { provide: NgLocalization, useClass: NgLocaleLocalization },
5225 ]
5226 }]
5227 }], null, null); })();
5228(function () { (typeof ngJitMode === "undefined" || ngJitMode) && ɵngcc0.ɵɵsetNgModuleScope(CommonModule, { declarations: [NgClass, NgComponentOutlet, NgForOf, NgIf, NgTemplateOutlet, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgPlural, NgPluralCase, AsyncPipe, UpperCasePipe, LowerCasePipe, JsonPipe, SlicePipe, DecimalPipe, PercentPipe, TitleCasePipe, CurrencyPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, KeyValuePipe], exports: [NgClass, NgComponentOutlet, NgForOf, NgIf, NgTemplateOutlet, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgPlural, NgPluralCase, AsyncPipe, UpperCasePipe, LowerCasePipe, JsonPipe, SlicePipe, DecimalPipe, PercentPipe, TitleCasePipe, CurrencyPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, KeyValuePipe] }); })();
5229
5230/**
5231 * @license
5232 * Copyright Google LLC All Rights Reserved.
5233 *
5234 * Use of this source code is governed by an MIT-style license that can be
5235 * found in the LICENSE file at https://angular.io/license
5236 */
5237const PLATFORM_BROWSER_ID = 'browser';
5238const PLATFORM_SERVER_ID = 'server';
5239const PLATFORM_WORKER_APP_ID = 'browserWorkerApp';
5240const PLATFORM_WORKER_UI_ID = 'browserWorkerUi';
5241/**
5242 * Returns whether a platform id represents a browser platform.
5243 * @publicApi
5244 */
5245function isPlatformBrowser(platformId) {
5246 return platformId === PLATFORM_BROWSER_ID;
5247}
5248/**
5249 * Returns whether a platform id represents a server platform.
5250 * @publicApi
5251 */
5252function isPlatformServer(platformId) {
5253 return platformId === PLATFORM_SERVER_ID;
5254}
5255/**
5256 * Returns whether a platform id represents a web worker app platform.
5257 * @publicApi
5258 */
5259function isPlatformWorkerApp(platformId) {
5260 return platformId === PLATFORM_WORKER_APP_ID;
5261}
5262/**
5263 * Returns whether a platform id represents a web worker UI platform.
5264 * @publicApi
5265 */
5266function isPlatformWorkerUi(platformId) {
5267 return platformId === PLATFORM_WORKER_UI_ID;
5268}
5269
5270/**
5271 * @license
5272 * Copyright Google LLC All Rights Reserved.
5273 *
5274 * Use of this source code is governed by an MIT-style license that can be
5275 * found in the LICENSE file at https://angular.io/license
5276 */
5277/**
5278 * @publicApi
5279 */
5280const VERSION = new Version('12.2.13');
5281
5282/**
5283 * @license
5284 * Copyright Google LLC All Rights Reserved.
5285 *
5286 * Use of this source code is governed by an MIT-style license that can be
5287 * found in the LICENSE file at https://angular.io/license
5288 */
5289/**
5290 * Defines a scroll position manager. Implemented by `BrowserViewportScroller`.
5291 *
5292 * @publicApi
5293 */
5294class ViewportScroller {
5295}
5296// De-sugared tree-shakable injection
5297// See #23917
5298/** @nocollapse */
5299ViewportScroller.ɵprov = ɵɵdefineInjectable({
5300 token: ViewportScroller,
5301 providedIn: 'root',
5302 factory: () => new BrowserViewportScroller(ɵɵinject(DOCUMENT), window)
5303});
5304/**
5305 * Manages the scroll position for a browser window.
5306 */
5307class BrowserViewportScroller {
5308 constructor(document, window) {
5309 this.document = document;
5310 this.window = window;
5311 this.offset = () => [0, 0];
5312 }
5313 /**
5314 * Configures the top offset used when scrolling to an anchor.
5315 * @param offset A position in screen coordinates (a tuple with x and y values)
5316 * or a function that returns the top offset position.
5317 *
5318 */
5319 setOffset(offset) {
5320 if (Array.isArray(offset)) {
5321 this.offset = () => offset;
5322 }
5323 else {
5324 this.offset = offset;
5325 }
5326 }
5327 /**
5328 * Retrieves the current scroll position.
5329 * @returns The position in screen coordinates.
5330 */
5331 getScrollPosition() {
5332 if (this.supportsScrolling()) {
5333 return [this.window.pageXOffset, this.window.pageYOffset];
5334 }
5335 else {
5336 return [0, 0];
5337 }
5338 }
5339 /**
5340 * Sets the scroll position.
5341 * @param position The new position in screen coordinates.
5342 */
5343 scrollToPosition(position) {
5344 if (this.supportsScrolling()) {
5345 this.window.scrollTo(position[0], position[1]);
5346 }
5347 }
5348 /**
5349 * Scrolls to an element and attempts to focus the element.
5350 *
5351 * Note that the function name here is misleading in that the target string may be an ID for a
5352 * non-anchor element.
5353 *
5354 * @param target The ID of an element or name of the anchor.
5355 *
5356 * @see https://html.spec.whatwg.org/#the-indicated-part-of-the-document
5357 * @see https://html.spec.whatwg.org/#scroll-to-fragid
5358 */
5359 scrollToAnchor(target) {
5360 if (!this.supportsScrolling()) {
5361 return;
5362 }
5363 const elSelected = findAnchorFromDocument(this.document, target);
5364 if (elSelected) {
5365 this.scrollToElement(elSelected);
5366 // After scrolling to the element, the spec dictates that we follow the focus steps for the
5367 // target. Rather than following the robust steps, simply attempt focus.
5368 this.attemptFocus(elSelected);
5369 }
5370 }
5371 /**
5372 * Disables automatic scroll restoration provided by the browser.
5373 */
5374 setHistoryScrollRestoration(scrollRestoration) {
5375 if (this.supportScrollRestoration()) {
5376 const history = this.window.history;
5377 if (history && history.scrollRestoration) {
5378 history.scrollRestoration = scrollRestoration;
5379 }
5380 }
5381 }
5382 /**
5383 * Scrolls to an element using the native offset and the specified offset set on this scroller.
5384 *
5385 * The offset can be used when we know that there is a floating header and scrolling naively to an
5386 * element (ex: `scrollIntoView`) leaves the element hidden behind the floating header.
5387 */
5388 scrollToElement(el) {
5389 const rect = el.getBoundingClientRect();
5390 const left = rect.left + this.window.pageXOffset;
5391 const top = rect.top + this.window.pageYOffset;
5392 const offset = this.offset();
5393 this.window.scrollTo(left - offset[0], top - offset[1]);
5394 }
5395 /**
5396 * Calls `focus` on the `focusTarget` and returns `true` if the element was focused successfully.
5397 *
5398 * If `false`, further steps may be necessary to determine a valid substitute to be focused
5399 * instead.
5400 *
5401 * @see https://html.spec.whatwg.org/#get-the-focusable-area
5402 * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus
5403 * @see https://html.spec.whatwg.org/#focusable-area
5404 */
5405 attemptFocus(focusTarget) {
5406 focusTarget.focus();
5407 return this.document.activeElement === focusTarget;
5408 }
5409 /**
5410 * We only support scroll restoration when we can get a hold of window.
5411 * This means that we do not support this behavior when running in a web worker.
5412 *
5413 * Lifting this restriction right now would require more changes in the dom adapter.
5414 * Since webworkers aren't widely used, we will lift it once RouterScroller is
5415 * battle-tested.
5416 */
5417 supportScrollRestoration() {
5418 try {
5419 if (!this.supportsScrolling()) {
5420 return false;
5421 }
5422 // The `scrollRestoration` property could be on the `history` instance or its prototype.
5423 const scrollRestorationDescriptor = getScrollRestorationProperty(this.window.history) ||
5424 getScrollRestorationProperty(Object.getPrototypeOf(this.window.history));
5425 // We can write to the `scrollRestoration` property if it is a writable data field or it has a
5426 // setter function.
5427 return !!scrollRestorationDescriptor &&
5428 !!(scrollRestorationDescriptor.writable || scrollRestorationDescriptor.set);
5429 }
5430 catch (_a) {
5431 return false;
5432 }
5433 }
5434 supportsScrolling() {
5435 try {
5436 return !!this.window && !!this.window.scrollTo && 'pageXOffset' in this.window;
5437 }
5438 catch (_a) {
5439 return false;
5440 }
5441 }
5442}
5443function getScrollRestorationProperty(obj) {
5444 return Object.getOwnPropertyDescriptor(obj, 'scrollRestoration');
5445}
5446function findAnchorFromDocument(document, target) {
5447 const documentResult = document.getElementById(target) || document.getElementsByName(target)[0];
5448 if (documentResult) {
5449 return documentResult;
5450 }
5451 // `getElementById` and `getElementsByName` won't pierce through the shadow DOM so we
5452 // have to traverse the DOM manually and do the lookup through the shadow roots.
5453 if (typeof document.createTreeWalker === 'function' && document.body &&
5454 (document.body.createShadowRoot || document.body.attachShadow)) {
5455 const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
5456 let currentNode = treeWalker.currentNode;
5457 while (currentNode) {
5458 const shadowRoot = currentNode.shadowRoot;
5459 if (shadowRoot) {
5460 // Note that `ShadowRoot` doesn't support `getElementsByName`
5461 // so we have to fall back to `querySelector`.
5462 const result = shadowRoot.getElementById(target) || shadowRoot.querySelector(`[name="${target}"]`);
5463 if (result) {
5464 return result;
5465 }
5466 }
5467 currentNode = treeWalker.nextNode();
5468 }
5469 }
5470 return null;
5471}
5472/**
5473 * Provides an empty implementation of the viewport scroller.
5474 */
5475class NullViewportScroller {
5476 /**
5477 * Empty implementation
5478 */
5479 setOffset(offset) { }
5480 /**
5481 * Empty implementation
5482 */
5483 getScrollPosition() {
5484 return [0, 0];
5485 }
5486 /**
5487 * Empty implementation
5488 */
5489 scrollToPosition(position) { }
5490 /**
5491 * Empty implementation
5492 */
5493 scrollToAnchor(anchor) { }
5494 /**
5495 * Empty implementation
5496 */
5497 setHistoryScrollRestoration(scrollRestoration) { }
5498}
5499
5500/**
5501 * @license
5502 * Copyright Google LLC All Rights Reserved.
5503 *
5504 * Use of this source code is governed by an MIT-style license that can be
5505 * found in the LICENSE file at https://angular.io/license
5506 */
5507/**
5508 * A wrapper around the `XMLHttpRequest` constructor.
5509 *
5510 * @publicApi
5511 */
5512class XhrFactory {
5513}
5514
5515/**
5516 * @license
5517 * Copyright Google LLC All Rights Reserved.
5518 *
5519 * Use of this source code is governed by an MIT-style license that can be
5520 * found in the LICENSE file at https://angular.io/license
5521 */
5522
5523/**
5524 * @license
5525 * Copyright Google LLC All Rights Reserved.
5526 *
5527 * Use of this source code is governed by an MIT-style license that can be
5528 * found in the LICENSE file at https://angular.io/license
5529 */
5530// This file only reexports content of the `src` folder. Keep it that way.
5531
5532/**
5533 * @license
5534 * Copyright Google LLC All Rights Reserved.
5535 *
5536 * Use of this source code is governed by an MIT-style license that can be
5537 * found in the LICENSE file at https://angular.io/license
5538 */
5539
5540/**
5541 * Generated bundle index. Do not edit.
5542 */
5543
5544export { APP_BASE_HREF, AsyncPipe, CommonModule, CurrencyPipe, DOCUMENT, DatePipe, DecimalPipe, FormStyle, FormatWidth, HashLocationStrategy, I18nPluralPipe, I18nSelectPipe, JsonPipe, KeyValuePipe, LOCATION_INITIALIZED, Location, LocationStrategy, LowerCasePipe, NgClass, NgComponentOutlet, NgForOf, NgForOfContext, NgIf, NgIfContext, NgLocaleLocalization, NgLocalization, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NumberFormatStyle, NumberSymbol, PathLocationStrategy, PercentPipe, PlatformLocation, Plural, SlicePipe, TitleCasePipe, TranslationWidth, UpperCasePipe, VERSION, ViewportScroller, WeekDay, XhrFactory, formatCurrency, formatDate, formatNumber, formatPercent, getCurrencySymbol, getLocaleCurrencyCode, getLocaleCurrencyName, getLocaleCurrencySymbol, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleDirection, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleFirstDayOfWeek, getLocaleId, getLocaleMonthNames, getLocaleNumberFormat, getLocaleNumberSymbol, getLocalePluralCase, getLocaleTimeFormat, getLocaleWeekEndRange, getNumberOfCurrencyDigits, isPlatformBrowser, isPlatformServer, isPlatformWorkerApp, isPlatformWorkerUi, registerLocaleData, BrowserPlatformLocation as ɵBrowserPlatformLocation, DomAdapter as ɵDomAdapter, NullViewportScroller as ɵNullViewportScroller, PLATFORM_BROWSER_ID as ɵPLATFORM_BROWSER_ID, PLATFORM_SERVER_ID as ɵPLATFORM_SERVER_ID, PLATFORM_WORKER_APP_ID as ɵPLATFORM_WORKER_APP_ID, PLATFORM_WORKER_UI_ID as ɵPLATFORM_WORKER_UI_ID, useBrowserPlatformLocation as ɵangular_packages_common_common_a, createBrowserPlatformLocation as ɵangular_packages_common_common_b, createLocation as ɵangular_packages_common_common_c, provideLocationStrategy as ɵangular_packages_common_common_d, COMMON_DIRECTIVES as ɵangular_packages_common_common_e, COMMON_PIPES as ɵangular_packages_common_common_f, getDOM as ɵgetDOM, parseCookieValue as ɵparseCookieValue, setRootDomAdapter as ɵsetRootDomAdapter };
5545
5546//# sourceMappingURL=common.js.map
Note: See TracBrowser for help on using the repository browser.