UNPKG

nxkit

Version:

This is a collection of tools, independent of any other libraries

538 lines (537 loc) 18 kB
"use strict"; /* ***** BEGIN LICENSE BLOCK ***** * Distributed under the BSD license: * * Copyright (c) 2015, xuewen.chu * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of xuewen.chu nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL xuewen.chu BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ***** END LICENSE BLOCK ***** */ Object.defineProperty(exports, "__esModule", { value: true }); const util_1 = require("../util"); const html_tag = /^(br|hr|input|frame|img|area|link|col|meta|area|base|basefont|param)$/i; const html = /^html$/i; var NODE_TYPE; (function (NODE_TYPE) { NODE_TYPE[NODE_TYPE["NODE_NODE"] = 1] = "NODE_NODE"; NODE_TYPE[NODE_TYPE["ELEMENT_NODE"] = 1] = "ELEMENT_NODE"; NODE_TYPE[NODE_TYPE["ATTRIBUTE_NODE"] = 2] = "ATTRIBUTE_NODE"; NODE_TYPE[NODE_TYPE["TEXT_NODE"] = 3] = "TEXT_NODE"; NODE_TYPE[NODE_TYPE["CDATA_SECTION_NODE"] = 4] = "CDATA_SECTION_NODE"; NODE_TYPE[NODE_TYPE["ENTITY_REFERENCE_NODE"] = 5] = "ENTITY_REFERENCE_NODE"; NODE_TYPE[NODE_TYPE["ENTITY_NODE"] = 6] = "ENTITY_NODE"; NODE_TYPE[NODE_TYPE["PROCESSING_INSTRUCTION_NODE"] = 7] = "PROCESSING_INSTRUCTION_NODE"; NODE_TYPE[NODE_TYPE["COMMENT_NODE"] = 8] = "COMMENT_NODE"; NODE_TYPE[NODE_TYPE["DOCUMENT_NODE"] = 9] = "DOCUMENT_NODE"; NODE_TYPE[NODE_TYPE["DOCUMENT_TYPE_NODE"] = 10] = "DOCUMENT_TYPE_NODE"; NODE_TYPE[NODE_TYPE["DOCUMENT_FRAGMENT_NODE"] = 11] = "DOCUMENT_FRAGMENT_NODE"; NODE_TYPE[NODE_TYPE["NOTATION_NODE"] = 12] = "NOTATION_NODE"; })(NODE_TYPE = exports.NODE_TYPE || (exports.NODE_TYPE = {})); ; function xmlEncoder(c) { return c == '<' && '&lt;' || c == '&' && '&amp;' || c == '"' && '&quot;' || '&#' + c.charCodeAt(0) + ';'; } function findNSMap(self) { var e = self; while (e && e.nodeType !== NODE_TYPE.ELEMENT_NODE) { if (e.nodeType === NODE_TYPE.ATTRIBUTE_NODE) { e = e.ownerElement; } else { e = e.parentNode; } } return e ? (e.namespaceMap || {}) : {}; } function serializeToString(node, buf) { switch (node.nodeType) { case NODE_TYPE.ELEMENT_NODE: var e = node; var attrs = e.attributes; var len = attrs.length; var child = node.firstChild; var nodeName = e.tagName; buf.push('<', nodeName); for (var i = 0; i < len; i++) { serializeToString(attrs.item(i), buf); } if (child) { buf.push('>'); while (child) { serializeToString(child, buf); child = child.nextSibling; } buf.push('</', nodeName, '>'); } else { var doc = node.ownerDocument; var doctype = doc.doctype; if (doctype && html.test(doctype.name)) { if (html_tag.test(nodeName)) buf.push(' />'); else buf.push('></', nodeName, '>'); } else buf.push(' />'); } return; case NODE_TYPE.DOCUMENT_NODE: case NODE_TYPE.DOCUMENT_FRAGMENT_NODE: var child = node.firstChild; while (child) { serializeToString(child, buf); child = child.nextSibling; } return; case NODE_TYPE.ATTRIBUTE_NODE: return buf.push(' ', node.name, '="', node.value.replace(/[<&"]/g, xmlEncoder), '"'); case NODE_TYPE.TEXT_NODE: return buf.push(node.data.replace(/[<&]/g, xmlEncoder)); //(?!#?[\w\d]+;) case NODE_TYPE.CDATA_SECTION_NODE: return buf.push('<![CDATA[', node.data, ']]>'); case NODE_TYPE.COMMENT_NODE: return buf.push("<!--", node.data, "-->"); case NODE_TYPE.DOCUMENT_TYPE_NODE: var pubid = node.publicId; var sysid = node.systemId; buf.push('<!DOCTYPE ', node.name); if (pubid) { buf.push(' PUBLIC "', pubid); if (sysid && sysid != '.') { buf.push('" "', sysid); } buf.push('">'); } else if (sysid && sysid != '.') { buf.push(' SYSTEM "', sysid, '">'); } else { var sub = node.internalSubset; if (sub) { buf.push(" [", sub, "]"); } buf.push(">"); } return; case NODE_TYPE.PROCESSING_INSTRUCTION_NODE: // readonly target: string; // readonly data: string; return buf.push("<?", node.nodeName, " ", node.data, "?>"); case NODE_TYPE.ENTITY_REFERENCE_NODE: return buf.push('&', node.nodeName, ';'); //case ENTITY_NODE: //case NOTATION_NODE: default: buf.push('??', node.nodeName || '?'); } } /* * attributes; * children; * * writeable properties: * nodeValue,Attr:value,CharacterData:data * prefix */ function update(self, e, attr) { var doc = self.ownerDocument || self; doc._inc++; if (attr) { if (attr.namespaceURI == 'http://www.w3.org/2000/xmlns/') { //update namespace } } else { //node //update childNodes var cs = e.childNodes; if (cs) { var child = e.firstChild; var i = 0; while (child) { cs[i++] = child; child = child.nextSibling; } cs._length = i; // TODO private visit } } } class Node { constructor(ownerDocument) { this.ownerDocument = ownerDocument; } // Modified in DOM Level 2: insertBefore(newChild, refChild) { util_1.default.assert(newChild.ownerDocument == this.ownerDocument, 'OwnerDocument mismatch'); util_1.default.assert(this.childNodes, 'Cannot add child node'); var parentNode = this; var cp = newChild.parentNode; if (cp) { cp.removeChild(newChild); //remove and update } var newLast, newFirst; if (newChild.nodeType === NODE_TYPE.DOCUMENT_FRAGMENT_NODE) { util_1.default.assert(newChild.firstChild, 'DOCUMENT_FRAGMENT_NODE cannot be empty'); newFirst = newChild.firstChild; newLast = newChild.lastChild; } else newFirst = newLast = newChild; if (!refChild) { var pre = parentNode.lastChild; parentNode.lastChild = newLast; } else { var pre = refChild.previousSibling; newLast.nextSibling = refChild; ; refChild.previousSibling = newLast; } if (pre) pre.nextSibling = newFirst; else parentNode.firstChild = newFirst; newFirst.previousSibling = pre; do newFirst.parentNode = parentNode; while (newFirst !== newLast && (newFirst = newFirst.nextSibling)); update(this, parentNode); } replaceChild(newChild, oldChild) { this.insertBefore(newChild, oldChild); if (oldChild) { this.removeChild(oldChild); } } removeAllChild() { var ns = this.childNodes; if (ns) { for (var i = 0, l = ns.length; i < l; i++) { ns.item(i).parentNode = undefined; delete ns[i]; } ns._length = 0; // TODO private visit this.firstChild = undefined; this.lastChild = undefined; update(this, this); } } removeChild(oldChild) { var parentNode = this; var previous; var child = this.firstChild; while (child) { var next = child.nextSibling; if (child === oldChild) { oldChild.parentNode = undefined; //remove it as a flag of not in document if (previous) previous.nextSibling = next; else parentNode.firstChild = next; if (next) next.previousSibling = previous; else parentNode.lastChild = previous; update(this, parentNode); return child; } previous = child; child = next; } return null; } appendChild(newChild) { return this.insertBefore(newChild, null); } hasChildNodes() { return this.firstChild != null; } cloneNode(deep = false) { // TODO Unrealized return null; } // Modified in DOM Level 2: normalize() { var child = this.firstChild; while (child) { var next = child.nextSibling; if (next && next.nodeType == NODE_TYPE.TEXT_NODE && child.nodeType == NODE_TYPE.TEXT_NODE) { this.removeChild(next); child.appendData(next.data); } else { child.normalize(); child = next; } } } // Introduced in DOM Level 2: isSupported(feature, version) { // TODO Unrealized // return this.ownerDocument.implementation.hasFeature(feature, version); return false; } // Introduced in DOM Level 2: hasAttributes() { if (this.attributes) return this.attributes.length > 0; return false; } lookupPrefix(namespaceURI) { var map = findNSMap(this); if (namespaceURI in map) { return map[namespaceURI]; } return null; } // Introduced in DOM Level 3: isDefaultNamespace(namespaceURI) { var prefix = this.lookupPrefix(namespaceURI); return prefix == null; } // Introduced in DOM Level 3: lookupNamespaceURI(prefix) { var map = findNSMap(this); for (var n in map) { if (map[n] == prefix) return n; } return null; } toString() { var buf = []; serializeToString(this, buf); return buf.join(''); } } exports.Node = Node; /** * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177 * 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. */ class NodeList { constructor() { /** * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive. * @standard level1 */ this._length = 0; } get length() { return this._length; } /** * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null. * @standard level1 * @param index unsigned long * Index into the collection. * @return Node * The node at the indexth position in the NodeList, or null if that is not a valid index. */ item(index) { return this[index] || null; } } exports.NodeList = NodeList; class LiveNodeList extends NodeList { constructor(node, refresh) { super(); this._node = node; this._refresh = refresh; } _updateLiveNodeList() { var self = this; var inc = self._node.ownerDocument._inc; if (self._inc != inc) { var ls = self._refresh(self._node); var l = ls.length; self._length = l; for (var i = 0; i < l; i++) self[i] = ls[i]; self._inc = inc; } } get length() { this._updateLiveNodeList(); return this._length; } item(index) { this._updateLiveNodeList(); return this[index] || null; } } exports.LiveNodeList = LiveNodeList; class CharacterData extends Node { constructor() { super(...arguments); this.data = ''; this.length = 0; } get nodeValue() { return this.data; } substringData(offset, count) { return this.data.substring(offset, offset + count); } appendData(text) { text = this.data + text; this.data = text; this.length = text.length; } insertData(offset, text) { this.replaceData(offset, 0, text); } deleteData(offset, count) { this.replaceData(offset, count, ''); } replaceData(offset, count, text) { var start = this.data.substring(0, offset); var end = this.data.substring(offset + count); text = start + text + end; this.data = text; this.length = text.length; } } class Attribute extends CharacterData { constructor(doc, name, value, specified = false) { super(doc); this.nodeType = NODE_TYPE.ATTRIBUTE_NODE; this.ownerElement = null; // this.ownerElement = ownerElement; this.name = name; this.value = value; this.specified = specified; } get nodeValue() { return this.value; } get nodeName() { return this.name; } } exports.Attribute = Attribute; class CDATASection extends CharacterData { constructor() { super(...arguments); this.nodeType = NODE_TYPE.CDATA_SECTION_NODE; this.nodeName = "#cdata-section"; } } exports.CDATASection = CDATASection; class Comment extends CharacterData { constructor() { super(...arguments); this.nodeType = NODE_TYPE.COMMENT_NODE; this.nodeName = "#comment"; } } exports.Comment = Comment; class DocumentFragment extends Node { constructor() { super(...arguments); this.nodeName = '#document-fragment'; this.childNodes = new NodeList(); } } exports.DocumentFragment = DocumentFragment; class DocumentType extends Node { // readonly attribute NamedNodeMap entities; // readonly attribute NamedNodeMap notations; /** * constructor function * @constructor * @param {String} qualifiedName * @param {String} publicId * @param {String} systemId */ constructor(doc, qualifiedName, publicId, systemId, internalSubset) { // raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR super(doc); this.nodeType = NODE_TYPE.DOCUMENT_TYPE_NODE; this.name = qualifiedName; this.nodeName = qualifiedName; this.publicId = publicId; this.systemId = systemId; this.internalSubset = internalSubset; } } exports.DocumentType = DocumentType; class Entity extends Node { constructor() { super(...arguments); this.nodeType = NODE_TYPE.ENTITY_NODE; this.nodeName = "#entity"; } } exports.Entity = Entity; class EntityReference extends Node { constructor(doc, nodeName, nodeValue) { super(doc); this.nodeType = NODE_TYPE.ENTITY_REFERENCE_NODE; this.nodeName = nodeName; this.nodeValue = nodeValue; } get text() { return this.nodeValue; } } exports.EntityReference = EntityReference; class Notation extends Node { constructor() { super(...arguments); this.nodeType = NODE_TYPE.NOTATION_NODE; this.nodeName = "#notation"; } } exports.Notation = Notation; class ProcessingInstruction extends Node { constructor(doc, name, data) { super(doc); this.nodeType = NODE_TYPE.PROCESSING_INSTRUCTION_NODE; this.name = name; this.data = data; } get nodeName() { return this.name; } } exports.ProcessingInstruction = ProcessingInstruction; class Text extends CharacterData { constructor() { super(...arguments); this.nodeName = "#text"; this.nodeType = NODE_TYPE.TEXT_NODE; } splitText(offset) { var text = this.data; var newText = text.substring(offset); text = text.substring(0, offset); this.data = text; this.length = text.length; var newNode = this.ownerDocument.createTextNode(newText); if (this.parentNode) { this.parentNode.insertBefore(newNode, this.nextSibling || null); } return newNode; } } exports.Text = Text;