Skip to content

Commit 91689ec

Browse files
Get document from parentNode.ownerDocument
Co-authored-by: Hydrophobefireman <hi@hpfm.dev>
1 parent 8941185 commit 91689ec

File tree

7 files changed

+77
-18
lines changed

7 files changed

+77
-18
lines changed

compat/src/portals.js

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

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
@@ -39,6 +39,7 @@ import { getDomSibling } from '../component';
3939
* siblings. In most cases, it starts out as `oldChildren[0]._dom`.
4040
* @param {boolean} isHydrating Whether or not we are in hydration
4141
* @param {any[]} refQueue an array of elements needed to invoke refs
42+
* @param {Document} doc The owner document of the parentNode
4243
*/
4344
export function diffChildren(
4445
parentDom,
@@ -51,7 +52,8 @@ export function diffChildren(
5152
commitQueue,
5253
oldDom,
5354
isHydrating,
54-
refQueue
55+
refQueue,
56+
doc
5557
) {
5658
let i,
5759
/** @type {VNode} */
@@ -104,7 +106,8 @@ export function diffChildren(
104106
commitQueue,
105107
oldDom,
106108
isHydrating,
107-
refQueue
109+
refQueue,
110+
doc
108111
);
109112

110113
// Adjust DOM nodes

src/diff/index.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import options from '../options';
4545
* siblings. In most cases, it starts out as `oldChildren[0]._dom`.
4646
* @param {boolean} isHydrating Whether or not we are in hydration
4747
* @param {any[]} refQueue an array of elements needed to invoke refs
48+
* @param {Document} doc The owner document of the parentNode
4849
*/
4950
export function diff(
5051
parentDom,
@@ -56,7 +57,8 @@ export function diff(
5657
commitQueue,
5758
oldDom,
5859
isHydrating,
59-
refQueue
60+
refQueue,
61+
doc
6062
) {
6163
/** @type {any} */
6264
let tmp,
@@ -275,7 +277,8 @@ export function diff(
275277
commitQueue,
276278
oldDom,
277279
isHydrating,
278-
refQueue
280+
refQueue,
281+
doc
279282
);
280283

281284
c.base = newVNode._dom;
@@ -332,7 +335,8 @@ export function diff(
332335
excessDomChildren,
333336
commitQueue,
334337
isHydrating,
335-
refQueue
338+
refQueue,
339+
doc
336340
);
337341
}
338342

@@ -381,6 +385,7 @@ export function commitRoot(commitQueue, root, refQueue) {
381385
* to invoke in commitRoot
382386
* @param {boolean} isHydrating Whether or not we are in hydration
383387
* @param {any[]} refQueue an array of elements needed to invoke refs
388+
* @param {Document} doc The owner document of the parentNode
384389
* @returns {PreactElement}
385390
*/
386391
function diffElementNodes(
@@ -392,7 +397,8 @@ function diffElementNodes(
392397
excessDomChildren,
393398
commitQueue,
394399
isHydrating,
395-
refQueue
400+
refQueue,
401+
doc
396402
) {
397403
let oldProps = oldVNode.props;
398404
let newProps = newVNode.props;
@@ -435,14 +441,10 @@ function diffElementNodes(
435441

436442
if (dom == NULL) {
437443
if (nodeType == NULL) {
438-
return document.createTextNode(newProps);
444+
return doc.createTextNode(newProps);
439445
}
440446

441-
dom = document.createElementNS(
442-
namespace,
443-
nodeType,
444-
newProps.is && newProps
445-
);
447+
dom = doc.createElementNS(namespace, nodeType, newProps.is && newProps);
446448

447449
// we are creating a new node, so we can assume this is a new subtree (in
448450
// case we are hydrating), this deopts the hydrate
@@ -543,7 +545,8 @@ function diffElementNodes(
543545
? excessDomChildren[0]
544546
: oldVNode._children && getDomSibling(oldVNode, 0),
545547
isHydrating,
546-
refQueue
548+
refQueue,
549+
doc
547550
);
548551

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

src/internal.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ export type ComponentChild =
6262
| undefined;
6363
export type ComponentChildren = ComponentChild[] | ComponentChild;
6464

65-
export interface FunctionComponent<P = {}>
66-
extends preact.FunctionComponent<P> {
65+
export interface FunctionComponent<P = {}> extends preact.FunctionComponent<P> {
6766
// Internally, createContext uses `contextType` on a Function component to
6867
// implement the Consumer component
6968
contextType?: PreactContext;
@@ -123,6 +122,7 @@ export interface PreactElement extends preact.ContainerNode {
123122
_children?: VNode<any> | null;
124123
/** Event listeners to support event delegation */
125124
_listeners?: Record<string, (e: Event) => void>;
125+
ownerDocument: Document;
126126
}
127127

128128
export interface PreactEvent extends Event {

src/render.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ export function render(vnode, parentDom, replaceNode) {
6161
? oldVNode._dom
6262
: parentDom.firstChild,
6363
isHydrating,
64-
refQueue
64+
refQueue,
65+
parentDom.ownerDocument
6566
);
6667

6768
// 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('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)