diff --git a/compat/src/portals.js b/compat/src/portals.js index c480a3d3a3..b48f2356f5 100644 --- a/compat/src/portals.js +++ b/compat/src/portals.js @@ -39,7 +39,7 @@ function Portal(props) { nodeType: 1, parentNode: container, childNodes: [], - contains: () => true, + isPortal: true, // Technically this isn't needed appendChild(child) { this.childNodes.push(child); diff --git a/src/diff/children.js b/src/diff/children.js index 5053a51174..784476fdca 100644 --- a/src/diff/children.js +++ b/src/diff/children.js @@ -7,7 +7,7 @@ import { MATCHED, UNDEFINED } from '../constants'; -import { isArray } from '../util'; +import { isArray, contains } from '../util'; import { getDomSibling } from '../component'; /** @@ -339,7 +339,7 @@ function insert(parentVNode, oldDom, parentDom) { return oldDom; } else if (parentVNode._dom != oldDom) { - if (oldDom && parentVNode.type && !parentDom.contains(oldDom)) { + if (oldDom && parentVNode.type && !contains(parentDom, oldDom)) { oldDom = getDomSibling(parentVNode); } parentDom.insertBefore(parentVNode._dom, oldDom || null); diff --git a/src/util.js b/src/util.js index 647519175f..1907e525b9 100644 --- a/src/util.js +++ b/src/util.js @@ -25,4 +25,23 @@ export function removeNode(node) { if (node && node.parentNode) node.parentNode.removeChild(node); } +/** + * Checks whether a given node is contained within a specified parent node's subtree. + * This function is a workaround for Internet Explorer 11's limited support for + * `Element.prototype.contains()`, which works only for DOM elements and does not + * support text nodes. + * + * @param {import('./internal').PreactElement} parent - The parent node within which to search for the `node`. + * @param {import('./index').ContainerNode} node - The node to check for containment within the `parent` subtree. + */ +export function contains(parent, node) { + if ('isPortal' in parent) return true; + + while (node) { + if (node === parent) return true; + node = node.parentNode; + } + return false; +} + export const slice = EMPTY_ARR.slice;