Skip to content

Ownerdocument rebased #4501

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compat/src/portals.js
Original file line number Diff line number Diff line change
@@ -52,7 +52,8 @@ function Portal(props) {
removeChild(child) {
this.childNodes.splice(this.childNodes.indexOf(child) >>> 1, 1);
_this._container.removeChild(child);
}
},
ownerDocument: container.ownerDocument
};
}

3 changes: 2 additions & 1 deletion src/component.js
Original file line number Diff line number Diff line change
@@ -141,7 +141,8 @@ function renderComponent(component) {
commitQueue,
oldDom == NULL ? getDomSibling(oldVNode) : oldDom,
!!(oldVNode._flags & MODE_HYDRATE),
refQueue
refQueue,
component._parentDom.ownerDocument
);

newVNode._original = oldVNode._original;
7 changes: 5 additions & 2 deletions src/diff/children.js
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ import { getDomSibling } from '../component';
* siblings. In most cases, it starts out as `oldChildren[0]._dom`.
* @param {boolean} isHydrating Whether or not we are in hydration
* @param {any[]} refQueue an array of elements needed to invoke refs
* @param {Document} doc The owner document of the parentNode
*/
export function diffChildren(
parentDom,
@@ -51,7 +52,8 @@ export function diffChildren(
commitQueue,
oldDom,
isHydrating,
refQueue
refQueue,
doc
) {
let i,
/** @type {VNode} */
@@ -104,7 +106,8 @@ export function diffChildren(
commitQueue,
oldDom,
isHydrating,
refQueue
refQueue,
doc
);

// Adjust DOM nodes
25 changes: 14 additions & 11 deletions src/diff/index.js
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ import options from '../options';
* siblings. In most cases, it starts out as `oldChildren[0]._dom`.
* @param {boolean} isHydrating Whether or not we are in hydration
* @param {any[]} refQueue an array of elements needed to invoke refs
* @param {Document} doc The owner document of the parentNode
*/
export function diff(
parentDom,
@@ -56,7 +57,8 @@ export function diff(
commitQueue,
oldDom,
isHydrating,
refQueue
refQueue,
doc
) {
/** @type {any} */
let tmp,
@@ -275,7 +277,8 @@ export function diff(
commitQueue,
oldDom,
isHydrating,
refQueue
refQueue,
doc
);

c.base = newVNode._dom;
@@ -332,7 +335,8 @@ export function diff(
excessDomChildren,
commitQueue,
isHydrating,
refQueue
refQueue,
doc
);
}

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

if (dom == NULL) {
if (nodeType == NULL) {
return document.createTextNode(newProps);
return doc.createTextNode(newProps);
}

dom = document.createElementNS(
namespace,
nodeType,
newProps.is && newProps
);
dom = doc.createElementNS(namespace, nodeType, newProps.is && newProps);

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

// Remove children that are not part of any vnode.
4 changes: 2 additions & 2 deletions src/internal.d.ts
Original file line number Diff line number Diff line change
@@ -62,8 +62,7 @@ export type ComponentChild =
| undefined;
export type ComponentChildren = ComponentChild[] | ComponentChild;

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

export interface PreactEvent extends Event {
3 changes: 2 additions & 1 deletion src/render.js
Original file line number Diff line number Diff line change
@@ -61,7 +61,8 @@ export function render(vnode, parentDom, replaceNode) {
? oldVNode._dom
: parentDom.firstChild,
isHydrating,
refQueue
refQueue,
parentDom.ownerDocument
);

// Flush all queued effects
50 changes: 50 additions & 0 deletions test/browser/getOwnerDocument.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { createElement, render } from 'preact';
import { setupScratch, teardown } from '../_util/helpers';

/** @jsx createElement */

describe('parentDom.ownerDocument', () => {
/** @type {HTMLDivElement} */
let scratch;

before(() => {
scratch = setupScratch();
});

after(() => {
teardown(scratch);
});

it('should reference the correct document from the parent node', () => {
let iframe = document.createElement('iframe');

scratch.appendChild(iframe);

let iframeDoc = iframe.contentDocument;

iframeDoc.write(
'<!DOCTYPE html><html><head></head><body><div></div></body></html>'
);

iframeDoc.close();

let rootTextSpy = sinon.spy(document, 'createTextNode');
let rootElementSpy = sinon.spy(document, 'createElement');

let iframeTextSpy = sinon.spy(iframeDoc, 'createTextNode');
let iframeElementSpy = sinon.spy(iframeDoc, 'createElement');

let iframeRootNode = iframeDoc.querySelector('div');

render(<span>Hello</span>, iframeRootNode);

expect(rootTextSpy).not.to.be.called;
expect(rootElementSpy).not.to.be.called;
expect(iframeTextSpy).to.be.called;
expect(iframeElementSpy).to.be.called;

expect(iframeRootNode.textContent).to.be.equal('Hello');
expect(iframeRootNode.firstChild.ownerDocument).to.be.equal(iframeDoc);
expect(iframeRootNode.firstChild.ownerDocument).to.not.be.equal(document);
});
});