UNPKG

@webcomponents/custom-elements

Version:
180 lines 8.29 kB
/** * @license * Copyright (c) 2016 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt The complete set of authors may be found * at http://polymer.github.io/AUTHORS.txt The complete set of contributors may * be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by * Google as part of the polymer project is also subject to an additional IP * rights grant found at http://polymer.github.io/PATENTS.txt */ import * as Utilities from '../Utilities.js'; import * as Native from './Native.js'; export default function (internals) { // `Node#nodeValue` is implemented on `Attr`. // `Node#textContent` is implemented on `Attr`, `Element`. Node.prototype.insertBefore = function (node, refNode) { if (node instanceof DocumentFragment) { const insertedNodes = Utilities.childrenFromFragment(node); const nativeResult = Native.Node_insertBefore.call(this, node, refNode); // DocumentFragments can't be connected, so `disconnectTree` will never // need to be called on a DocumentFragment's children after inserting it. if (Utilities.isConnected(this)) { for (let i = 0; i < insertedNodes.length; i++) { internals.connectTree(insertedNodes[i]); } } return nativeResult; } const nodeWasConnectedElement = node instanceof Element && Utilities.isConnected(node); const nativeResult = Native.Node_insertBefore.call(this, node, refNode); if (nodeWasConnectedElement) { internals.disconnectTree(node); } if (Utilities.isConnected(this)) { internals.connectTree(node); } return nativeResult; }; Node.prototype.appendChild = function (node) { if (node instanceof DocumentFragment) { const insertedNodes = Utilities.childrenFromFragment(node); const nativeResult = Native.Node_appendChild.call(this, node); // DocumentFragments can't be connected, so `disconnectTree` will never // need to be called on a DocumentFragment's children after inserting it. if (Utilities.isConnected(this)) { for (let i = 0; i < insertedNodes.length; i++) { internals.connectTree(insertedNodes[i]); } } return nativeResult; } const nodeWasConnectedElement = node instanceof Element && Utilities.isConnected(node); const nativeResult = Native.Node_appendChild.call(this, node); if (nodeWasConnectedElement) { internals.disconnectTree(node); } if (Utilities.isConnected(this)) { internals.connectTree(node); } return nativeResult; }; Node.prototype.cloneNode = function (deep) { const clone = Native.Node_cloneNode.call(this, !!deep); // Only create custom elements if this element's owner document is // associated with the registry. if (!this.ownerDocument.__CE_registry) { internals.patchTree(clone); } else { internals.patchAndUpgradeTree(clone); } return clone; }; Node.prototype.removeChild = function (node) { const nodeWasConnectedElement = node instanceof Element && Utilities.isConnected(node); const nativeResult = Native.Node_removeChild.call(this, node); if (nodeWasConnectedElement) { internals.disconnectTree(node); } return nativeResult; }; Node.prototype.replaceChild = function (nodeToInsert, nodeToRemove) { if (nodeToInsert instanceof DocumentFragment) { const insertedNodes = Utilities.childrenFromFragment(nodeToInsert); const nativeResult = Native.Node_replaceChild.call(this, nodeToInsert, nodeToRemove); // DocumentFragments can't be connected, so `disconnectTree` will never // need to be called on a DocumentFragment's children after inserting it. if (Utilities.isConnected(this)) { internals.disconnectTree(nodeToRemove); for (let i = 0; i < insertedNodes.length; i++) { internals.connectTree(insertedNodes[i]); } } return nativeResult; } const nodeToInsertWasConnectedElement = nodeToInsert instanceof Element && Utilities.isConnected(nodeToInsert); const nativeResult = Native.Node_replaceChild.call(this, nodeToInsert, nodeToRemove); const thisIsConnected = Utilities.isConnected(this); if (thisIsConnected) { internals.disconnectTree(nodeToRemove); } if (nodeToInsertWasConnectedElement) { internals.disconnectTree(nodeToInsert); } if (thisIsConnected) { internals.connectTree(nodeToInsert); } return nativeResult; }; function patch_textContent(destination, baseDescriptor) { Object.defineProperty(destination, 'textContent', { enumerable: baseDescriptor.enumerable, configurable: true, get: baseDescriptor.get, set: function (assignedValue) { // If this is a text node then there are no nodes to disconnect. if (this.nodeType === Node.TEXT_NODE) { baseDescriptor.set.call(this, assignedValue); return; } let removedNodes = undefined; // Checking for `firstChild` is faster than reading `childNodes.length` // to compare with 0. if (this.firstChild) { // Using `childNodes` is faster than `children`, even though we only // care about elements. const childNodes = this.childNodes; const childNodesLength = childNodes.length; if (childNodesLength > 0 && Utilities.isConnected(this)) { // Copying an array by iterating is faster than using slice. removedNodes = new Array(childNodesLength); for (let i = 0; i < childNodesLength; i++) { removedNodes[i] = childNodes[i]; } } } baseDescriptor.set.call(this, assignedValue); if (removedNodes) { for (let i = 0; i < removedNodes.length; i++) { internals.disconnectTree(removedNodes[i]); } } }, }); } if (Native.Node_textContent && Native.Node_textContent.get) { patch_textContent(Node.prototype, Native.Node_textContent); } else { internals.addNodePatch(function (element) { patch_textContent(element, { enumerable: true, configurable: true, // NOTE: This implementation of the `textContent` getter assumes that // text nodes' `textContent` getter will not be patched. get: function () { const parts = []; for (let n = this.firstChild; n; n = n.nextSibling) { if (n.nodeType === Node.COMMENT_NODE) { continue; } parts.push(n.textContent); } return parts.join(''); }, set: function (assignedValue) { while (this.firstChild) { Native.Node_removeChild.call(this, this.firstChild); } // `textContent = null | undefined | ''` does not result in // a TextNode childNode if (assignedValue != null && assignedValue !== '') { Native.Node_appendChild.call(this, document.createTextNode(assignedValue)); } }, }); }); } } //# sourceMappingURL=Node.js.map