source: trip-planner-front/node_modules/@angular/common/fesm2015/common.js@ 84d0fbb

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

primeNG components

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