Server IP : 162.213.251.212 / Your IP : 18.118.30.58 [ Web Server : LiteSpeed System : Linux business55.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64 User : allssztx ( 535) PHP Version : 8.1.31 Disable Function : NONE Domains : 1 Domains MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/allssztx/nodevenv/needapair.com/20/lib/node_modules/@xmldom/xmldom/lib/ |
Upload File : |
'use strict'; var conventions = require('./conventions'); var find = conventions.find; var hasDefaultHTMLNamespace = conventions.hasDefaultHTMLNamespace; var hasOwn = conventions.hasOwn; var isHTMLMimeType = conventions.isHTMLMimeType; var isHTMLRawTextElement = conventions.isHTMLRawTextElement; var isHTMLVoidElement = conventions.isHTMLVoidElement; var MIME_TYPE = conventions.MIME_TYPE; var NAMESPACE = conventions.NAMESPACE; /** * Private DOM Constructor symbol * * Internal symbol used for construction of all classes whose constructors should be private. * Currently used for checks in `Node`, `Document`, `Element`, `Attr`, `CharacterData`, `Text`, `Comment`, * `CDATASection`, `DocumentType`, `Notation`, `Entity`, `EntityReference`, `DocumentFragment`, `ProcessingInstruction` * so the constructor can't be used from outside the module. */ var PDC = Symbol(); var errors = require('./errors'); var DOMException = errors.DOMException; var DOMExceptionName = errors.DOMExceptionName; var g = require('./grammar'); /** * Checks if the given symbol equals the Private DOM Constructor symbol (PDC) * and throws an Illegal constructor exception when the symbols don't match. * This ensures that the constructor remains private and can't be used outside this module. */ function checkSymbol(symbol) { if (symbol !== PDC) { throw new TypeError('Illegal constructor'); } } /** * A prerequisite for `[].filter`, to drop elements that are empty. * * @param {string} input * The string to be checked. * @returns {boolean} * Returns `true` if the input string is not empty, `false` otherwise. */ function notEmptyString(input) { return input !== ''; } /** * Splits a string on ASCII whitespace characters (U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, * U+0020 SPACE). * It follows the definition from the infra specification from WHATWG. * * @param {string} input * The string to be split. * @returns {string[]} * An array of the split strings. The array can be empty if the input string is empty or only * contains whitespace characters. * @see {@link https://infra.spec.whatwg.org/#split-on-ascii-whitespace} * @see {@link https://infra.spec.whatwg.org/#ascii-whitespace} */ function splitOnASCIIWhitespace(input) { // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, U+0020 SPACE return input ? input.split(/[\t\n\f\r ]+/).filter(notEmptyString) : []; } /** * Adds element as a key to current if it is not already present. * * @param {Record<string, boolean | undefined>} current * The current record object to which the element will be added as a key. * The object's keys are string types and values are either boolean or undefined. * @param {string} element * The string to be added as a key to the current record. * @returns {Record<string, boolean | undefined>} * The updated record object after the addition of the new element. */ function orderedSetReducer(current, element) { if (!hasOwn(current, element)) { current[element] = true; } return current; } /** * Converts a string into an ordered set by splitting the input on ASCII whitespace and * ensuring uniqueness of elements. * This follows the definition of an ordered set from the infra specification by WHATWG. * * @param {string} input * The input string to be transformed into an ordered set. * @returns {string[]} * An array of unique strings obtained from the input, preserving the original order. * The array can be empty if the input string is empty or only contains whitespace characters. * @see {@link https://infra.spec.whatwg.org/#ordered-set} */ function toOrderedSet(input) { if (!input) return []; var list = splitOnASCIIWhitespace(input); return Object.keys(list.reduce(orderedSetReducer, {})); } /** * Uses `list.indexOf` to implement a function that behaves like `Array.prototype.includes`. * This function is used in environments where `Array.prototype.includes` may not be available. * * @param {any[]} list * The array in which to search for the element. * @returns {function(any): boolean} * A function that accepts an element and returns a boolean indicating whether the element is * included in the provided list. */ function arrayIncludes(list) { return function (element) { return list && list.indexOf(element) !== -1; }; } /** * Validates a qualified name based on the criteria provided in the DOM specification by * WHATWG. * * @param {string} qualifiedName * The qualified name to be validated. * @throws {DOMException} * With code {@link DOMException.INVALID_CHARACTER_ERR} if the qualified name contains an * invalid character. * @see {@link https://dom.spec.whatwg.org/#validate} */ function validateQualifiedName(qualifiedName) { if (!g.QName_exact.test(qualifiedName)) { throw new DOMException(DOMException.INVALID_CHARACTER_ERR, 'invalid character in qualified name "' + qualifiedName + '"'); } } /** * Validates a qualified name and the namespace associated with it, * based on the criteria provided in the DOM specification by WHATWG. * * @param {string | null} namespace * The namespace to be validated. It can be a string or null. * @param {string} qualifiedName * The qualified name to be validated. * @returns {[namespace: string | null, prefix: string | null, localName: string]} * Returns a tuple with the namespace, * prefix and local name of the qualified name. * @throws {DOMException} * Throws a DOMException if the qualified name or the namespace is not valid. * @see {@link https://dom.spec.whatwg.org/#validate-and-extract} */ function validateAndExtract(namespace, qualifiedName) { validateQualifiedName(qualifiedName); namespace = namespace || null; /** * @type {string | null} */ var prefix = null; var localName = qualifiedName; if (qualifiedName.indexOf(':') >= 0) { var splitResult = qualifiedName.split(':'); prefix = splitResult[0]; localName = splitResult[1]; } if (prefix !== null && namespace === null) { throw new DOMException(DOMException.NAMESPACE_ERR, 'prefix is non-null and namespace is null'); } if (prefix === 'xml' && namespace !== conventions.NAMESPACE.XML) { throw new DOMException(DOMException.NAMESPACE_ERR, 'prefix is "xml" and namespace is not the XML namespace'); } if ((prefix === 'xmlns' || qualifiedName === 'xmlns') && namespace !== conventions.NAMESPACE.XMLNS) { throw new DOMException( DOMException.NAMESPACE_ERR, 'either qualifiedName or prefix is "xmlns" and namespace is not the XMLNS namespace' ); } if (namespace === conventions.NAMESPACE.XMLNS && prefix !== 'xmlns' && qualifiedName !== 'xmlns') { throw new DOMException( DOMException.NAMESPACE_ERR, 'namespace is the XMLNS namespace and neither qualifiedName nor prefix is "xmlns"' ); } return [namespace, prefix, localName]; } /** * Copies properties from one object to another. * It only copies the object's own (not inherited) properties. * * @param {Object} src * The source object from which properties are copied. * @param {Object} dest * The destination object to which properties are copied. */ function copy(src, dest) { for (var p in src) { if (hasOwn(src, p)) { dest[p] = src[p]; } } } /** * Extends a class with the properties and methods of a super class. * It uses a form of prototypal inheritance, and establishes the `constructor` property * correctly(?). * * It is not clear to the current maintainers if this implementation is making sense, * since it creates an intermediate prototype function, * which all properties of `Super` are copied onto using `_copy`. * * @param {Object} Class * The class that is to be extended. * @param {Object} Super * The super class from which properties and methods are inherited. * @private */ function _extends(Class, Super) { var pt = Class.prototype; if (!(pt instanceof Super)) { function t() {} t.prototype = Super.prototype; t = new t(); copy(pt, t); Class.prototype = pt = t; } if (pt.constructor != Class) { if (typeof Class != 'function') { console.error('unknown Class:' + Class); } pt.constructor = Class; } } var NodeType = {}; var ELEMENT_NODE = (NodeType.ELEMENT_NODE = 1); var ATTRIBUTE_NODE = (NodeType.ATTRIBUTE_NODE = 2); var TEXT_NODE = (NodeType.TEXT_NODE = 3); var CDATA_SECTION_NODE = (NodeType.CDATA_SECTION_NODE = 4); var ENTITY_REFERENCE_NODE = (NodeType.ENTITY_REFERENCE_NODE = 5); var ENTITY_NODE = (NodeType.ENTITY_NODE = 6); var PROCESSING_INSTRUCTION_NODE = (NodeType.PROCESSING_INSTRUCTION_NODE = 7); var COMMENT_NODE = (NodeType.COMMENT_NODE = 8); var DOCUMENT_NODE = (NodeType.DOCUMENT_NODE = 9); var DOCUMENT_TYPE_NODE = (NodeType.DOCUMENT_TYPE_NODE = 10); var DOCUMENT_FRAGMENT_NODE = (NodeType.DOCUMENT_FRAGMENT_NODE = 11); var NOTATION_NODE = (NodeType.NOTATION_NODE = 12); var DocumentPosition = conventions.freeze({ DOCUMENT_POSITION_DISCONNECTED: 1, DOCUMENT_POSITION_PRECEDING: 2, DOCUMENT_POSITION_FOLLOWING: 4, DOCUMENT_POSITION_CONTAINS: 8, DOCUMENT_POSITION_CONTAINED_BY: 16, DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32, }); //helper functions for compareDocumentPosition /** * Constructs a parent chain for a node. * * @param {Node} node * The start node from which the parent chain will be constructed. * @returns {Node[]} * The array of nodes representing the parent chain from the root to the specified node. */ function parentChain(node) { var chain = []; while (node.parentNode || node.ownerElement) { node = node.parentNode || node.ownerElement; chain.unshift(node); } return chain; } /** * Finds the common ancestor in two parent chains. * * @param {Node[]} a * The first parent chain. * @param {Node[]} b * The second parent chain. * @returns {Node} * The common ancestor node if it exists. If there is no common ancestor, the function will * return `null`. */ function commonAncestor(a, b) { if (b.length < a.length) return commonAncestor(b, a); var c = null; for (var n in a) { if (a[n] !== b[n]) return c; c = a[n]; } return c; } /** * Assigns a unique identifier to a document to ensure consistency while comparing unrelated * nodes. * * @param {Document} doc * The document to which a unique identifier is to be assigned. * @returns {string} * The unique identifier of the document. If the document already had a unique identifier, the * function will return the existing one. */ function docGUID(doc) { if (!doc.guid) doc.guid = Math.random(); return doc.guid; } //-- end of helper functions /** * The NodeList interface provides the abstraction of an ordered collection of nodes, * without defining or constraining how this collection is implemented. * NodeList objects in the DOM are live. * The items in the NodeList are accessible via an integral index, starting from 0. * You can also access the items of the NodeList with a `for...of` loop. * * @class NodeList * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177 * @constructs NodeList */ function NodeList() {} NodeList.prototype = { /** * The number of nodes in the list. The range of valid child node indices is 0 to length-1 * inclusive. * * @type {number} */ length: 0, /** * Returns the item at `index`. If index is greater than or equal to the number of nodes in * the list, this returns null. * * @param index * Unsigned long Index into the collection. * @returns {Node | null} * The node at position `index` in the NodeList, * or null if that is not a valid index. */ item: function (index) { return index >= 0 && index < this.length ? this[index] : null; }, /** * Returns a string representation of the NodeList. * * @param {unknown} nodeFilter * __A filter function? Not implemented according to the spec?__. * @returns {string} * A string representation of the NodeList. */ toString: function (nodeFilter) { for (var buf = [], i = 0; i < this.length; i++) { serializeToString(this[i], buf, nodeFilter); } return buf.join(''); }, /** * Filters the NodeList based on a predicate. * * @param {function(Node): boolean} predicate * - A predicate function to filter the NodeList. * @returns {Node[]} * An array of nodes that satisfy the predicate. * @private */ filter: function (predicate) { return Array.prototype.filter.call(this, predicate); }, /** * Returns the first index at which a given node can be found in the NodeList, or -1 if it is * not present. * * @param {Node} item * - The Node item to locate in the NodeList. * @returns {number} * The first index of the node in the NodeList; -1 if not found. * @private */ indexOf: function (item) { return Array.prototype.indexOf.call(this, item); }, }; NodeList.prototype[Symbol.iterator] = function () { var me = this; var index = 0; return { next: function () { if (index < me.length) { return { value: me[index++], done: false, }; } else { return { done: true, }; } }, return: function () { return { done: true, }; }, }; }; /** * Represents a live collection of nodes that is automatically updated when its associated * document changes. * * @class LiveNodeList * @param {Node} node * The associated node. * @param {function} refresh * The function to refresh the live node list. * @augments NodeList * @constructs LiveNodeList */ function LiveNodeList(node, refresh) { this._node = node; this._refresh = refresh; _updateLiveList(this); } /** * Updates the live node list. * * @param {LiveNodeList} list * The live node list to update. * @private */ function _updateLiveList(list) { var inc = list._node._inc || list._node.ownerDocument._inc; if (list._inc !== inc) { var ls = list._refresh(list._node); __set__(list, 'length', ls.length); if (!list.$$length || ls.length < list.$$length) { for (var i = ls.length; i in list; i++) { if (hasOwn(list, i)) { delete list[i]; } } } copy(ls, list); list._inc = inc; } } /** * Returns the node at position `index` in the LiveNodeList, or null if that is not a valid * index. * * @param {number} i * Index into the collection. * @returns {Node | null} * The node at position `index` in the LiveNodeList, or null if that is not a valid index. */ LiveNodeList.prototype.item = function (i) { _updateLiveList(this); return this[i] || null; }; _extends(LiveNodeList, NodeList); /** * Objects implementing the NamedNodeMap interface are used to represent collections of nodes * that can be accessed by name. * Note that NamedNodeMap does not inherit from NodeList; * NamedNodeMaps are not maintained in any particular order. * Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal * index, * but this is simply to allow convenient enumeration of the contents of a NamedNodeMap, * and does not imply that the DOM specifies an order to these Nodes. * NamedNodeMap objects in the DOM are live. * used for attributes or DocumentType entities * * This implementation only supports property indices, but does not support named properties, * as specified in the living standard. * * @class NamedNodeMap * @see https://dom.spec.whatwg.org/#interface-namednodemap * @see https://webidl.spec.whatwg.org/#dfn-supported-property-names * @constructs NamedNodeMap */ function NamedNodeMap() {} /** * Returns the index of a node within the list. * * @param {Array} list * The list of nodes. * @param {Node} node * The node to find. * @returns {number} * The index of the node within the list, or -1 if not found. * @private */ function _findNodeIndex(list, node) { var i = 0; while (i < list.length) { if (list[i] === node) { return i; } i++; } } /** * Adds a new attribute to the list and updates the owner element of the attribute. * * @param {Element} el * The element which will become the owner of the new attribute. * @param {NamedNodeMap} list * The list to which the new attribute will be added. * @param {Attr} newAttr * The new attribute to be added. * @param {Attr} oldAttr * The old attribute to be replaced, or null if no attribute is to be replaced. * @returns {void} * @private */ function _addNamedNode(el, list, newAttr, oldAttr) { if (oldAttr) { list[_findNodeIndex(list, oldAttr)] = newAttr; } else { list[list.length] = newAttr; list.length++; } if (el) { newAttr.ownerElement = el; var doc = el.ownerDocument; if (doc) { oldAttr && _onRemoveAttribute(doc, el, oldAttr); _onAddAttribute(doc, el, newAttr); } } } /** * Removes an attribute from the list and updates the owner element of the attribute. * * @param {Element} el * The element which is the current owner of the attribute. * @param {NamedNodeMap} list * The list from which the attribute will be removed. * @param {Attr} attr * The attribute to be removed. * @returns {void} * @private */ function _removeNamedNode(el, list, attr) { //console.log('remove attr:'+attr) var i = _findNodeIndex(list, attr); if (i >= 0) { var lastIndex = list.length - 1; while (i <= lastIndex) { list[i] = list[++i]; } list.length = lastIndex; if (el) { var doc = el.ownerDocument; if (doc) { _onRemoveAttribute(doc, el, attr); } attr.ownerElement = null; } } } NamedNodeMap.prototype = { length: 0, item: NodeList.prototype.item, /** * Get an attribute by name. Note: Name is in lower case in case of HTML namespace and * document. * * @param {string} localName * The local name of the attribute. * @returns {Attr | null} * The attribute with the given local name, or null if no such attribute exists. * @see https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name */ getNamedItem: function (localName) { if (this._ownerElement && this._ownerElement._isInHTMLDocumentAndNamespace()) { localName = localName.toLowerCase(); } var i = 0; while (i < this.length) { var attr = this[i]; if (attr.nodeName === localName) { return attr; } i++; } return null; }, /** * Set an attribute. * * @param {Attr} attr * The attribute to set. * @returns {Attr | null} * The old attribute with the same local name and namespace URI as the new one, or null if no * such attribute exists. * @throws {DOMException} * With code: * - {@link INUSE_ATTRIBUTE_ERR} - If the attribute is already an attribute of another * element. * @see https://dom.spec.whatwg.org/#concept-element-attributes-set */ setNamedItem: function (attr) { var el = attr.ownerElement; if (el && el !== this._ownerElement) { throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR); } var oldAttr = this.getNamedItemNS(attr.namespaceURI, attr.localName); if (oldAttr === attr) { return attr; } _addNamedNode(this._ownerElement, this, attr, oldAttr); return oldAttr; }, /** * Set an attribute, replacing an existing attribute with the same local name and namespace * URI if one exists. * * @param {Attr} attr * The attribute to set. * @returns {Attr | null} * The old attribute with the same local name and namespace URI as the new one, or null if no * such attribute exists. * @throws {DOMException} * Throws a DOMException with the name "InUseAttributeError" if the attribute is already an * attribute of another element. * @see https://dom.spec.whatwg.org/#concept-element-attributes-set */ setNamedItemNS: function (attr) { return this.setNamedItem(attr); }, /** * Removes an attribute specified by the local name. * * @param {string} localName * The local name of the attribute to be removed. * @returns {Attr} * The attribute node that was removed. * @throws {DOMException} * With code: * - {@link DOMException.NOT_FOUND_ERR} if no attribute with the given name is found. * @see https://dom.spec.whatwg.org/#dom-namednodemap-removenameditem * @see https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-name */ removeNamedItem: function (localName) { var attr = this.getNamedItem(localName); if (!attr) { throw new DOMException(DOMException.NOT_FOUND_ERR, localName); } _removeNamedNode(this._ownerElement, this, attr); return attr; }, /** * Removes an attribute specified by the namespace and local name. * * @param {string | null} namespaceURI * The namespace URI of the attribute to be removed. * @param {string} localName * The local name of the attribute to be removed. * @returns {Attr} * The attribute node that was removed. * @throws {DOMException} * With code: * - {@link DOMException.NOT_FOUND_ERR} if no attribute with the given namespace URI and local * name is found. * @see https://dom.spec.whatwg.org/#dom-namednodemap-removenameditemns * @see https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-namespace */ removeNamedItemNS: function (namespaceURI, localName) { var attr = this.getNamedItemNS(namespaceURI, localName); if (!attr) { throw new DOMException(DOMException.NOT_FOUND_ERR, namespaceURI ? namespaceURI + ' : ' + localName : localName); } _removeNamedNode(this._ownerElement, this, attr); return attr; }, /** * Get an attribute by namespace and local name. * * @param {string | null} namespaceURI * The namespace URI of the attribute. * @param {string} localName * The local name of the attribute. * @returns {Attr | null} * The attribute with the given namespace URI and local name, or null if no such attribute * exists. * @see https://dom.spec.whatwg.org/#concept-element-attributes-get-by-namespace */ getNamedItemNS: function (namespaceURI, localName) { if (!namespaceURI) { namespaceURI = null; } var i = 0; while (i < this.length) { var node = this[i]; if (node.localName === localName && node.namespaceURI === namespaceURI) { return node; } i++; } return null; }, }; NamedNodeMap.prototype[Symbol.iterator] = function () { var me = this; var index = 0; return { next: function () { if (index < me.length) { return { value: me[index++], done: false, }; } else { return { done: true, }; } }, return: function () { return { done: true, }; }, }; }; /** * The DOMImplementation interface provides a number of methods for performing operations that * are independent of any particular instance of the document object model. * * The DOMImplementation interface represents an object providing methods which are not * dependent on any particular document. * Such an object is returned by the `Document.implementation` property. * * **The individual methods describe the differences compared to the specs**. * * @class DOMImplementation * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation MDN * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core * (Initial) * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490 DOM Level 2 Core * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-102161490 DOM Level 3 Core * @see https://dom.spec.whatwg.org/#domimplementation DOM Living Standard * @constructs DOMImplementation */ function DOMImplementation() {} DOMImplementation.prototype = { /** * Test if the DOM implementation implements a specific feature and version, as specified in * {@link https://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMFeatures DOM Features}. * * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given * feature is supported. The different implementations fairly diverged in what kind of * features were reported. The latest version of the spec settled to force this method to * always return true, where the functionality was accurate and in use. * * @deprecated * It is deprecated and modern browsers return true in all cases. * @function DOMImplementation#hasFeature * @param {string} feature * The name of the feature to test. * @param {string} [version] * This is the version number of the feature to test. * @returns {boolean} * Always returns true. * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/hasFeature MDN * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-5CED94D7 DOM Level 1 Core * @see https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature DOM Living Standard * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-5CED94D7 DOM Level 3 Core */ hasFeature: function (feature, version) { return true; }, /** * Creates a DOM Document object of the specified type with its document element. Note that * based on the {@link DocumentType} * given to create the document, the implementation may instantiate specialized * {@link Document} objects that support additional features than the "Core", such as "HTML" * {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#DOM2HTML DOM Level 2 HTML}. * On the other hand, setting the {@link DocumentType} after the document was created makes * this very unlikely to happen. Alternatively, specialized {@link Document} creation methods, * such as createHTMLDocument * {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#DOM2HTML DOM Level 2 HTML}, * can be used to obtain specific types of {@link Document} objects. * * __It behaves slightly different from the description in the living standard__: * - There is no interface/class `XMLDocument`, it returns a `Document` * instance (with it's `type` set to `'xml'`). * - `encoding`, `mode`, `origin`, `url` fields are currently not declared. * * @function DOMImplementation.createDocument * @param {string | null} namespaceURI * The * {@link https://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-namespaceURI namespace URI} * of the document element to create or null. * @param {string | null} qualifiedName * The * {@link https://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-qualifiedname qualified name} * of the document element to be created or null. * @param {DocumentType | null} [doctype=null] * The type of document to be created or null. When doctype is not null, its * {@link Node#ownerDocument} attribute is set to the document being created. Default is * `null` * @returns {Document} * A new {@link Document} object with its document element. If the NamespaceURI, * qualifiedName, and doctype are null, the returned {@link Document} is empty with no * document element. * @throws {DOMException} * With code: * * - `INVALID_CHARACTER_ERR`: Raised if the specified qualified name is not an XML name * according to {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#XML XML 1.0}. * - `NAMESPACE_ERR`: Raised if the qualifiedName is malformed, if the qualifiedName has a * prefix and the namespaceURI is null, or if the qualifiedName is null and the namespaceURI * is different from null, or if the qualifiedName has a prefix that is "xml" and the * namespaceURI is different from "{@link http://www.w3.org/XML/1998/namespace}" * {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#Namespaces XML Namespaces}, * or if the DOM implementation does not support the "XML" feature but a non-null namespace * URI was provided, since namespaces were defined by XML. * - `WRONG_DOCUMENT_ERR`: Raised if doctype has already been used with a different document * or was created from a different implementation. * - `NOT_SUPPORTED_ERR`: May be raised if the implementation does not support the feature * "XML" and the language exposed through the Document does not support XML Namespaces (such * as {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#HTML40 HTML 4.01}). * @since DOM Level 2. * @see {@link #createHTMLDocument} * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument DOM Living Standard * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Level-2-Core-DOM-createDocument DOM * Level 3 Core * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM * Level 2 Core (initial) */ createDocument: function (namespaceURI, qualifiedName, doctype) { var contentType = MIME_TYPE.XML_APPLICATION; if (namespaceURI === NAMESPACE.HTML) { contentType = MIME_TYPE.XML_XHTML_APPLICATION; } else if (namespaceURI === NAMESPACE.SVG) { contentType = MIME_TYPE.XML_SVG_IMAGE; } var doc = new Document(PDC, { contentType: contentType }); doc.implementation = this; doc.childNodes = new NodeList(); doc.doctype = doctype || null; if (doctype) { doc.appendChild(doctype); } if (qualifiedName) { var root = doc.createElementNS(namespaceURI, qualifiedName); doc.appendChild(root); } return doc; }, /** * Creates an empty DocumentType node. Entity declarations and notations are not made * available. Entity reference expansions and default attribute additions do not occur. * * **This behavior is slightly different from the one in the specs**: * - `encoding`, `mode`, `origin`, `url` fields are currently not declared. * - `publicId` and `systemId` contain the raw data including any possible quotes, * so they can always be serialized back to the original value * - `internalSubset` contains the raw string between `[` and `]` if present, * but is not parsed or validated in any form. * * @function DOMImplementation#createDocumentType * @param {string} qualifiedName * The {@link https://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-qualifiedname qualified * name} of the document type to be created. * @param {string} [publicId] * The external subset public identifier. * @param {string} [systemId] * The external subset system identifier. * @param {string} [internalSubset] * the internal subset or an empty string if it is not present * @returns {DocumentType} * A new {@link DocumentType} node with {@link Node#ownerDocument} set to null. * @throws {DOMException} * With code: * * - `INVALID_CHARACTER_ERR`: Raised if the specified qualified name is not an XML name * according to {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#XML XML 1.0}. * - `NAMESPACE_ERR`: Raised if the qualifiedName is malformed. * - `NOT_SUPPORTED_ERR`: May be raised if the implementation does not support the feature * "XML" and the language exposed through the Document does not support XML Namespaces (such * as {@link https://www.w3.org/TR/DOM-Level-3-Core/references.html#HTML40 HTML 4.01}). * @since DOM Level 2. * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType * MDN * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living * Standard * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Level-3-Core-DOM-createDocType DOM * Level 3 Core * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM * Level 2 Core * @see https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md#050 * @see https://www.w3.org/TR/DOM-Level-2-Core/#core-ID-Core-DocType-internalSubset * @prettierignore */ createDocumentType: function (qualifiedName, publicId, systemId, internalSubset) { validateQualifiedName(qualifiedName); var node = new DocumentType(PDC); node.name = qualifiedName; node.nodeName = qualifiedName; node.publicId = publicId || ''; node.systemId = systemId || ''; node.internalSubset = internalSubset || ''; node.childNodes = new NodeList(); return node; }, /** * Returns an HTML document, that might already have a basic DOM structure. * * __It behaves slightly different from the description in the living standard__: * - If the first argument is `false` no initial nodes are added (steps 3-7 in the specs are * omitted) * - `encoding`, `mode`, `origin`, `url` fields are currently not declared. * * @param {string | false} [title] * A string containing the title to give the new HTML document. * @returns {Document} * The HTML document. * @since WHATWG Living Standard. * @see {@link #createDocument} * @see https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument * @see https://dom.spec.whatwg.org/#html-document */ createHTMLDocument: function (title) { var doc = new Document(PDC, { contentType: MIME_TYPE.HTML }); doc.implementation = this; doc.childNodes = new NodeList(); if (title !== false) { doc.doctype = this.createDocumentType('html'); doc.doctype.ownerDocument = doc; doc.appendChild(doc.doctype); var htmlNode = doc.createElement('html'); doc.appendChild(htmlNode); var headNode = doc.createElement('head'); htmlNode.appendChild(headNode); if (typeof title === 'string') { var titleNode = doc.createElement('title'); titleNode.appendChild(doc.createTextNode(title)); headNode.appendChild(titleNode); } htmlNode.appendChild(doc.createElement('body')); } return doc; }, }; /** * The DOM Node interface is an abstract base class upon which many other DOM API objects are * based, thus letting those object types to be used similarly and often interchangeably. As an * abstract class, there is no such thing as a plain Node object. All objects that implement * Node functionality are based on one of its subclasses. Most notable are Document, Element, * and DocumentFragment. * * In addition, every kind of DOM node is represented by an interface based on Node. These * include Attr, CharacterData (which Text, Comment, CDATASection and ProcessingInstruction are * all based on), and DocumentType. * * In some cases, a particular feature of the base Node interface may not apply to one of its * child interfaces; in that case, the inheriting node may return null or throw an exception, * depending on circumstances. For example, attempting to add children to a node type that * cannot have children will throw an exception. * * **This behavior is slightly different from the in the specs**: * - unimplemented interfaces: `EventTarget` * * @class * @abstract * @param {Symbol} symbol * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247 * @see https://dom.spec.whatwg.org/#node * @prettierignore */ function Node(symbol) { checkSymbol(symbol); } Node.prototype = { /** * The first child of this node. * * @type {Node | null} */ firstChild: null, /** * The last child of this node. * * @type {Node | null} */ lastChild: null, /** * The previous sibling of this node. * * @type {Node | null} */ previousSibling: null, /** * The next sibling of this node. * * @type {Node | null} */ nextSibling: null, /** * The parent node of this node. * * @type {Node | null} */ parentNode: null, /** * The parent element of this node. * * @type {Element | null} */ get parentElement() { return this.parentNode && this.parentNode.nodeType === this.ELEMENT_NODE ? this.parentNode : null; }, /** * The child nodes of this node. * * @type {NodeList} */ childNodes: null, /** * The document object associated with this node. * * @type {Document | null} */ ownerDocument: null, /** * The value of this node. * * @type {string | null} */ nodeValue: null, /** * The namespace URI of this node. * * @type {string | null} */ namespaceURI: null, /** * The prefix of the namespace for this node. * * @type {string | null} */ prefix: null, /** * The local part of the qualified name of this node. * * @type {string | null} */ localName: null, /** * The baseURI is currently always `about:blank`, * since that's what happens when you create a document from scratch. * * @type {'about:blank'} */ baseURI: 'about:blank', /** * Is true if this node is part of a document. * * @type {boolean} */ get isConnected() { var rootNode = this.getRootNode(); return rootNode && rootNode.nodeType === rootNode.DOCUMENT_NODE; }, /** * Checks whether `other` is an inclusive descendant of this node. * * @param {Node | null | undefined} other * The node to check. * @returns {boolean} * True if `other` is an inclusive descendant of this node; false otherwise. * @see https://dom.spec.whatwg.org/#dom-node-contains */ contains: function (other) { if (!other) return false; var parent = other; do { if (this === parent) return true; parent = other.parentNode; } while (parent); return false; }, /** * @typedef GetRootNodeOptions * @property {boolean} [composed=false] */ /** * Searches for the root node of this node. * * **This behavior is slightly different from the in the specs**: * - ignores `options.composed`, since `ShadowRoot`s are unsupported, always returns root. * * @param {GetRootNodeOptions} [options] * @returns {Node} * Root node. * @see https://dom.spec.whatwg.org/#dom-node-getrootnode * @see https://dom.spec.whatwg.org/#concept-shadow-including-root */ getRootNode: function (options) { var parent = this; do { if (!parent.parentNode) { return parent; } parent = parent.parentNode; } while (parent); }, /** * Checks whether the given node is equal to this node. * * @param {Node} [otherNode] * @see https://dom.spec.whatwg.org/#concept-node-equals */ isEqualNode: function (otherNode) { if (!otherNode) return false; if (this.nodeType !== otherNode.nodeType) return false; switch (this.nodeType) { case this.DOCUMENT_TYPE_NODE: if (this.name !== otherNode.name) return false; if (this.publicId !== otherNode.publicId) return false; if (this.systemId !== otherNode.systemId) return false; break; case this.ELEMENT_NODE: if (this.namespaceURI !== otherNode.namespaceURI) return false; if (this.prefix !== otherNode.prefix) return false; if (this.localName !== otherNode.localName) return false; if (this.attributes.length !== otherNode.attributes.length) return false; for (var i = 0; i < this.attributes.length; i++) { var attr = this.attributes.item(i); if (!attr.isEqualNode(otherNode.getAttributeNodeNS(attr.namespaceURI, attr.localName))) { return false; } } break; case this.ATTRIBUTE_NODE: if (this.namespaceURI !== otherNode.namespaceURI) return false; if (this.localName !== otherNode.localName) return false; if (this.value !== otherNode.value) return false; break; case this.PROCESSING_INSTRUCTION_NODE: if (this.target !== otherNode.target || this.data !== otherNode.data) { return false; } break; case this.TEXT_NODE: case this.COMMENT_NODE: if (this.data !== otherNode.data) return false; break; } if (this.childNodes.length !== otherNode.childNodes.length) { return false; } for (var i = 0; i < this.childNodes.length; i++) { if (!this.childNodes[i].isEqualNode(otherNode.childNodes[i])) { return false; } } return true; }, /** * Checks whether or not the given node is this node. * * @param {Node} [otherNode] */ isSameNode: function (otherNode) { return this === otherNode; }, /** * Inserts a node before a reference node as a child of this node. * * @param {Node} newChild * The new child node to be inserted. * @param {Node | null} refChild * The reference node before which newChild will be inserted. * @returns {Node} * The new child node successfully inserted. * @throws {DOMException} * Throws a DOMException if inserting the node would result in a DOM tree that is not * well-formed, or if `child` is provided but is not a child of `parent`. * See {@link _insertBefore} for more details. * @since Modified in DOM L2 */ insertBefore: function (newChild, refChild) { return _insertBefore(this, newChild, refChild); }, /** * Replaces an old child node with a new child node within this node. * * @param {Node} newChild * The new node that is to replace the old node. * If it already exists in the DOM, it is removed from its original position. * @param {Node} oldChild * The existing child node to be replaced. * @returns {Node} * Returns the replaced child node. * @throws {DOMException} * Throws a DOMException if replacing the node would result in a DOM tree that is not * well-formed, or if `oldChild` is not a child of `this`. * This can also occur if the pre-replacement validity assertion fails. * See {@link _insertBefore}, {@link Node.removeChild}, and * {@link assertPreReplacementValidityInDocument} for more details. * @see https://dom.spec.whatwg.org/#concept-node-replace */ replaceChild: function (newChild, oldChild) { _insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument); if (oldChild) { this.removeChild(oldChild); } }, /** * Removes an existing child node from this node. * * @param {Node} oldChild * The child node to be removed. * @returns {Node} * Returns the removed child node. * @throws {DOMException} * Throws a DOMException if `oldChild` is not a child of `this`. * See {@link _removeChild} for more details. */ removeChild: function (oldChild) { return _removeChild(this, oldChild); }, /** * Appends a child node to this node. * * @param {Node} newChild * The child node to be appended to this node. * If it already exists in the DOM, it is removed from its original position. * @returns {Node} * Returns the appended child node. * @throws {DOMException} * Throws a DOMException if appending the node would result in a DOM tree that is not * well-formed, or if `newChild` is not a valid Node. * See {@link insertBefore} for more details. */ appendChild: function (newChild) { return this.insertBefore(newChild, null); }, /** * Determines whether this node has any child nodes. * * @returns {boolean} * Returns true if this node has any child nodes, and false otherwise. */ hasChildNodes: function () { return this.firstChild != null; }, /** * Creates a copy of the calling node. * * @param {boolean} deep * If true, the contents of the node are recursively copied. * If false, only the node itself (and its attributes, if it is an element) are copied. * @returns {Node} * Returns the newly created copy of the node. * @throws {DOMException} * May throw a DOMException if operations within {@link Element#setAttributeNode} or * {@link Node#appendChild} (which are potentially invoked in this method) do not meet their * specific constraints. * @see {@link cloneNode} */ cloneNode: function (deep) { return cloneNode(this.ownerDocument || this, this, deep); }, /** * Puts the specified node and all of its subtree into a "normalized" form. In a normalized * subtree, no text nodes in the subtree are empty and there are no adjacent text nodes. * * Specifically, this method merges any adjacent text nodes (i.e., nodes for which `nodeType` * is `TEXT_NODE`) into a single node with the combined data. It also removes any empty text * nodes. * * This method operates recursively, so it also normalizes any and all descendent nodes within * the subtree. * * @throws {DOMException} * May throw a DOMException if operations within removeChild or appendData (which are * potentially invoked in this method) do not meet their specific constraints. * @since Modified in DOM Level 2 * @see {@link Node.removeChild} * @see {@link CharacterData.appendData} */ normalize: function () { var child = this.firstChild; while (child) { var next = child.nextSibling; if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) { this.removeChild(next); child.appendData(next.data); } else { child.normalize(); child = next; } } }, /** * Checks whether the DOM implementation implements a specific feature and its version. * * @deprecated * Since `DOMImplementation.hasFeature` is deprecated and always returns true. * @param {string} feature * The package name of the feature to test. This is the same name that can be passed to the * method `hasFeature` on `DOMImplementation`. * @param {string} version * This is the version number of the package name to test. * @returns {boolean} * Returns true in all cases in the current implementation. * @since Introduced in DOM Level 2 * @see {@link DOMImplementation.hasFeature} */ isSupported: function (feature, version) { return this.ownerDocument.implementation.hasFeature(feature, version); }, /** * Look up the prefix associated to the given namespace URI, starting from this node. * **The default namespace declarations are ignored by this method.** * See Namespace Prefix Lookup for details on the algorithm used by this method. * * **This behavior is different from the in the specs**: * - no node type specific handling * - uses the internal attribute _nsMap for resolving namespaces that is updated when changing attributes * * @param {string | null} namespaceURI * The namespace URI for which to find the associated prefix. * @returns {string | null} * The associated prefix, if found; otherwise, null. * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespacePrefix * @see https://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespacePrefixAlgo * @see https://dom.spec.whatwg.org/#dom-node-lookupprefix * @see https://github.com/xmldom/xmldom/issues/322 * @prettierignore */ lookupPrefix: function (namespaceURI) { var el = this; while (el) { var map = el._nsMap; //console.dir(map) if (map) { for (var n in map) { if (hasOwn(map, n) && map[n] === namespaceURI) { return n; } } } el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode; } return null; }, /** * This function is used to look up the namespace URI associated with the given prefix, * starting from this node. * * **This behavior is different from the in the specs**: * - no node type specific handling * - uses the internal attribute _nsMap for resolving namespaces that is updated when changing attributes * * @param {string | null} prefix * The prefix for which to find the associated namespace URI. * @returns {string | null} * The associated namespace URI, if found; otherwise, null. * @since DOM Level 3 * @see https://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI * @prettierignore */ lookupNamespaceURI: function (prefix) { var el = this; while (el) { var map = el._nsMap; //console.dir(map) if (map) { if (hasOwn(map, prefix)) { return map[prefix]; } } el = el.nodeType == ATTRIBUTE_NODE ? el.ownerDocument : el.parentNode; } return null; }, /** * Determines whether the given namespace URI is the default namespace. * * The function works by looking up the prefix associated with the given namespace URI. If no * prefix is found (i.e., the namespace URI is not registered in the namespace map of this * node or any of its ancestors), it returns `true`, implying the namespace URI is considered * the default. * * **This behavior is different from the in the specs**: * - no node type specific handling * - uses the internal attribute _nsMap for resolving namespaces that is updated when changing attributes * * @param {string | null} namespaceURI * The namespace URI to be checked. * @returns {boolean} * Returns true if the given namespace URI is the default namespace, false otherwise. * @since DOM Level 3 * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-isDefaultNamespace * @see https://dom.spec.whatwg.org/#dom-node-isdefaultnamespace * @prettierignore */ isDefaultNamespace: function (namespaceURI) { var prefix = this.lookupPrefix(namespaceURI); return prefix == null; }, /** * Compares the reference node with a node with regard to their position in the document and * according to the document order. * * @param {Node} other * The node to compare the reference node to. * @returns {number} * Returns how the node is positioned relatively to the reference node according to the * bitmask. 0 if reference node and given node are the same. * @since DOM Level 3 * @see https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-compare * @see https://dom.spec.whatwg.org/#dom-node-comparedocumentposition */ compareDocumentPosition: function (other) { if (this === other) return 0; var node1 = other; var node2 = this; var attr1 = null; var attr2 = null; if (node1 instanceof Attr) { attr1 = node1; node1 = attr1.ownerElement; } if (node2 instanceof Attr) { attr2 = node2; node2 = attr2.ownerElement; if (attr1 && node1 && node2 === node1) { for (var i = 0, attr; (attr = node2.attributes[i]); i++) { if (attr === attr1) return DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + DocumentPosition.DOCUMENT_POSITION_PRECEDING; if (attr === attr2) return DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + DocumentPosition.DOCUMENT_POSITION_FOLLOWING; } } } if (!node1 || !node2 || node2.ownerDocument !== node1.ownerDocument) { return ( DocumentPosition.DOCUMENT_POSITION_DISCONNECTED + DocumentPosition.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + (docGUID(node2.ownerDocument) > docGUID(node1.ownerDocument) ? DocumentPosition.DOCUMENT_POSITION_FOLLOWING : DocumentPosition.DOCUMENT_POSITION_PRECEDING) ); } var chain1 = parentChain(node1); var chain2 = parentChain(node2); if ((!attr1 && chain2.indexOf(node1) >= 0) || (attr2 && node1 === node2)) { return DocumentPosition.DOCUMENT_POSITION_CONTAINS + DocumentPosition.DOCUMENT_POSITION_PRECEDING; } if ((!attr2 && chain1.indexOf(node2) >= 0) || (attr1 && node1 === node2)) { return DocumentPosition.DOCUMENT_POSITION_CONTAINED_BY + DocumentPosition.DOCUMENT_POSITION_FOLLOWING; } var ca = commonAncestor(chain2, chain1); for (var n in ca.childNodes) { var child = ca.childNodes[n]; if (child === node2) return DocumentPosition.DOCUMENT_POSITION_FOLLOWING; if (child === node1) return DocumentPosition.DOCUMENT_POSITION_PRECEDING; if (chain2.indexOf(child) >= 0) return DocumentPosition.DOCUMENT_POSITION_FOLLOWING; if (chain1.indexOf(child) >= 0) return DocumentPosition.DOCUMENT_POSITION_PRECEDING; } return 0; }, }; /** * Encodes special XML characters to their corresponding entities. * * @param {string} c * The character to be encoded. * @returns {string} * The encoded character. * @private */ function _xmlEncoder(c) { return ( (c == '<' && '<') || (c == '>' && '>') || (c == '&' && '&') || (c == '"' && '"') || '&#' + c.charCodeAt() + ';' ); } copy(NodeType, Node); copy(NodeType, Node.prototype); copy(DocumentPosition, Node); copy(DocumentPosition, Node.prototype); /** * @param callback * Return true for continue,false for break. * @returns * boolean true: break visit; */ function _visitNode(node, callback) { if (callback(node)) { return true; } if ((node = node.firstChild)) { do { if (_visitNode(node, callback)) { return true; } } while ((node = node.nextSibling)); } } /** * @typedef DocumentOptions * @property {string} [contentType=MIME_TYPE.XML_APPLICATION] */ /** * The Document interface describes the common properties and methods for any kind of document. * * It should usually be created using `new DOMImplementation().createDocument(...)` * or `new DOMImplementation().createHTMLDocument(...)`. * * The constructor is considered a private API and offers to initially set the `contentType` * property via it's options parameter. * * @class * @param {Symbol} symbol * @param {DocumentOptions} [options] * @augments Node * @private * @see https://developer.mozilla.org/en-US/docs/Web/API/Document * @see https://dom.spec.whatwg.org/#interface-document */ function Document(symbol, options) { checkSymbol(symbol); var opt = options || {}; this.ownerDocument = this; /** * The mime type of the document is determined at creation time and can not be modified. * * @type {string} * @see https://dom.spec.whatwg.org/#concept-document-content-type * @see {@link DOMImplementation} * @see {@link MIME_TYPE} * @readonly */ this.contentType = opt.contentType || MIME_TYPE.XML_APPLICATION; /** * @type {'html' | 'xml'} * @see https://dom.spec.whatwg.org/#concept-document-type * @see {@link DOMImplementation} * @readonly */ this.type = isHTMLMimeType(this.contentType) ? 'html' : 'xml'; } /** * Updates the namespace mapping of an element when a new attribute is added. * * @param {Document} doc * The document that the element belongs to. * @param {Element} el * The element to which the attribute is being added. * @param {Attr} newAttr * The new attribute being added. * @private */ function _onAddAttribute(doc, el, newAttr) { doc && doc._inc++; var ns = newAttr.namespaceURI; if (ns === NAMESPACE.XMLNS) { //update namespace el._nsMap[newAttr.prefix ? newAttr.localName : ''] = newAttr.value; } } /** * Updates the namespace mapping of an element when an attribute is removed. * * @param {Document} doc * The document that the element belongs to. * @param {Element} el * The element from which the attribute is being removed. * @param {Attr} newAttr * The attribute being removed. * @param {boolean} remove * Indicates whether the attribute is to be removed. * @private */ function _onRemoveAttribute(doc, el, newAttr, remove) { doc && doc._inc++; var ns = newAttr.namespaceURI; if (ns === NAMESPACE.XMLNS) { //update namespace delete el._nsMap[newAttr.prefix ? newAttr.localName : '']; } } /** * Updates `parent.childNodes`, adjusting the indexed items and its `length`. * If `newChild` is provided and has no nextSibling, it will be appended. * Otherwise, it's assumed that an item has been removed or inserted, * and `parent.firstNode` and its `.nextSibling` to re-indexing all child nodes of `parent`. * * @param {Document} doc * The parent document of `el`. * @param {Node} parent * The parent node whose childNodes list needs to be updated. * @param {Node} [newChild] * The new child node to be appended. If not provided, the function assumes a node has been * removed. * @private */ function _onUpdateChild(doc, parent, newChild) { if (doc && doc._inc) { doc._inc++; var childNodes = parent.childNodes; // assumes nextSibling and previousSibling were already configured upfront if (newChild && !newChild.nextSibling) { // if an item has been appended, we only need to update the last index and the length childNodes[childNodes.length++] = newChild; } else { // otherwise we need to reindex all items, // which can take a while when processing nodes with a lot of children var child = parent.firstChild; var i = 0; while (child) { childNodes[i++] = child; child = child.nextSibling; } childNodes.length = i; delete childNodes[childNodes.length]; } } } /** * Removes the connections between `parentNode` and `child` * and any existing `child.previousSibling` or `child.nextSibling`. * * @param {Node} parentNode * The parent node from which the child node is to be removed. * @param {Node} child * The child node to be removed from the parentNode. * @returns {Node} * Returns the child node that was removed. * @throws {DOMException} * With code: * - {@link DOMException.NOT_FOUND_ERR} If the parentNode is not the parent of the child node. * @private * @see https://github.com/xmldom/xmldom/issues/135 * @see https://github.com/xmldom/xmldom/issues/145 */ function _removeChild(parentNode, child) { if (parentNode !== child.parentNode) { throw new DOMException(DOMException.NOT_FOUND_ERR, "child's parent is not parent"); } var oldPreviousSibling = child.previousSibling; var oldNextSibling = child.nextSibling; if (oldPreviousSibling) { oldPreviousSibling.nextSibling = oldNextSibling; } else { parentNode.firstChild = oldNextSibling; } if (oldNextSibling) { oldNextSibling.previousSibling = oldPreviousSibling; } else { parentNode.lastChild = oldPreviousSibling; } _onUpdateChild(parentNode.ownerDocument, parentNode); child.parentNode = null; child.previousSibling = null; child.nextSibling = null; return child; } /** * Returns `true` if `node` can be a parent for insertion. * * @param {Node} node * @returns {boolean} */ function hasValidParentNodeType(node) { return ( node && (node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.ELEMENT_NODE) ); } /** * Returns `true` if `node` can be inserted according to it's `nodeType`. * * @param {Node} node * @returns {boolean} */ function hasInsertableNodeType(node) { return ( node && (node.nodeType === Node.CDATA_SECTION_NODE || node.nodeType === Node.COMMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.DOCUMENT_TYPE_NODE || node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.PROCESSING_INSTRUCTION_NODE || node.nodeType === Node.TEXT_NODE) ); } /** * Returns true if `node` is a DOCTYPE node. * * @param {Node} node * @returns {boolean} */ function isDocTypeNode(node) { return node && node.nodeType === Node.DOCUMENT_TYPE_NODE; } /** * Returns true if the node is an element. * * @param {Node} node * @returns {boolean} */ function isElementNode(node) { return node && node.nodeType === Node.ELEMENT_NODE; } /** * Returns true if `node` is a text node. * * @param {Node} node * @returns {boolean} */ function isTextNode(node) { return node && node.nodeType === Node.TEXT_NODE; } /** * Check if en element node can be inserted before `child`, or at the end if child is falsy, * according to the presence and position of a doctype node on the same level. * * @param {Document} doc * The document node. * @param {Node} child * The node that would become the nextSibling if the element would be inserted. * @returns {boolean} * `true` if an element can be inserted before child. * @private */ function isElementInsertionPossible(doc, child) { var parentChildNodes = doc.childNodes || []; if (find(parentChildNodes, isElementNode) || isDocTypeNode(child)) { return false; } var docTypeNode = find(parentChildNodes, isDocTypeNode); return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child)); } /** * Check if en element node can be inserted before `child`, or at the end if child is falsy, * according to the presence and position of a doctype node on the same level. * * @param {Node} doc * The document node. * @param {Node} child * The node that would become the nextSibling if the element would be inserted. * @returns {boolean} * `true` if an element can be inserted before child. * @private */ function isElementReplacementPossible(doc, child) { var parentChildNodes = doc.childNodes || []; function hasElementChildThatIsNotChild(node) { return isElementNode(node) && node !== child; } if (find(parentChildNodes, hasElementChildThatIsNotChild)) { return false; } var docTypeNode = find(parentChildNodes, isDocTypeNode); return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child)); } /** * Asserts pre-insertion validity of a node into a parent before a child. * Throws errors for invalid node combinations that would result in an ill-formed DOM. * * @param {Node} parent * The parent node to insert `node` into. * @param {Node} node * The node to insert. * @param {Node | null} child * The node that should become the `nextSibling` of `node`. If null, no sibling is considered. * @throws {DOMException} * With code: * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `parent` is not a Document, * DocumentFragment, or Element node. * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a host-including inclusive * ancestor of `parent`. (Currently not implemented) * - {@link DOMException.NOT_FOUND_ERR} If `child` is non-null and its `parent` is not * `parent`. * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is not a DocumentFragment, * DocumentType, Element, or CharacterData node. * - {@link DOMException.HIERARCHY_REQUEST_ERR} If either `node` is a Text node and `parent` is * a document, or if `node` is a doctype and `parent` is not a document. * @private * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity * @see https://dom.spec.whatwg.org/#concept-node-replace */ function assertPreInsertionValidity1to5(parent, node, child) { // 1. If `parent` is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException. if (!hasValidParentNodeType(parent)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType); } // 2. If `node` is a host-including inclusive ancestor of `parent`, then throw a "HierarchyRequestError" DOMException. // not implemented! // 3. If `child` is non-null and its parent is not `parent`, then throw a "NotFoundError" DOMException. if (child && child.parentNode !== parent) { throw new DOMException(DOMException.NOT_FOUND_ERR, 'child not in parent'); } if ( // 4. If `node` is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException. !hasInsertableNodeType(node) || // 5. If either `node` is a Text node and `parent` is a document, // the sax parser currently adds top level text nodes, this will be fixed in 0.9.0 // || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE) // or `node` is a doctype and `parent` is not a document, then throw a "HierarchyRequestError" DOMException. (isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE) ) { throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, 'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType ); } } /** * Asserts pre-insertion validity of a node into a document before a child. * Throws errors for invalid node combinations that would result in an ill-formed DOM. * * @param {Document} parent * The parent node to insert `node` into. * @param {Node} node * The node to insert. * @param {Node | undefined} child * The node that should become the `nextSibling` of `node`. If undefined, no sibling is * considered. * @returns {Node} * @throws {DOMException} * With code: * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a DocumentFragment with more than * one element child or has a Text node child. * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a DocumentFragment with one * element child and either `parent` has an element child, `child` is a doctype, or `child` is * non-null and a doctype is following `child`. * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is an Element and `parent` has an * element child, `child` is a doctype, or `child` is non-null and a doctype is following * `child`. * - {@link DOMException.HIERARCHY_REQUEST_ERR} If `node` is a DocumentType and `parent` has a * doctype child, `child` is non-null and an element is preceding `child`, or `child` is null * and `parent` has an element child. * @private * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity * @see https://dom.spec.whatwg.org/#concept-node-replace */ function assertPreInsertionValidityInDocument(parent, node, child) { var parentChildNodes = parent.childNodes || []; var nodeChildNodes = node.childNodes || []; // DocumentFragment if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { var nodeChildElements = nodeChildNodes.filter(isElementNode); // If node has more than one element child or has a Text node child. if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment'); } // Otherwise, if `node` has one element child and either `parent` has an element child, // `child` is a doctype, or `child` is non-null and a doctype is following `child`. if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype'); } } // Element if (isElementNode(node)) { // `parent` has an element child, `child` is a doctype, // or `child` is non-null and a doctype is following `child`. if (!isElementInsertionPossible(parent, child)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype'); } } // DocumentType if (isDocTypeNode(node)) { // `parent` has a doctype child, if (find(parentChildNodes, isDocTypeNode)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed'); } var parentElementChild = find(parentChildNodes, isElementNode); // `child` is non-null and an element is preceding `child`, if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element'); } // or `child` is null and `parent` has an element child. if (!child && parentElementChild) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present'); } } } /** * @param {Document} parent * The parent node to insert `node` into. * @param {Node} node * The node to insert. * @param {Node | undefined} child * the node that should become the `nextSibling` of `node` * @returns {Node} * @throws {DOMException} * For several node combinations that would create a DOM that is not well-formed. * @throws {DOMException} * If `child` is provided but is not a child of `parent`. * @private * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity * @see https://dom.spec.whatwg.org/#concept-node-replace */ function assertPreReplacementValidityInDocument(parent, node, child) { var parentChildNodes = parent.childNodes || []; var nodeChildNodes = node.childNodes || []; // DocumentFragment if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { var nodeChildElements = nodeChildNodes.filter(isElementNode); // If `node` has more than one element child or has a Text node child. if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment'); } // Otherwise, if `node` has one element child and either `parent` has an element child that is not `child` or a doctype is following `child`. if (nodeChildElements.length === 1 && !isElementReplacementPossible(parent, child)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype'); } } // Element if (isElementNode(node)) { // `parent` has an element child that is not `child` or a doctype is following `child`. if (!isElementReplacementPossible(parent, child)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype'); } } // DocumentType if (isDocTypeNode(node)) { function hasDoctypeChildThatIsNotChild(node) { return isDocTypeNode(node) && node !== child; } // `parent` has a doctype child that is not `child`, if (find(parentChildNodes, hasDoctypeChildThatIsNotChild)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed'); } var parentElementChild = find(parentChildNodes, isElementNode); // or an element is preceding `child`. if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element'); } } } /** * Inserts a node into a parent node before a child node. * * @param {Node} parent * The parent node to insert the node into. * @param {Node} node * The node to insert into the parent. * @param {Node | null} child * The node that should become the next sibling of the node. * If null, the function inserts the node at the end of the children of the parent node. * @param {Function} [_inDocumentAssertion] * An optional function to check pre-insertion validity if parent is a document node. * Defaults to {@link assertPreInsertionValidityInDocument} * @returns {Node} * Returns the inserted node. * @throws {DOMException} * Throws a DOMException if inserting the node would result in a DOM tree that is not * well-formed. See {@link assertPreInsertionValidity1to5}, * {@link assertPreInsertionValidityInDocument}. * @throws {DOMException} * Throws a DOMException if child is provided but is not a child of the parent. See * {@link Node.removeChild} * @private * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity */ function _insertBefore(parent, node, child, _inDocumentAssertion) { // To ensure pre-insertion validity of a node into a parent before a child, run these steps: assertPreInsertionValidity1to5(parent, node, child); // If parent is a document, and any of the statements below, switched on the interface node implements, // are true, then throw a "HierarchyRequestError" DOMException. if (parent.nodeType === Node.DOCUMENT_NODE) { (_inDocumentAssertion || assertPreInsertionValidityInDocument)(parent, node, child); } var cp = node.parentNode; if (cp) { cp.removeChild(node); //remove and update } if (node.nodeType === DOCUMENT_FRAGMENT_NODE) { var newFirst = node.firstChild; if (newFirst == null) { return node; } var newLast = node.lastChild; } else { newFirst = newLast = node; } var pre = child ? child.previousSibling : parent.lastChild; newFirst.previousSibling = pre; newLast.nextSibling = child; if (pre) { pre.nextSibling = newFirst; } else { parent.firstChild = newFirst; } if (child == null) { parent.lastChild = newLast; } else { child.previousSibling = newLast; } do { newFirst.parentNode = parent; } while (newFirst !== newLast && (newFirst = newFirst.nextSibling)); _onUpdateChild(parent.ownerDocument || parent, parent, node); if (node.nodeType == DOCUMENT_FRAGMENT_NODE) { node.firstChild = node.lastChild = null; } return node; } Document.prototype = { /** * The implementation that created this document. * * @type DOMImplementation * @readonly */ implementation: null, nodeName: '#document', nodeType: DOCUMENT_NODE, /** * The DocumentType node of the document. * * @type DocumentType * @readonly */ doctype: null, documentElement: null, _inc: 1, insertBefore: function (newChild, refChild) { //raises if (newChild.nodeType === DOCUMENT_FRAGMENT_NODE) { var child = newChild.firstChild; while (child) { var next = child.nextSibling; this.insertBefore(child, refChild); child = next; } return newChild; } _insertBefore(this, newChild, refChild); newChild.ownerDocument = this; if (this.documentElement === null && newChild.nodeType === ELEMENT_NODE) { this.documentElement = newChild; } return newChild; }, removeChild: function (oldChild) { var removed = _removeChild(this, oldChild); if (removed === this.documentElement) { this.documentElement = null; } return removed; }, replaceChild: function (newChild, oldChild) { //raises _insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument); newChild.ownerDocument = this; if (oldChild) { this.removeChild(oldChild); } if (isElementNode(newChild)) { this.documentElement = newChild; } }, // Introduced in DOM Level 2: importNode: function (importedNode, deep) { return importNode(this, importedNode, deep); }, // Introduced in DOM Level 2: getElementById: function (id) { var rtv = null; _visitNode(this.documentElement, function (node) { if (node.nodeType == ELEMENT_NODE) { if (node.getAttribute('id') == id) { rtv = node; return true; } } }); return rtv; }, /** * Creates a new `Element` that is owned by this `Document`. * In HTML Documents `localName` is the lower cased `tagName`, * otherwise no transformation is being applied. * When `contentType` implies the HTML namespace, it will be set as `namespaceURI`. * * __This implementation differs from the specification:__ - The provided name is not checked * against the `Name` production, * so no related error will be thrown. * - There is no interface `HTMLElement`, it is always an `Element`. * - There is no support for a second argument to indicate using custom elements. * * @param {string} tagName * @returns {Element} * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement * @see https://dom.spec.whatwg.org/#dom-document-createelement * @see https://dom.spec.whatwg.org/#concept-create-element */ createElement: function (tagName) { var node = new Element(PDC); node.ownerDocument = this; if (this.type === 'html') { tagName = tagName.toLowerCase(); } if (hasDefaultHTMLNamespace(this.contentType)) { node.namespaceURI = NAMESPACE.HTML; } node.nodeName = tagName; node.tagName = tagName; node.localName = tagName; node.childNodes = new NodeList(); var attrs = (node.attributes = new NamedNodeMap()); attrs._ownerElement = node; return node; }, /** * @returns {DocumentFragment} */ createDocumentFragment: function () { var node = new DocumentFragment(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); return node; }, /** * @param {string} data * @returns {Text} */ createTextNode: function (data) { var node = new Text(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.appendData(data); return node; }, /** * @param {string} data * @returns {Comment} */ createComment: function (data) { var node = new Comment(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.appendData(data); return node; }, /** * @param {string} data * @returns {CDATASection} */ createCDATASection: function (data) { var node = new CDATASection(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.appendData(data); return node; }, /** * @param {string} target * @param {string} data * @returns {ProcessingInstruction} */ createProcessingInstruction: function (target, data) { var node = new ProcessingInstruction(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.nodeName = node.target = target; node.nodeValue = node.data = data; return node; }, /** * Creates an `Attr` node that is owned by this document. * In HTML Documents `localName` is the lower cased `name`, * otherwise no transformation is being applied. * * __This implementation differs from the specification:__ - The provided name is not checked * against the `Name` production, * so no related error will be thrown. * * @param {string} name * @returns {Attr} * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createAttribute * @see https://dom.spec.whatwg.org/#dom-document-createattribute */ createAttribute: function (name) { if (!g.QName_exact.test(name)) { throw new DOMException(DOMException.INVALID_CHARACTER_ERR, 'invalid character in name "' + name + '"'); } if (this.type === 'html') { name = name.toLowerCase(); } return this._createAttribute(name); }, _createAttribute: function (name) { var node = new Attr(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.name = name; node.nodeName = name; node.localName = name; node.specified = true; return node; }, /** * Creates an EntityReference object. * The current implementation does not fill the `childNodes` with those of the corresponding * `Entity` * * @deprecated * In DOM Level 4. * @param {string} name * The name of the entity to reference. No namespace well-formedness checks are performed. * @returns {EntityReference} * @throws {DOMException} * With code `INVALID_CHARACTER_ERR` when `name` is not valid. * @throws {DOMException} * with code `NOT_SUPPORTED_ERR` when the document is of type `html` * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-392B75AE */ createEntityReference: function (name) { if (!g.Name.test(name)) { throw new DOMException(DOMException.INVALID_CHARACTER_ERR, 'not a valid xml name "' + name + '"'); } if (this.type === 'html') { throw new DOMException('document is an html document', DOMExceptionName.NotSupportedError); } var node = new EntityReference(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.nodeName = name; return node; }, // Introduced in DOM Level 2: /** * @param {string} namespaceURI * @param {string} qualifiedName * @returns {Element} */ createElementNS: function (namespaceURI, qualifiedName) { var validated = validateAndExtract(namespaceURI, qualifiedName); var node = new Element(PDC); var attrs = (node.attributes = new NamedNodeMap()); node.childNodes = new NodeList(); node.ownerDocument = this; node.nodeName = qualifiedName; node.tagName = qualifiedName; node.namespaceURI = validated[0]; node.prefix = validated[1]; node.localName = validated[2]; attrs._ownerElement = node; return node; }, // Introduced in DOM Level 2: /** * @param {string} namespaceURI * @param {string} qualifiedName * @returns {Attr} */ createAttributeNS: function (namespaceURI, qualifiedName) { var validated = validateAndExtract(namespaceURI, qualifiedName); var node = new Attr(PDC); node.ownerDocument = this; node.childNodes = new NodeList(); node.nodeName = qualifiedName; node.name = qualifiedName; node.specified = true; node.namespaceURI = validated[0]; node.prefix = validated[1]; node.localName = validated[2]; return node; }, }; _extends(Document, Node); function Element(symbol) { checkSymbol(symbol); this._nsMap = Object.create(null); } Element.prototype = { nodeType: ELEMENT_NODE, /** * The attributes of this element. * * @type {NamedNodeMap | null} */ attributes: null, getQualifiedName: function () { return this.prefix ? this.prefix + ':' + this.localName : this.localName; }, _isInHTMLDocumentAndNamespace: function () { return this.ownerDocument.type === 'html' && this.namespaceURI === NAMESPACE.HTML; }, hasAttribute: function (name) { return !!this.getAttributeNode(name); }, /** * Returns element’s first attribute whose qualified name is `name`, and `null` * if there is no such attribute. * * @param {string} name * @returns {string | null} */ getAttribute: function (name) { var attr = this.getAttributeNode(name); return attr ? attr.value : null; }, getAttributeNode: function (name) { if (this._isInHTMLDocumentAndNamespace()) { name = name.toLowerCase(); } return this.attributes.getNamedItem(name); }, /** * Sets the value of element’s first attribute whose qualified name is qualifiedName to value. * * @param {string} name * @param {string} value */ setAttribute: function (name, value) { if (this._isInHTMLDocumentAndNamespace()) { name = name.toLowerCase(); } var attr = this.getAttributeNode(name); if (attr) { attr.value = attr.nodeValue = '' + value; } else { attr = this.ownerDocument._createAttribute(name); attr.value = attr.nodeValue = '' + value; this.setAttributeNode(attr); } }, removeAttribute: function (name) { var attr = this.getAttributeNode(name); attr && this.removeAttributeNode(attr); }, setAttributeNode: function (newAttr) { return this.attributes.setNamedItem(newAttr); }, setAttributeNodeNS: function (newAttr) { return this.attributes.setNamedItemNS(newAttr); }, removeAttributeNode: function (oldAttr) { //console.log(this == oldAttr.ownerElement) return this.attributes.removeNamedItem(oldAttr.nodeName); }, //get real attribute name,and remove it by removeAttributeNode removeAttributeNS: function (namespaceURI, localName) { var old = this.getAttributeNodeNS(namespaceURI, localName); old && this.removeAttributeNode(old); }, hasAttributeNS: function (namespaceURI, localName) { return this.getAttributeNodeNS(namespaceURI, localName) != null; }, /** * Returns element’s attribute whose namespace is `namespaceURI` and local name is * `localName`, * or `null` if there is no such attribute. * * @param {string} namespaceURI * @param {string} localName * @returns {string | null} */ getAttributeNS: function (namespaceURI, localName) { var attr = this.getAttributeNodeNS(namespaceURI, localName); return attr ? attr.value : null; }, /** * Sets the value of element’s attribute whose namespace is `namespaceURI` and local name is * `localName` to value. * * @param {string} namespaceURI * @param {string} qualifiedName * @param {string} value * @see https://dom.spec.whatwg.org/#dom-element-setattributens */ setAttributeNS: function (namespaceURI, qualifiedName, value) { var validated = validateAndExtract(namespaceURI, qualifiedName); var localName = validated[2]; var attr = this.getAttributeNodeNS(namespaceURI, localName); if (attr) { attr.value = attr.nodeValue = '' + value; } else { attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName); attr.value = attr.nodeValue = '' + value; this.setAttributeNode(attr); } }, getAttributeNodeNS: function (namespaceURI, localName) { return this.attributes.getNamedItemNS(namespaceURI, localName); }, /** * Returns a LiveNodeList of all child elements which have **all** of the given class name(s). * * Returns an empty list if `classNames` is an empty string or only contains HTML white space * characters. * * Warning: This returns a live LiveNodeList. * Changes in the DOM will reflect in the array as the changes occur. * If an element selected by this array no longer qualifies for the selector, * it will automatically be removed. Be aware of this for iteration purposes. * * @param {string} classNames * Is a string representing the class name(s) to match; multiple class names are separated by * (ASCII-)whitespace. * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByClassName * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName * @see https://dom.spec.whatwg.org/#concept-getelementsbyclassname */ getElementsByClassName: function (classNames) { var classNamesSet = toOrderedSet(classNames); return new LiveNodeList(this, function (base) { var ls = []; if (classNamesSet.length > 0) { _visitNode(base, function (node) { if (node !== base && node.nodeType === ELEMENT_NODE) { var nodeClassNames = node.getAttribute('class'); // can be null if the attribute does not exist if (nodeClassNames) { // before splitting and iterating just compare them for the most common case var matches = classNames === nodeClassNames; if (!matches) { var nodeClassNamesSet = toOrderedSet(nodeClassNames); matches = classNamesSet.every(arrayIncludes(nodeClassNamesSet)); } if (matches) { ls.push(node); } } } }); } return ls; }); }, /** * Returns a LiveNodeList of elements with the given qualifiedName. * Searching for all descendants can be done by passing `*` as `qualifiedName`. * * All descendants of the specified element are searched, but not the element itself. * The returned list is live, which means it updates itself with the DOM tree automatically. * Therefore, there is no need to call `Element.getElementsByTagName()` * with the same element and arguments repeatedly if the DOM changes in between calls. * * When called on an HTML element in an HTML document, * `getElementsByTagName` lower-cases the argument before searching for it. * This is undesirable when trying to match camel-cased SVG elements (such as * `<linearGradient>`) in an HTML document. * Instead, use `Element.getElementsByTagNameNS()`, * which preserves the capitalization of the tag name. * * `Element.getElementsByTagName` is similar to `Document.getElementsByTagName()`, * except that it only searches for elements that are descendants of the specified element. * * @param {string} qualifiedName * @returns {LiveNodeList} * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName * @see https://dom.spec.whatwg.org/#concept-getelementsbytagname */ getElementsByTagName: function (qualifiedName) { var isHTMLDocument = (this.nodeType === DOCUMENT_NODE ? this : this.ownerDocument).type === 'html'; var lowerQualifiedName = qualifiedName.toLowerCase(); return new LiveNodeList(this, function (base) { var ls = []; _visitNode(base, function (node) { if (node === base || node.nodeType !== ELEMENT_NODE) { return; } if (qualifiedName === '*') { ls.push(node); } else { var nodeQualifiedName = node.getQualifiedName(); var matchingQName = isHTMLDocument && node.namespaceURI === NAMESPACE.HTML ? lowerQualifiedName : qualifiedName; if (nodeQualifiedName === matchingQName) { ls.push(node); } } }); return ls; }); }, getElementsByTagNameNS: function (namespaceURI, localName) { return new LiveNodeList(this, function (base) { var ls = []; _visitNode(base, function (node) { if ( node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName) ) { ls.push(node); } }); return ls; }); }, }; Document.prototype.getElementsByClassName = Element.prototype.getElementsByClassName; Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName; Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS; _extends(Element, Node); function Attr(symbol) { checkSymbol(symbol); this.namespaceURI = null; this.prefix = null; this.ownerElement = null; } Attr.prototype.nodeType = ATTRIBUTE_NODE; _extends(Attr, Node); function CharacterData(symbol) { checkSymbol(symbol); } CharacterData.prototype = { data: '', substringData: function (offset, count) { return this.data.substring(offset, offset + count); }, appendData: function (text) { text = this.data + text; this.nodeValue = this.data = text; this.length = text.length; }, insertData: function (offset, text) { this.replaceData(offset, 0, text); }, deleteData: function (offset, count) { this.replaceData(offset, count, ''); }, replaceData: function (offset, count, text) { var start = this.data.substring(0, offset); var end = this.data.substring(offset + count); text = start + text + end; this.nodeValue = this.data = text; this.length = text.length; }, }; _extends(CharacterData, Node); function Text(symbol) { checkSymbol(symbol); } Text.prototype = { nodeName: '#text', nodeType: TEXT_NODE, splitText: function (offset) { var text = this.data; var newText = text.substring(offset); text = text.substring(0, offset); this.data = this.nodeValue = text; this.length = text.length; var newNode = this.ownerDocument.createTextNode(newText); if (this.parentNode) { this.parentNode.insertBefore(newNode, this.nextSibling); } return newNode; }, }; _extends(Text, CharacterData); function Comment(symbol) { checkSymbol(symbol); } Comment.prototype = { nodeName: '#comment', nodeType: COMMENT_NODE, }; _extends(Comment, CharacterData); function CDATASection(symbol) { checkSymbol(symbol); } CDATASection.prototype = { nodeName: '#cdata-section', nodeType: CDATA_SECTION_NODE, }; _extends(CDATASection, Text); function DocumentType(symbol) { checkSymbol(symbol); } DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE; _extends(DocumentType, Node); function Notation(symbol) { checkSymbol(symbol); } Notation.prototype.nodeType = NOTATION_NODE; _extends(Notation, Node); function Entity(symbol) { checkSymbol(symbol); } Entity.prototype.nodeType = ENTITY_NODE; _extends(Entity, Node); function EntityReference(symbol) { checkSymbol(symbol); } EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE; _extends(EntityReference, Node); function DocumentFragment(symbol) { checkSymbol(symbol); } DocumentFragment.prototype.nodeName = '#document-fragment'; DocumentFragment.prototype.nodeType = DOCUMENT_FRAGMENT_NODE; _extends(DocumentFragment, Node); function ProcessingInstruction(symbol) { checkSymbol(symbol); } ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE; _extends(ProcessingInstruction, CharacterData); function XMLSerializer() {} XMLSerializer.prototype.serializeToString = function (node, nodeFilter) { return nodeSerializeToString.call(node, nodeFilter); }; Node.prototype.toString = nodeSerializeToString; function nodeSerializeToString(nodeFilter) { var buf = []; var refNode = (this.nodeType === DOCUMENT_NODE && this.documentElement) || this; var prefix = refNode.prefix; var uri = refNode.namespaceURI; if (uri && prefix == null) { var prefix = refNode.lookupPrefix(uri); if (prefix == null) { var visibleNamespaces = [ { namespace: uri, prefix: null }, //{namespace:uri,prefix:''} ]; } } serializeToString(this, buf, nodeFilter, visibleNamespaces); return buf.join(''); } function needNamespaceDefine(node, isHTML, visibleNamespaces) { var prefix = node.prefix || ''; var uri = node.namespaceURI; // According to [Namespaces in XML 1.0](https://www.w3.org/TR/REC-xml-names/#ns-using) , // and more specifically https://www.w3.org/TR/REC-xml-names/#nsc-NoPrefixUndecl : // > In a namespace declaration for a prefix [...], the attribute value MUST NOT be empty. // in a similar manner [Namespaces in XML 1.1](https://www.w3.org/TR/xml-names11/#ns-using) // and more specifically https://www.w3.org/TR/xml-names11/#nsc-NSDeclared : // > [...] Furthermore, the attribute value [...] must not be an empty string. // so serializing empty namespace value like xmlns:ds="" would produce an invalid XML document. if (!uri) { return false; } if ((prefix === 'xml' && uri === NAMESPACE.XML) || uri === NAMESPACE.XMLNS) { return false; } var i = visibleNamespaces.length; while (i--) { var ns = visibleNamespaces[i]; // get namespace prefix if (ns.prefix === prefix) { return ns.namespace !== uri; } } return true; } /** * Literal whitespace other than space that appear in attribute values are serialized as * their entity references, so they will be preserved. * (In contrast to whitespace literals in the input which are normalized to spaces). * * Well-formed constraint: No < in Attribute Values: * > The replacement text of any entity referred to directly or indirectly * > in an attribute value must not contain a <. * * @see https://www.w3.org/TR/xml11/#CleanAttrVals * @see https://www.w3.org/TR/xml11/#NT-AttValue * @see https://www.w3.org/TR/xml11/#AVNormalize * @see https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes * @prettierignore */ function addSerializedAttribute(buf, qualifiedName, value) { buf.push(' ', qualifiedName, '="', value.replace(/[<>&"\t\n\r]/g, _xmlEncoder), '"'); } function serializeToString(node, buf, nodeFilter, visibleNamespaces) { if (!visibleNamespaces) { visibleNamespaces = []; } var doc = node.nodeType === DOCUMENT_NODE ? node : node.ownerDocument; var isHTML = doc.type === 'html'; if (nodeFilter) { node = nodeFilter(node); if (node) { if (typeof node == 'string') { buf.push(node); return; } } else { return; } //buf.sort.apply(attrs, attributeSorter); } switch (node.nodeType) { case ELEMENT_NODE: var attrs = node.attributes; var len = attrs.length; var child = node.firstChild; var nodeName = node.tagName; var prefixedNodeName = nodeName; if (!isHTML && !node.prefix && node.namespaceURI) { var defaultNS; // lookup current default ns from `xmlns` attribute for (var ai = 0; ai < attrs.length; ai++) { if (attrs.item(ai).name === 'xmlns') { defaultNS = attrs.item(ai).value; break; } } if (!defaultNS) { // lookup current default ns in visibleNamespaces for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) { var namespace = visibleNamespaces[nsi]; if (namespace.prefix === '' && namespace.namespace === node.namespaceURI) { defaultNS = namespace.namespace; break; } } } if (defaultNS !== node.namespaceURI) { for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) { var namespace = visibleNamespaces[nsi]; if (namespace.namespace === node.namespaceURI) { if (namespace.prefix) { prefixedNodeName = namespace.prefix + ':' + nodeName; } break; } } } } buf.push('<', prefixedNodeName); for (var i = 0; i < len; i++) { // add namespaces for attributes var attr = attrs.item(i); if (attr.prefix == 'xmlns') { visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value, }); } else if (attr.nodeName == 'xmlns') { visibleNamespaces.push({ prefix: '', namespace: attr.value }); } } for (var i = 0; i < len; i++) { var attr = attrs.item(i); if (needNamespaceDefine(attr, isHTML, visibleNamespaces)) { var prefix = attr.prefix || ''; var uri = attr.namespaceURI; addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : 'xmlns', uri); visibleNamespaces.push({ prefix: prefix, namespace: uri }); } serializeToString(attr, buf, nodeFilter, visibleNamespaces); } // add namespace for current node if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) { var prefix = node.prefix || ''; var uri = node.namespaceURI; addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : 'xmlns', uri); visibleNamespaces.push({ prefix: prefix, namespace: uri }); } // in XML elements can be closed when they have no children var canCloseTag = !child; if (canCloseTag && (isHTML || node.namespaceURI === NAMESPACE.HTML)) { // in HTML (doc or ns) only void elements can be closed right away canCloseTag = isHTMLVoidElement(nodeName); } if (canCloseTag) { buf.push('/>'); } else { buf.push('>'); //if is cdata child node if (isHTML && isHTMLRawTextElement(nodeName)) { while (child) { if (child.data) { buf.push(child.data); } else { serializeToString(child, buf, nodeFilter, visibleNamespaces.slice()); } child = child.nextSibling; } } else { while (child) { serializeToString(child, buf, nodeFilter, visibleNamespaces.slice()); child = child.nextSibling; } } buf.push('</', prefixedNodeName, '>'); } // remove added visible namespaces //visibleNamespaces.length = startVisibleNamespaces; return; case DOCUMENT_NODE: case DOCUMENT_FRAGMENT_NODE: var child = node.firstChild; while (child) { serializeToString(child, buf, nodeFilter, visibleNamespaces.slice()); child = child.nextSibling; } return; case ATTRIBUTE_NODE: return addSerializedAttribute(buf, node.name, node.value); case TEXT_NODE: /* * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form, * except when used as markup delimiters, or within a comment, a processing instruction, * or a CDATA section. * If they are needed elsewhere, they must be escaped using either numeric character * references or the strings `&` and `<` respectively. * The right angle bracket (>) may be represented using the string " > ", * and must, for compatibility, be escaped using either `>`, * or a character reference when it appears in the string `]]>` in content, * when that string is not marking the end of a CDATA section. * * In the content of elements, character data is any string of characters which does not * contain the start-delimiter of any markup and does not include the CDATA-section-close * delimiter, `]]>`. * * @see https://www.w3.org/TR/xml/#NT-CharData * @see https://w3c.github.io/DOM-Parsing/#xml-serializing-a-text-node */ return buf.push(node.data.replace(/[<&>]/g, _xmlEncoder)); case CDATA_SECTION_NODE: return buf.push(g.CDATA_START, node.data, g.CDATA_END); case COMMENT_NODE: return buf.push(g.COMMENT_START, node.data, g.COMMENT_END); case DOCUMENT_TYPE_NODE: var pubid = node.publicId; var sysid = node.systemId; buf.push(g.DOCTYPE_DECL_START, ' ', node.name); if (pubid) { buf.push(' ', g.PUBLIC, ' ', pubid); if (sysid && sysid !== '.') { buf.push(' ', sysid); } } else if (sysid && sysid !== '.') { buf.push(' ', g.SYSTEM, ' ', sysid); } if (node.internalSubset) { buf.push(' [', node.internalSubset, ']'); } buf.push('>'); return; case PROCESSING_INSTRUCTION_NODE: return buf.push('<?', node.target, ' ', node.data, '?>'); case ENTITY_REFERENCE_NODE: return buf.push('&', node.nodeName, ';'); //case ENTITY_NODE: //case NOTATION_NODE: default: buf.push('??', node.nodeName); } } function importNode(doc, node, deep) { var node2; switch (node.nodeType) { case ELEMENT_NODE: node2 = node.cloneNode(false); node2.ownerDocument = doc; //var attrs = node2.attributes; //var len = attrs.length; //for(var i=0;i<len;i++){ //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep)); //} case DOCUMENT_FRAGMENT_NODE: break; case ATTRIBUTE_NODE: deep = true; break; //case ENTITY_REFERENCE_NODE: //case PROCESSING_INSTRUCTION_NODE: ////case TEXT_NODE: //case CDATA_SECTION_NODE: //case COMMENT_NODE: // deep = false; // break; //case DOCUMENT_NODE: //case DOCUMENT_TYPE_NODE: //cannot be imported. //case ENTITY_NODE: //case NOTATION_NODE: //can not hit in level3 //default:throw e; } if (!node2) { node2 = node.cloneNode(false); //false } node2.ownerDocument = doc; node2.parentNode = null; if (deep) { var child = node.firstChild; while (child) { node2.appendChild(importNode(doc, child, deep)); child = child.nextSibling; } } return node2; } /** * Creates a copy of a node from an existing one. * * @param {Document} doc * The Document object representing the document that the new node will belong to. * @param {Node} node * The node to clone. * @param {boolean} deep * If true, the contents of the node are recursively copied. * If false, only the node itself (and its attributes, if it is an element) are copied. * @returns {Node} * Returns the newly created copy of the node. * @throws {DOMException} * May throw a DOMException if operations within setAttributeNode or appendChild (which are * potentially invoked in this function) do not meet their specific constraints. */ function cloneNode(doc, node, deep) { var node2 = new node.constructor(PDC); for (var n in node) { if (hasOwn(node, n)) { var v = node[n]; if (typeof v != 'object') { if (v != node2[n]) { node2[n] = v; } } } } if (node.childNodes) { node2.childNodes = new NodeList(); } node2.ownerDocument = doc; switch (node2.nodeType) { case ELEMENT_NODE: var attrs = node.attributes; var attrs2 = (node2.attributes = new NamedNodeMap()); var len = attrs.length; attrs2._ownerElement = node2; for (var i = 0; i < len; i++) { node2.setAttributeNode(cloneNode(doc, attrs.item(i), true)); } break; case ATTRIBUTE_NODE: deep = true; } if (deep) { var child = node.firstChild; while (child) { node2.appendChild(cloneNode(doc, child, deep)); child = child.nextSibling; } } return node2; } function __set__(object, key, value) { object[key] = value; } //do dynamic try { if (Object.defineProperty) { Object.defineProperty(LiveNodeList.prototype, 'length', { get: function () { _updateLiveList(this); return this.$$length; }, }); Object.defineProperty(Node.prototype, 'textContent', { get: function () { return getTextContent(this); }, set: function (data) { switch (this.nodeType) { case ELEMENT_NODE: case DOCUMENT_FRAGMENT_NODE: while (this.firstChild) { this.removeChild(this.firstChild); } if (data || String(data)) { this.appendChild(this.ownerDocument.createTextNode(data)); } break; default: this.data = data; this.value = data; this.nodeValue = data; } }, }); function getTextContent(node) { switch (node.nodeType) { case ELEMENT_NODE: case DOCUMENT_FRAGMENT_NODE: var buf = []; node = node.firstChild; while (node) { if (node.nodeType !== 7 && node.nodeType !== 8) { buf.push(getTextContent(node)); } node = node.nextSibling; } return buf.join(''); default: return node.nodeValue; } } __set__ = function (object, key, value) { //console.log(value) object['$$' + key] = value; }; } } catch (e) { //ie8 } exports._updateLiveList = _updateLiveList; exports.Attr = Attr; exports.CDATASection = CDATASection; exports.CharacterData = CharacterData; exports.Comment = Comment; exports.Document = Document; exports.DocumentFragment = DocumentFragment; exports.DocumentType = DocumentType; exports.DOMImplementation = DOMImplementation; exports.Element = Element; exports.Entity = Entity; exports.EntityReference = EntityReference; exports.LiveNodeList = LiveNodeList; exports.NamedNodeMap = NamedNodeMap; exports.Node = Node; exports.NodeList = NodeList; exports.Notation = Notation; exports.Text = Text; exports.ProcessingInstruction = ProcessingInstruction; exports.XMLSerializer = XMLSerializer;