-
Notifications
You must be signed in to change notification settings - Fork 400
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(engine): fixes #973 to support cloneNode with ie11 devtool comment (
#974) * fix(engine): fixes #973 to support cloneNode with ie11 devtool comment * fix(engine): fix for devtool logging of -bash on a root custom element * fix(engine): more guarding around isNodeSlotted for inserted nodes
- Loading branch information
Showing
4 changed files
with
73 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import { | |
forEach, | ||
getPrototypeOf, | ||
setPrototypeOf, | ||
isFalse, | ||
} from '../shared/language'; | ||
import { | ||
parentNodeGetter, | ||
|
@@ -31,6 +32,8 @@ import { getShadowRoot } from './shadow-root'; | |
const OwnerKey = '$$OwnerKey$$'; | ||
const OwnKey = '$$OwnKey$$'; | ||
|
||
export const hasNativeSymbolsSupport = Symbol('x').toString() === 'Symbol(x)'; | ||
|
||
export function getNodeOwnerKey(node: Node): number | undefined { | ||
return node[OwnerKey]; | ||
} | ||
|
@@ -40,12 +43,18 @@ export function setNodeOwnerKey(node: Node, key: number) { | |
} | ||
|
||
export function getNodeNearestOwnerKey(node: Node): number | undefined { | ||
let ownerKey: number | undefined; | ||
let ownerNode: Node | null = node; | ||
// search for the first element with owner identity (just in case of manually inserted elements) | ||
while (!isNull(node) && isUndefined((ownerKey = node[OwnerKey]))) { | ||
node = parentNodeGetter.call(node); | ||
while (!isNull(ownerNode)) { | ||
if (!isUndefined(ownerNode[OwnerKey])) { | ||
return ownerNode[OwnerKey]; | ||
} else if (!isUndefined(ownerNode[OwnKey])) { | ||
// perf optimization: | ||
// root elements have ownKey but not ownerKey, we don't need to walk up anymore | ||
return; | ||
} | ||
ownerNode = parentNodeGetter.call(ownerNode); | ||
} | ||
return ownerKey; | ||
} | ||
|
||
export function getNodeKey(node: Node): number | undefined { | ||
|
@@ -66,7 +75,7 @@ const portalObserverConfig: MutationObserverInit = { | |
}; | ||
|
||
function patchPortalElement(node: Node, ownerKey: number, shadowToken: string | undefined) { | ||
// If node aleady has an ownerkey, we can skip | ||
// If node already has an ownerKey, we can skip | ||
// Note: checking if a node as any ownerKey is not enough | ||
// because this element could be moved from one | ||
// shadow to another | ||
|
@@ -76,7 +85,7 @@ function patchPortalElement(node: Node, ownerKey: number, shadowToken: string | | |
setNodeOwnerKey(node, ownerKey); | ||
if (node instanceof Element) { | ||
setCSSToken(node, shadowToken); | ||
const { childNodes } = node; | ||
const childNodes = getInternalChildNodes(node); | ||
for (let i = 0, len = childNodes.length; i < len; i += 1) { | ||
const child = childNodes[i]; | ||
patchPortalElement(child, ownerKey, shadowToken); | ||
|
@@ -171,17 +180,17 @@ export function PatchedNode(node: Node): NodeConstructor { | |
throw new TypeError('Illegal constructor'); | ||
} | ||
hasChildNodes(this: Node, ) { | ||
return this.childNodes.length > 0; | ||
return getInternalChildNodes(this).length > 0; | ||
} | ||
// @ts-ignore until [email protected] | ||
get firstChild(this: Node): ChildNode | null { | ||
const { childNodes } = this; | ||
const childNodes = getInternalChildNodes(this); | ||
// @ts-ignore until [email protected] | ||
return childNodes[0] || null; | ||
} | ||
// @ts-ignore until [email protected] | ||
get lastChild(this: Node): ChildNode | null { | ||
const { childNodes } = this; | ||
const childNodes = getInternalChildNodes(this); | ||
// @ts-ignore until [email protected] | ||
return childNodes[childNodes.length - 1] || null; | ||
} | ||
|
@@ -202,7 +211,7 @@ export function PatchedNode(node: Node): NodeConstructor { | |
return children.item(children.length - 1) || null; | ||
} | ||
get assignedSlot(this: Node): HTMLElement | null { | ||
const parentNode: HTMLElement = nativeParentNodeGetter.call(this); | ||
const parentNode = nativeParentNodeGetter.call(this); | ||
/** | ||
* if it doesn't have a parent node, | ||
* or the parent is not an slot element | ||
|
@@ -263,7 +272,7 @@ export function PatchedNode(node: Node): NodeConstructor { | |
return clone; | ||
} | ||
|
||
const childNodes = this.childNodes; | ||
const childNodes = getInternalChildNodes(this); | ||
for (let i = 0, len = childNodes.length; i < len; i += 1) { | ||
clone.appendChild(childNodes[i].cloneNode(true)); | ||
} | ||
|
@@ -276,3 +285,36 @@ export function PatchedNode(node: Node): NodeConstructor { | |
setPrototypeOf(PatchedNodeClass.prototype, Ctor.prototype); | ||
return (PatchedNodeClass as any) as NodeConstructor; | ||
} | ||
|
||
let internalChildNodeAccessorFlag = false; | ||
|
||
/** | ||
* These 2 methods are providing a machinery to understand who is accessing the | ||
* .childNodes member property of a node. If it is used from inside the synthetic shadow | ||
* or from an external invoker. This helps to produce the right output in one very peculiar | ||
* case, the IE11 debugging comment for shadowRoot representation on the devtool. | ||
*/ | ||
export function isExternalChildNodeAccessorFlagOn(): boolean { | ||
return !internalChildNodeAccessorFlag; | ||
} | ||
export const getInternalChildNodes = (process.env.NODE_ENV !== 'production' && isFalse(hasNativeSymbolsSupport)) ? | ||
function(node: Node): NodeListOf<ChildNode> { | ||
internalChildNodeAccessorFlag = true; | ||
let childNodes; | ||
let error = null; | ||
try { | ||
childNodes = node.childNodes; | ||
} catch (e) { | ||
// childNodes accessor should never throw, but just in case! | ||
error = e; | ||
} finally { | ||
internalChildNodeAccessorFlag = false; | ||
if (!isNull(error)) { | ||
// re-throwing after restoring the state machinery for setInternalChildNodeAccessorFlag | ||
throw error; // tslint:disable-line | ||
} | ||
} | ||
return childNodes; | ||
} : function(node: Node): NodeListOf<ChildNode> { | ||
return node.childNodes; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters