UNPKG

16.9 kBJavaScriptView Raw
1import * as i0 from '@angular/core';
2import { PLATFORM_ID, Injectable, Inject, NgModule } from '@angular/core';
3import { isPlatformBrowser } from '@angular/common';
4
5/**
6 * @license
7 * Copyright Google LLC All Rights Reserved.
8 *
9 * Use of this source code is governed by an MIT-style license that can be
10 * found in the LICENSE file at https://angular.io/license
11 */
12// Whether the current platform supports the V8 Break Iterator. The V8 check
13// is necessary to detect all Blink based browsers.
14let hasV8BreakIterator;
15// We need a try/catch around the reference to `Intl`, because accessing it in some cases can
16// cause IE to throw. These cases are tied to particular versions of Windows and can happen if
17// the consumer is providing a polyfilled `Map`. See:
18// https://github.com/Microsoft/ChakraCore/issues/3189
19// https://github.com/angular/components/issues/15687
20try {
21 hasV8BreakIterator = typeof Intl !== 'undefined' && Intl.v8BreakIterator;
22}
23catch {
24 hasV8BreakIterator = false;
25}
26/**
27 * Service to detect the current platform by comparing the userAgent strings and
28 * checking browser-specific global properties.
29 */
30class Platform {
31 constructor(_platformId) {
32 this._platformId = _platformId;
33 // We want to use the Angular platform check because if the Document is shimmed
34 // without the navigator, the following checks will fail. This is preferred because
35 // sometimes the Document may be shimmed without the user's knowledge or intention
36 /** Whether the Angular application is being rendered in the browser. */
37 this.isBrowser = this._platformId
38 ? isPlatformBrowser(this._platformId)
39 : typeof document === 'object' && !!document;
40 /** Whether the current browser is Microsoft Edge. */
41 this.EDGE = this.isBrowser && /(edge)/i.test(navigator.userAgent);
42 /** Whether the current rendering engine is Microsoft Trident. */
43 this.TRIDENT = this.isBrowser && /(msie|trident)/i.test(navigator.userAgent);
44 // EdgeHTML and Trident mock Blink specific things and need to be excluded from this check.
45 /** Whether the current rendering engine is Blink. */
46 this.BLINK = this.isBrowser &&
47 !!(window.chrome || hasV8BreakIterator) &&
48 typeof CSS !== 'undefined' &&
49 !this.EDGE &&
50 !this.TRIDENT;
51 // Webkit is part of the userAgent in EdgeHTML, Blink and Trident. Therefore we need to
52 // ensure that Webkit runs standalone and is not used as another engine's base.
53 /** Whether the current rendering engine is WebKit. */
54 this.WEBKIT = this.isBrowser &&
55 /AppleWebKit/i.test(navigator.userAgent) &&
56 !this.BLINK &&
57 !this.EDGE &&
58 !this.TRIDENT;
59 /** Whether the current platform is Apple iOS. */
60 this.IOS = this.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window);
61 // It's difficult to detect the plain Gecko engine, because most of the browsers identify
62 // them self as Gecko-like browsers and modify the userAgent's according to that.
63 // Since we only cover one explicit Firefox case, we can simply check for Firefox
64 // instead of having an unstable check for Gecko.
65 /** Whether the current browser is Firefox. */
66 this.FIREFOX = this.isBrowser && /(firefox|minefield)/i.test(navigator.userAgent);
67 /** Whether the current platform is Android. */
68 // Trident on mobile adds the android platform to the userAgent to trick detections.
69 this.ANDROID = this.isBrowser && /android/i.test(navigator.userAgent) && !this.TRIDENT;
70 // Safari browsers will include the Safari keyword in their userAgent. Some browsers may fake
71 // this and just place the Safari keyword in the userAgent. To be more safe about Safari every
72 // Safari browser should also use Webkit as its layout engine.
73 /** Whether the current browser is Safari. */
74 this.SAFARI = this.isBrowser && /safari/i.test(navigator.userAgent) && this.WEBKIT;
75 }
76}
77Platform.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: Platform, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
78Platform.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: Platform, providedIn: 'root' });
79i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: Platform, decorators: [{
80 type: Injectable,
81 args: [{ providedIn: 'root' }]
82 }], ctorParameters: function () { return [{ type: Object, decorators: [{
83 type: Inject,
84 args: [PLATFORM_ID]
85 }] }]; } });
86
87/**
88 * @license
89 * Copyright Google LLC All Rights Reserved.
90 *
91 * Use of this source code is governed by an MIT-style license that can be
92 * found in the LICENSE file at https://angular.io/license
93 */
94class PlatformModule {
95}
96PlatformModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: PlatformModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
97PlatformModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.0.1", ngImport: i0, type: PlatformModule });
98PlatformModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: PlatformModule });
99i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.1", ngImport: i0, type: PlatformModule, decorators: [{
100 type: NgModule,
101 args: [{}]
102 }] });
103
104/**
105 * @license
106 * Copyright Google LLC All Rights Reserved.
107 *
108 * Use of this source code is governed by an MIT-style license that can be
109 * found in the LICENSE file at https://angular.io/license
110 */
111/** Cached result Set of input types support by the current browser. */
112let supportedInputTypes;
113/** Types of `<input>` that *might* be supported. */
114const candidateInputTypes = [
115 // `color` must come first. Chrome 56 shows a warning if we change the type to `color` after
116 // first changing it to something else:
117 // The specified value "" does not conform to the required format.
118 // The format is "#rrggbb" where rr, gg, bb are two-digit hexadecimal numbers.
119 'color',
120 'button',
121 'checkbox',
122 'date',
123 'datetime-local',
124 'email',
125 'file',
126 'hidden',
127 'image',
128 'month',
129 'number',
130 'password',
131 'radio',
132 'range',
133 'reset',
134 'search',
135 'submit',
136 'tel',
137 'text',
138 'time',
139 'url',
140 'week',
141];
142/** @returns The input types supported by this browser. */
143function getSupportedInputTypes() {
144 // Result is cached.
145 if (supportedInputTypes) {
146 return supportedInputTypes;
147 }
148 // We can't check if an input type is not supported until we're on the browser, so say that
149 // everything is supported when not on the browser. We don't use `Platform` here since it's
150 // just a helper function and can't inject it.
151 if (typeof document !== 'object' || !document) {
152 supportedInputTypes = new Set(candidateInputTypes);
153 return supportedInputTypes;
154 }
155 let featureTestInput = document.createElement('input');
156 supportedInputTypes = new Set(candidateInputTypes.filter(value => {
157 featureTestInput.setAttribute('type', value);
158 return featureTestInput.type === value;
159 }));
160 return supportedInputTypes;
161}
162
163/**
164 * @license
165 * Copyright Google LLC All Rights Reserved.
166 *
167 * Use of this source code is governed by an MIT-style license that can be
168 * found in the LICENSE file at https://angular.io/license
169 */
170/** Cached result of whether the user's browser supports passive event listeners. */
171let supportsPassiveEvents;
172/**
173 * Checks whether the user's browser supports passive event listeners.
174 * See: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
175 */
176function supportsPassiveEventListeners() {
177 if (supportsPassiveEvents == null && typeof window !== 'undefined') {
178 try {
179 window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
180 get: () => (supportsPassiveEvents = true),
181 }));
182 }
183 finally {
184 supportsPassiveEvents = supportsPassiveEvents || false;
185 }
186 }
187 return supportsPassiveEvents;
188}
189/**
190 * Normalizes an `AddEventListener` object to something that can be passed
191 * to `addEventListener` on any browser, no matter whether it supports the
192 * `options` parameter.
193 * @param options Object to be normalized.
194 */
195function normalizePassiveListenerOptions(options) {
196 return supportsPassiveEventListeners() ? options : !!options.capture;
197}
198
199/**
200 * @license
201 * Copyright Google LLC All Rights Reserved.
202 *
203 * Use of this source code is governed by an MIT-style license that can be
204 * found in the LICENSE file at https://angular.io/license
205 */
206/** Cached result of the way the browser handles the horizontal scroll axis in RTL mode. */
207let rtlScrollAxisType;
208/** Cached result of the check that indicates whether the browser supports scroll behaviors. */
209let scrollBehaviorSupported;
210/** Check whether the browser supports scroll behaviors. */
211function supportsScrollBehavior() {
212 if (scrollBehaviorSupported == null) {
213 // If we're not in the browser, it can't be supported. Also check for `Element`, because
214 // some projects stub out the global `document` during SSR which can throw us off.
215 if (typeof document !== 'object' || !document || typeof Element !== 'function' || !Element) {
216 scrollBehaviorSupported = false;
217 return scrollBehaviorSupported;
218 }
219 // If the element can have a `scrollBehavior` style, we can be sure that it's supported.
220 if ('scrollBehavior' in document.documentElement.style) {
221 scrollBehaviorSupported = true;
222 }
223 else {
224 // At this point we have 3 possibilities: `scrollTo` isn't supported at all, it's
225 // supported but it doesn't handle scroll behavior, or it has been polyfilled.
226 const scrollToFunction = Element.prototype.scrollTo;
227 if (scrollToFunction) {
228 // We can detect if the function has been polyfilled by calling `toString` on it. Native
229 // functions are obfuscated using `[native code]`, whereas if it was overwritten we'd get
230 // the actual function source. Via https://davidwalsh.name/detect-native-function. Consider
231 // polyfilled functions as supporting scroll behavior.
232 scrollBehaviorSupported = !/\{\s*\[native code\]\s*\}/.test(scrollToFunction.toString());
233 }
234 else {
235 scrollBehaviorSupported = false;
236 }
237 }
238 }
239 return scrollBehaviorSupported;
240}
241/**
242 * Checks the type of RTL scroll axis used by this browser. As of time of writing, Chrome is NORMAL,
243 * Firefox & Safari are NEGATED, and IE & Edge are INVERTED.
244 */
245function getRtlScrollAxisType() {
246 // We can't check unless we're on the browser. Just assume 'normal' if we're not.
247 if (typeof document !== 'object' || !document) {
248 return 0 /* RtlScrollAxisType.NORMAL */;
249 }
250 if (rtlScrollAxisType == null) {
251 // Create a 1px wide scrolling container and a 2px wide content element.
252 const scrollContainer = document.createElement('div');
253 const containerStyle = scrollContainer.style;
254 scrollContainer.dir = 'rtl';
255 containerStyle.width = '1px';
256 containerStyle.overflow = 'auto';
257 containerStyle.visibility = 'hidden';
258 containerStyle.pointerEvents = 'none';
259 containerStyle.position = 'absolute';
260 const content = document.createElement('div');
261 const contentStyle = content.style;
262 contentStyle.width = '2px';
263 contentStyle.height = '1px';
264 scrollContainer.appendChild(content);
265 document.body.appendChild(scrollContainer);
266 rtlScrollAxisType = 0 /* RtlScrollAxisType.NORMAL */;
267 // The viewport starts scrolled all the way to the right in RTL mode. If we are in a NORMAL
268 // browser this would mean that the scrollLeft should be 1. If it's zero instead we know we're
269 // dealing with one of the other two types of browsers.
270 if (scrollContainer.scrollLeft === 0) {
271 // In a NEGATED browser the scrollLeft is always somewhere in [-maxScrollAmount, 0]. For an
272 // INVERTED browser it is always somewhere in [0, maxScrollAmount]. We can determine which by
273 // setting to the scrollLeft to 1. This is past the max for a NEGATED browser, so it will
274 // return 0 when we read it again.
275 scrollContainer.scrollLeft = 1;
276 rtlScrollAxisType =
277 scrollContainer.scrollLeft === 0 ? 1 /* RtlScrollAxisType.NEGATED */ : 2 /* RtlScrollAxisType.INVERTED */;
278 }
279 scrollContainer.remove();
280 }
281 return rtlScrollAxisType;
282}
283
284/**
285 * @license
286 * Copyright Google LLC All Rights Reserved.
287 *
288 * Use of this source code is governed by an MIT-style license that can be
289 * found in the LICENSE file at https://angular.io/license
290 */
291let shadowDomIsSupported;
292/** Checks whether the user's browser support Shadow DOM. */
293function _supportsShadowDom() {
294 if (shadowDomIsSupported == null) {
295 const head = typeof document !== 'undefined' ? document.head : null;
296 shadowDomIsSupported = !!(head && (head.createShadowRoot || head.attachShadow));
297 }
298 return shadowDomIsSupported;
299}
300/** Gets the shadow root of an element, if supported and the element is inside the Shadow DOM. */
301function _getShadowRoot(element) {
302 if (_supportsShadowDom()) {
303 const rootNode = element.getRootNode ? element.getRootNode() : null;
304 // Note that this should be caught by `_supportsShadowDom`, but some
305 // teams have been able to hit this code path on unsupported browsers.
306 if (typeof ShadowRoot !== 'undefined' && ShadowRoot && rootNode instanceof ShadowRoot) {
307 return rootNode;
308 }
309 }
310 return null;
311}
312/**
313 * Gets the currently-focused element on the page while
314 * also piercing through Shadow DOM boundaries.
315 */
316function _getFocusedElementPierceShadowDom() {
317 let activeElement = typeof document !== 'undefined' && document
318 ? document.activeElement
319 : null;
320 while (activeElement && activeElement.shadowRoot) {
321 const newActiveElement = activeElement.shadowRoot.activeElement;
322 if (newActiveElement === activeElement) {
323 break;
324 }
325 else {
326 activeElement = newActiveElement;
327 }
328 }
329 return activeElement;
330}
331/** Gets the target of an event while accounting for Shadow DOM. */
332function _getEventTarget(event) {
333 // If an event is bound outside the Shadow DOM, the `event.target` will
334 // point to the shadow root so we have to use `composedPath` instead.
335 return (event.composedPath ? event.composedPath()[0] : event.target);
336}
337
338/**
339 * @license
340 * Copyright Google LLC All Rights Reserved.
341 *
342 * Use of this source code is governed by an MIT-style license that can be
343 * found in the LICENSE file at https://angular.io/license
344 */
345/** Gets whether the code is currently running in a test environment. */
346function _isTestEnvironment() {
347 // We can't use `declare const` because it causes conflicts inside Google with the real typings
348 // for these symbols and we can't read them off the global object, because they don't appear to
349 // be attached there for some runners like Jest.
350 // (see: https://github.com/angular/components/issues/23365#issuecomment-938146643)
351 return (
352 // @ts-ignore
353 (typeof __karma__ !== 'undefined' && !!__karma__) ||
354 // @ts-ignore
355 (typeof jasmine !== 'undefined' && !!jasmine) ||
356 // @ts-ignore
357 (typeof jest !== 'undefined' && !!jest) ||
358 // @ts-ignore
359 (typeof Mocha !== 'undefined' && !!Mocha));
360}
361
362/**
363 * @license
364 * Copyright Google LLC All Rights Reserved.
365 *
366 * Use of this source code is governed by an MIT-style license that can be
367 * found in the LICENSE file at https://angular.io/license
368 */
369
370/**
371 * @license
372 * Copyright Google LLC All Rights Reserved.
373 *
374 * Use of this source code is governed by an MIT-style license that can be
375 * found in the LICENSE file at https://angular.io/license
376 */
377
378/**
379 * Generated bundle index. Do not edit.
380 */
381
382export { Platform, PlatformModule, _getEventTarget, _getFocusedElementPierceShadowDom, _getShadowRoot, _isTestEnvironment, _supportsShadowDom, getRtlScrollAxisType, getSupportedInputTypes, normalizePassiveListenerOptions, supportsPassiveEventListeners, supportsScrollBehavior };
383//# sourceMappingURL=platform.mjs.map