update dependency after merge from master

This commit is contained in:
Slawomir Jaranowski
2022-11-13 08:58:21 +01:00
parent 2bd0acf716
commit 6091258250
5 changed files with 420 additions and 58 deletions

View File

@ -1,5 +1,6 @@
var conventions = require("./conventions");
var find = conventions.find;
var NAMESPACE = conventions.NAMESPACE;
/**
@ -158,14 +159,14 @@ NodeList.prototype = {
* The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
* @standard level1
*/
length:0,
length:0,
/**
* 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
* @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.
* The node at the indexth position in the NodeList, or null if that is not a valid index.
*/
item: function(index) {
return this[index] || null;
@ -175,7 +176,23 @@ NodeList.prototype = {
serializeToString(this[i],buf,isHTML,nodeFilter);
}
return buf.join('');
}
},
/**
* @private
* @param {function (Node):boolean} predicate
* @returns {Node[]}
*/
filter: function (predicate) {
return Array.prototype.filter.call(this, predicate);
},
/**
* @private
* @param {Node} item
* @returns {number}
*/
indexOf: function (item) {
return Array.prototype.indexOf.call(this, item);
},
};
function LiveNodeList(node,refresh){
@ -209,7 +226,7 @@ _extends(LiveNodeList,NodeList);
* 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
* used for attributes or DocumentType entities
*/
function NamedNodeMap() {
};
@ -253,7 +270,7 @@ function _removeNamedNode(el,list,attr){
}
}
}else{
throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
throw new DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
}
}
NamedNodeMap.prototype = {
@ -298,10 +315,10 @@ NamedNodeMap.prototype = {
var attr = this.getNamedItem(key);
_removeNamedNode(this._ownerElement,this,attr);
return attr;
},// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
//for level2
removeNamedItemNS:function(namespaceURI,localName){
var attr = this.getNamedItemNS(namespaceURI,localName);
@ -447,11 +464,11 @@ Node.prototype = {
prefix : null,
localName : null,
// Modified in DOM Level 2:
insertBefore:function(newChild, refChild){//raises
insertBefore:function(newChild, refChild){//raises
return _insertBefore(this,newChild,refChild);
},
replaceChild:function(newChild, oldChild){//raises
this.insertBefore(newChild,oldChild);
replaceChild:function(newChild, oldChild){//raises
_insertBefore(this, newChild,oldChild, assertPreReplacementValidityInDocument);
if(oldChild){
this.removeChild(oldChild);
}
@ -573,6 +590,7 @@ function _visitNode(node,callback){
function Document(){
this.ownerDocument = this;
}
function _onAddAttribute(doc,el,newAttr){
@ -656,48 +674,313 @@ function _removeChild (parentNode, child) {
_onUpdateChild(parentNode.ownerDocument, parentNode);
return child;
}
/**
* preformance key(refChild == null)
* Returns `true` if `node` can be a parent for insertion.
* @param {Node} node
* @returns {boolean}
*/
function _insertBefore(parentNode,newChild,nextChild){
var cp = newChild.parentNode;
if(cp){
cp.removeChild(newChild);//remove and update
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 &&
(isElementNode(node) ||
isTextNode(node) ||
isDocTypeNode(node) ||
node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ||
node.nodeType === Node.COMMENT_NODE ||
node.nodeType === Node.PROCESSING_INSTRUCTION_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
* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
*/
function isElementInsertionPossible(doc, child) {
var parentChildNodes = doc.childNodes || [];
if (find(parentChildNodes, isElementNode) || isDocTypeNode(child)) {
return false;
}
if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
var newFirst = newChild.firstChild;
if (newFirst == null) {
return newChild;
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
* https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
*/
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));
}
/**
* @private
* Steps 1-5 of the checks before inserting and before replacing a child are the same.
*
* @param {Node} parent the parent node to insert `node` into
* @param {Node} node the node to insert
* @param {Node=} 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`.
* @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(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(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(
HIERARCHY_REQUEST_ERR,
'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
);
}
}
/**
* @private
* Step 6 of the checks before inserting and before replacing a child are different.
*
* @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`.
* @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(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(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
}
var newLast = newChild.lastChild;
}else{
newFirst = newLast = newChild;
}
var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
// 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(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(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(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(HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
}
}
}
/**
* @private
* Step 6 of the checks before inserting and before replacing a child are different.
*
* @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`.
* @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(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(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(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(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(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
}
}
}
/**
* @private
* @param {Node} parent the parent node to insert `node` into
* @param {Node} node the node to insert
* @param {Node=} 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`.
* @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 = nextChild;
newLast.nextSibling = child;
if(pre){
pre.nextSibling = newFirst;
}else{
parentNode.firstChild = newFirst;
parent.firstChild = newFirst;
}
if(nextChild == null){
parentNode.lastChild = newLast;
if(child == null){
parent.lastChild = newLast;
}else{
nextChild.previousSibling = newLast;
child.previousSibling = newLast;
}
do{
newFirst.parentNode = parentNode;
newFirst.parentNode = parent;
}while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
_onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
//console.log(parentNode.lastChild.nextSibling == null)
if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
newChild.firstChild = newChild.lastChild = null;
_onUpdateChild(parent.ownerDocument||parent, parent);
//console.log(parent.lastChild.nextSibling == null)
if (node.nodeType == DOCUMENT_FRAGMENT_NODE) {
node.firstChild = node.lastChild = null;
}
return newChild;
return node;
}
/**
@ -752,11 +1035,13 @@ Document.prototype = {
}
return newChild;
}
if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
_insertBefore(this, newChild, refChild);
newChild.ownerDocument = this;
if (this.documentElement === null && newChild.nodeType === ELEMENT_NODE) {
this.documentElement = newChild;
}
return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
return newChild;
},
removeChild : function(oldChild){
if(this.documentElement == oldChild){
@ -764,6 +1049,17 @@ Document.prototype = {
}
return _removeChild(this,oldChild);
},
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);
@ -950,7 +1246,7 @@ Element.prototype = {
var attr = this.getAttributeNode(name)
attr && this.removeAttributeNode(attr);
},
//four real opeartion method
appendChild:function(newChild){
if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
@ -974,7 +1270,7 @@ Element.prototype = {
var old = this.getAttributeNodeNS(namespaceURI, localName);
old && this.removeAttributeNode(old);
},
hasAttributeNS : function(namespaceURI, localName){
return this.getAttributeNodeNS(namespaceURI, localName)!=null;
},
@ -990,7 +1286,7 @@ Element.prototype = {
getAttributeNodeNS : function(namespaceURI, localName){
return this.attributes.getNamedItemNS(namespaceURI, localName);
},
getElementsByTagName : function(tagName){
return new LiveNodeList(this,function(base){
var ls = [];
@ -1011,7 +1307,7 @@ Element.prototype = {
}
});
return ls;
});
}
};
@ -1040,7 +1336,7 @@ CharacterData.prototype = {
},
insertData: function(offset,text) {
this.replaceData(offset,0,text);
},
appendChild:function(newChild){
throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
@ -1134,7 +1430,7 @@ function nodeSerializeToString(isHtml,nodeFilter){
var refNode = this.nodeType == 9 && this.documentElement || this;
var prefix = refNode.prefix;
var uri = refNode.namespaceURI;
if(uri && prefix == null){
//console.log(prefix)
var prefix = refNode.lookupPrefix(uri);
@ -1167,8 +1463,8 @@ function needNamespaceDefine(node, isHTML, visibleNamespaces) {
if (prefix === "xml" && uri === NAMESPACE.XML || uri === NAMESPACE.XMLNS) {
return false;
}
var i = visibleNamespaces.length
var i = visibleNamespaces.length
while (i--) {
var ns = visibleNamespaces[i];
// get namespace prefix
@ -1219,7 +1515,7 @@ function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
var len = attrs.length;
var child = node.firstChild;
var nodeName = node.tagName;
isHTML = NAMESPACE.isHTML(node.namespaceURI) || isHTML
var prefixedNodeName = nodeName
@ -1278,14 +1574,14 @@ function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
}
// add namespace for current node
// 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 });
}
if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
buf.push('>');
//if is cdata child node
@ -1500,7 +1796,7 @@ try{
}
}
})
function getTextContent(node){
switch(node.nodeType){
case ELEMENT_NODE: