UNPKG

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