Skip to content

Commit fe6b65c

Browse files
Make isHTMLElement work for nodes that belong to other realms (#931).
1 parent 4a0ead2 commit fe6b65c

7 files changed

Lines changed: 53 additions & 42 deletions

File tree

dist/js/splide-renderer.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/js/splide-renderer.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/js/splide.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
6969
}
7070

7171
function isHTMLElement(subject) {
72-
return subject instanceof HTMLElement;
72+
try {
73+
return subject instanceof (subject.ownerDocument.defaultView || window).HTMLElement;
74+
} catch (e) {
75+
return false;
76+
}
7377
}
7478

7579
function toArray(value) {

dist/js/splide.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/js/splide.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/js/utils/type/type.test.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
isArray,
33
isFunction,
4-
isHTMLButtonElement,
54
isHTMLElement,
65
isNull,
76
isObject,
@@ -11,9 +10,6 @@ import {
1110

1211

1312
describe( 'Type methods', () => {
14-
const div = document.createElement( 'div' );
15-
const text = document.createTextNode( 'test' );
16-
1713
describe( 'isObject', () => {
1814
test( 'can return `true` if a subject is an object.', () => {
1915
[ {}, { a: 1 }, new Date() ].forEach( subject => {
@@ -93,29 +89,46 @@ describe( 'Type methods', () => {
9389
} );
9490
} );
9591
} );
92+
} );
9693

97-
describe( 'isHTMLElement', () => {
98-
test( 'can return `true` if a subject is an HTMLElement.', () => {
99-
expect( isHTMLElement( div ) ).toBe( true );
100-
} );
94+
describe( 'isHTMLElement', () => {
95+
const div = document.createElement( 'div' );
96+
const text = document.createTextNode( 'test' );
10197

102-
test( 'should return `false` for other subjects.', () => {
103-
[ document, window, text, 1, true, undefined, '1', null, [ 1 ], { a: 1 }, NaN ].forEach( subject => {
104-
expect( isHTMLElement( subject ) ).toBe( false );
105-
} );
106-
} );
98+
document.body.innerHTML = '<iframe></iframe>';
99+
100+
test( 'can return `true` if a subject is an HTMLElement.', () => {
101+
expect( isHTMLElement( div ) ).toBe( true );
107102
} );
108103

109-
describe( 'isHTMLButtonElement', () => {
110-
test( 'can return `true` if a subject is an HTMLElement.', () => {
111-
const button = document.createElement( 'button' );
112-
expect( isHTMLButtonElement( button ) ).toBe( true );
104+
test( 'should return `false` for other subjects.', () => {
105+
[ document, window, text, 1, true, undefined, '1', null, [ 1 ], { a: 1 }, NaN ].forEach( subject => {
106+
expect( isHTMLElement( subject ) ).toBe( false );
113107
} );
108+
} );
114109

115-
test( 'should return `false` for other subjects.', () => {
116-
[ document, window, div, text, 1, true, undefined, '1', null, [ 1 ], { a: 1 }, NaN ].forEach( subject => {
117-
expect( isHTMLButtonElement( subject ) ).toBe( false );
118-
} );
119-
} );
110+
test( 'should work for nodes coming from other realms.', () => {
111+
const iframe = document.querySelector( 'iframe' );
112+
113+
expect( iframe ).toBeTruthy();
114+
115+
const { contentDocument, contentWindow } = iframe;
116+
const iDiv = contentDocument.createElement( 'div' );
117+
118+
expect( contentWindow ).not.toBe( window );
119+
120+
// This should fail since `HTMLElement` is different with the iframe's.
121+
expect( iDiv instanceof HTMLElement ).toBe( false );
122+
123+
// But this method will work since checking owners.
124+
expect( isHTMLElement( iDiv ) ).toBe( true );
120125
} );
121-
} );
126+
127+
test( 'should work for nodes that do not belong to a specific window.', () => {
128+
const div = new DOMParser().parseFromString( '<div>', 'text/html' ).body.firstElementChild;
129+
130+
expect( div ).toBeTruthy();
131+
expect( div.ownerDocument.defaultView ).toBeNull();
132+
expect( isHTMLElement( div ) ).toBe( true );
133+
} );
134+
} );

src/js/utils/type/type.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,17 @@ export function isNull( subject: unknown ): subject is null {
7373
}
7474

7575
/**
76-
* Checks if the given subject is an HTMLElement or not.
76+
* Checks if the given subject is an HTMLElement instance or not.
77+
* This method takes into account which `window` the node belongs to.
7778
*
7879
* @param subject - A subject to check.
7980
*
8081
* @return `true` if the subject is an HTMLElement instance, or otherwise `false`.
8182
*/
8283
export function isHTMLElement( subject: unknown ): subject is HTMLElement {
83-
return subject instanceof HTMLElement;
84-
}
85-
86-
/**
87-
* Checks if the given subject is an HTMLButtonElement or not.
88-
*
89-
* @param subject - A subject to check.
90-
*
91-
* @return `true` if the subject is an HTMLButtonElement, or otherwise `false`.
92-
*/
93-
export function isHTMLButtonElement( subject: unknown ): subject is HTMLButtonElement {
94-
return subject instanceof HTMLButtonElement;
95-
}
84+
try {
85+
return subject instanceof ( ( subject as Node ).ownerDocument.defaultView || window ).HTMLElement;
86+
} catch ( e ) {
87+
return false;
88+
}
89+
}

0 commit comments

Comments
 (0)