Skip to content

Commit 5f33510

Browse files
Get document from parentNode.ownerDocument
Co-authored-by: Hydrophobefireman <[email protected]>
1 parent 1807173 commit 5f33510

File tree

7 files changed

+76
-16
lines changed

7 files changed

+76
-16
lines changed

compat/src/portals.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ function Portal(props) {
5151
removeChild(child) {
5252
this.childNodes.splice(this.childNodes.indexOf(child) >>> 1, 1);
5353
_this._container.removeChild(child);
54-
}
54+
},
55+
ownerDocument: container.ownerDocument
5556
};
5657
}
5758

src/component.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ function renderComponent(component) {
141141
commitQueue,
142142
oldDom == null ? getDomSibling(oldVNode) : oldDom,
143143
!!(oldVNode._flags & MODE_HYDRATE),
144-
refQueue
144+
refQueue,
145+
component._parentDom.ownerDocument
145146
);
146147

147148
newVNode._original = oldVNode._original;

src/diff/children.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { getDomSibling } from '../component';
2525
* siblings. In most cases, it starts out as `oldChildren[0]._dom`.
2626
* @param {boolean} isHydrating Whether or not we are in hydration
2727
* @param {any[]} refQueue an array of elements needed to invoke refs
28+
* @param {Document} doc The owner document of the parentNode
2829
*/
2930
export function diffChildren(
3031
parentDom,
@@ -37,7 +38,8 @@ export function diffChildren(
3738
commitQueue,
3839
oldDom,
3940
isHydrating,
40-
refQueue
41+
refQueue,
42+
doc
4143
) {
4244
let i,
4345
/** @type {VNode} */
@@ -86,7 +88,8 @@ export function diffChildren(
8688
commitQueue,
8789
oldDom,
8890
isHydrating,
89-
refQueue
91+
refQueue,
92+
doc
9093
);
9194

9295
// Adjust DOM nodes

src/diff/index.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import options from '../options';
2828
* siblings. In most cases, it starts out as `oldChildren[0]._dom`.
2929
* @param {boolean} isHydrating Whether or not we are in hydration
3030
* @param {any[]} refQueue an array of elements needed to invoke refs
31+
* @param {Document} doc The owner document of the parentNode
3132
*/
3233
export function diff(
3334
parentDom,
@@ -39,7 +40,8 @@ export function diff(
3940
commitQueue,
4041
oldDom,
4142
isHydrating,
42-
refQueue
43+
refQueue,
44+
doc
4345
) {
4446
/** @type {any} */
4547
let tmp,
@@ -254,7 +256,8 @@ export function diff(
254256
commitQueue,
255257
oldDom,
256258
isHydrating,
257-
refQueue
259+
refQueue,
260+
doc
258261
);
259262

260263
c.base = newVNode._dom;
@@ -304,7 +307,8 @@ export function diff(
304307
excessDomChildren,
305308
commitQueue,
306309
isHydrating,
307-
refQueue
310+
refQueue,
311+
doc
308312
);
309313
}
310314

@@ -353,6 +357,7 @@ export function commitRoot(commitQueue, root, refQueue) {
353357
* to invoke in commitRoot
354358
* @param {boolean} isHydrating Whether or not we are in hydration
355359
* @param {any[]} refQueue an array of elements needed to invoke refs
360+
* @param {Document} doc The owner document of the parentNode
356361
* @returns {PreactElement}
357362
*/
358363
function diffElementNodes(
@@ -364,7 +369,8 @@ function diffElementNodes(
364369
excessDomChildren,
365370
commitQueue,
366371
isHydrating,
367-
refQueue
372+
refQueue,
373+
doc
368374
) {
369375
let oldProps = oldVNode.props;
370376
let newProps = newVNode.props;
@@ -408,14 +414,10 @@ function diffElementNodes(
408414

409415
if (dom == null) {
410416
if (nodeType === null) {
411-
return document.createTextNode(newProps);
417+
return doc.createTextNode(newProps);
412418
}
413419

414-
dom = document.createElementNS(
415-
namespace,
416-
nodeType,
417-
newProps.is && newProps
418-
);
420+
dom = doc.createElementNS(namespace, nodeType, newProps.is && newProps);
419421

420422
// we are creating a new node, so we can assume this is a new subtree (in
421423
// case we are hydrating), this deopts the hydrate
@@ -517,7 +519,8 @@ function diffElementNodes(
517519
? excessDomChildren[0]
518520
: oldVNode._children && getDomSibling(oldVNode, 0),
519521
isHydrating,
520-
refQueue
522+
refQueue,
523+
doc
521524
);
522525

523526
// Remove children that are not part of any vnode.

src/internal.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ declare global {
119119
_children?: VNode<any> | null;
120120
/** Event listeners to support event delegation */
121121
_listeners?: Record<string, (e: Event) => void>;
122+
ownerDocument: Document;
122123
}
123124

124125
export interface PreactEvent extends Event {

src/render.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ export function render(vnode, parentDom, replaceNode) {
5656
? oldVNode._dom
5757
: parentDom.firstChild,
5858
isHydrating,
59-
refQueue
59+
refQueue,
60+
parentDom.ownerDocument
6061
);
6162

6263
// Flush all queued effects

test/browser/getOwnerDocument.test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { createElement, render } from 'preact';
2+
import { setupScratch, teardown } from '../_util/helpers';
3+
4+
/** @jsx createElement */
5+
6+
describe.only('parentDom.ownerDocument', () => {
7+
/** @type {HTMLDivElement} */
8+
let scratch;
9+
10+
before(() => {
11+
scratch = setupScratch();
12+
});
13+
14+
after(() => {
15+
teardown(scratch);
16+
});
17+
18+
it('should reference the correct document from the parent node', () => {
19+
let iframe = document.createElement('iframe');
20+
21+
scratch.appendChild(iframe);
22+
23+
let iframeDoc = iframe.contentDocument;
24+
25+
iframeDoc.write(
26+
'<!DOCTYPE html><html><head></head><body><div></div></body></html>'
27+
);
28+
29+
iframeDoc.close();
30+
31+
let rootTextSpy = sinon.spy(document, 'createTextNode');
32+
let rootElementSpy = sinon.spy(document, 'createElement');
33+
34+
let iframeTextSpy = sinon.spy(iframeDoc, 'createTextNode');
35+
let iframeElementSpy = sinon.spy(iframeDoc, 'createElement');
36+
37+
let iframeRootNode = iframeDoc.querySelector('div');
38+
39+
render(<span>Hello</span>, iframeRootNode);
40+
41+
expect(rootTextSpy).not.to.be.called;
42+
expect(rootElementSpy).not.to.be.called;
43+
expect(iframeTextSpy).to.be.called;
44+
expect(iframeElementSpy).to.be.called;
45+
46+
expect(iframeRootNode.textContent).to.be.equal('Hello');
47+
expect(iframeRootNode.firstChild.ownerDocument).to.be.equal(iframeDoc);
48+
expect(iframeRootNode.firstChild.ownerDocument).to.not.be.equal(document);
49+
});
50+
});

0 commit comments

Comments
 (0)