Skip to content

Commit f023579

Browse files
CaerusKarutinayuangao
authored andcommitted
fix(platform): change isBrowser check to use Angular PLATFORM_ID (#10659)
* Use the Angular PLATFORM_ID token as a more reliable check for whether the current platform is browser. This is because the previous check for a global document could be a false positive if another application pollutes the global namespace BREAKING CHANGE: * Platform now takes the PLATFORM_ID as an optional parameter in its constructor. This will become a required parameter in v7
1 parent be84566 commit f023579

File tree

5 files changed

+32
-10
lines changed

5 files changed

+32
-10
lines changed

src/cdk/a11y/focus-trap/focus-trap.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Platform} from '@angular/cdk/platform';
2-
import {Component, ViewChild} from '@angular/core';
2+
import {Component, PLATFORM_ID, ViewChild} from '@angular/core';
33
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
44
import {A11yModule, FocusTrap, CdkTrapFocus} from '../index';
55

@@ -47,8 +47,9 @@ describe('FocusTrap', () => {
4747
// focus event handler directly.
4848
const result = focusTrapInstance.focusLastTabbableElement();
4949

50+
const platformId = TestBed.get(PLATFORM_ID);
5051
// In iOS button elements are never tabbable, so the last element will be the input.
51-
const lastElement = new Platform().IOS ? 'input' : 'button';
52+
const lastElement = new Platform(platformId).IOS ? 'input' : 'button';
5253

5354
expect(document.activeElement.nodeName.toLowerCase())
5455
.toBe(lastElement, `Expected ${lastElement} element to be focused`);

src/cdk/a11y/interactivity-checker/interactivity-checker.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import {InteractivityChecker} from './interactivity-checker';
55
describe('InteractivityChecker', () => {
66
let testContainerElement: HTMLElement;
77
let checker: InteractivityChecker;
8+
// TODO: refactor this to be injected with the platformId
9+
// Needs to be done carefully due to the runIf checks below executing
10+
// before injection
811
let platform: Platform = new Platform();
912

1013
beforeEach(() => {

src/cdk/overlay/scroll/block-scroll-strategy.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {Overlay, OverlayContainer, OverlayModule, OverlayRef, OverlayConfig} fro
77

88

99
describe('BlockScrollStrategy', () => {
10-
let platform = new Platform();
10+
let platform: Platform;
1111
let viewport: ViewportRuler;
1212
let overlayRef: OverlayRef;
1313
let componentPortal: ComponentPortal<FocacciaMsg>;
@@ -22,7 +22,8 @@ describe('BlockScrollStrategy', () => {
2222
}).compileComponents();
2323
}));
2424

25-
beforeEach(inject([Overlay, ViewportRuler], (overlay: Overlay, viewportRuler: ViewportRuler) => {
25+
beforeEach(inject([Overlay, ViewportRuler, Platform],
26+
(overlay: Overlay, viewportRuler: ViewportRuler, _platform: Platform) => {
2627
let overlayConfig = new OverlayConfig({scrollStrategy: overlay.scrollStrategies.block()});
2728

2829
overlayRef = overlay.create(overlayConfig);
@@ -34,6 +35,7 @@ describe('BlockScrollStrategy', () => {
3435
forceScrollElement.style.width = '100px';
3536
forceScrollElement.style.height = '3000px';
3637
forceScrollElement.style.background = 'rebeccapurple';
38+
platform = _platform;
3739
}));
3840

3941
afterEach(inject([OverlayContainer], (container: OverlayContainer) => {

src/cdk/platform/platform.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Injectable} from '@angular/core';
9+
import {Inject, Injectable, Optional, PLATFORM_ID} from '@angular/core';
10+
import {isPlatformBrowser} from '@angular/common';
1011

1112

1213
// Whether the current platform supports the V8 Break Iterator. The V8 check
@@ -19,8 +20,14 @@ const hasV8BreakIterator = (typeof Intl !== 'undefined' && (Intl as any).v8Break
1920
*/
2021
@Injectable({providedIn: 'root'})
2122
export class Platform {
22-
/** Whether the Angular application is being rendered in the browser. */
23-
isBrowser: boolean = typeof document === 'object' && !!document;
23+
/**
24+
* Whether the Angular application is being rendered in the browser.
25+
* We want to use the Angular platform check because if the Document is shimmed
26+
* without the navigator, the following checks will fail. This is preferred because
27+
* sometimes the Document may be shimmed without the user's knowledge or intention
28+
*/
29+
isBrowser: boolean = this._platformId ?
30+
isPlatformBrowser(this._platformId) : typeof document === 'object' && !!document;
2431

2532
/** Whether the current browser is Microsoft Edge. */
2633
EDGE: boolean = this.isBrowser && /(edge)/i.test(navigator.userAgent);
@@ -31,7 +38,7 @@ export class Platform {
3138
/** Whether the current rendering engine is Blink. */
3239
// EdgeHTML and Trident mock Blink specific things and need to be excluded from this check.
3340
BLINK: boolean = this.isBrowser && (!!((window as any).chrome || hasV8BreakIterator) &&
34-
typeof CSS !== 'undefined' && !this.EDGE && !this.TRIDENT);
41+
typeof CSS !== 'undefined' && !this.EDGE && !this.TRIDENT);
3542

3643
/** Whether the current rendering engine is WebKit. */
3744
// Webkit is part of the userAgent in EdgeHTML, Blink and Trident. Therefore we need to
@@ -59,4 +66,11 @@ export class Platform {
5966
// this and just place the Safari keyword in the userAgent. To be more safe about Safari every
6067
// Safari browser should also use Webkit as its layout engine.
6168
SAFARI: boolean = this.isBrowser && /safari/i.test(navigator.userAgent) && this.WEBKIT;
69+
70+
/**
71+
* @deletion-target v7.0.0 remove optional decorator
72+
*/
73+
constructor(@Optional() @Inject(PLATFORM_ID) private _platformId?: Object) {
74+
}
6275
}
76+

src/lib/core/datetime/native-date-adapter.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const SUPPORTS_INTL = typeof Intl != 'undefined';
88

99

1010
describe('NativeDateAdapter', () => {
11-
const platform = new Platform();
11+
let platform: Platform;
1212
let adapter: NativeDateAdapter;
1313
let assertValidDate: (d: Date | null, valid: boolean) => void;
1414

@@ -18,8 +18,10 @@ describe('NativeDateAdapter', () => {
1818
}).compileComponents();
1919
}));
2020

21-
beforeEach(inject([DateAdapter], (dateAdapter: NativeDateAdapter) => {
21+
beforeEach(inject([DateAdapter, Platform],
22+
(dateAdapter: NativeDateAdapter, _platform: Platform) => {
2223
adapter = dateAdapter;
24+
platform = _platform;
2325

2426
assertValidDate = (d: Date | null, valid: boolean) => {
2527
expect(adapter.isDateInstance(d)).not.toBeNull(`Expected ${d} to be a date instance`);

0 commit comments

Comments
 (0)