diff options
author | Moonchild <moonchild@palemoon.org> | 2021-02-25 01:03:57 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2021-02-25 01:03:57 +0000 |
commit | ceadffab6b357723981a429e11222daf6cd6dcfb (patch) | |
tree | 5603053048d6a460f79b22bdf165fb74d32d39b0 /testing/web-platform/tests/dom/common.js | |
parent | 14fb2f966e9b54598c451e3cb35b4aa0480dafed (diff) | |
parent | ad5a13bd501e379517da1a944c104a11d951a3f5 (diff) | |
download | UXP-RC_20210225.tar UXP-RC_20210225.tar.gz UXP-RC_20210225.tar.lz UXP-RC_20210225.tar.xz UXP-RC_20210225.zip |
Merge branch 'master' into releaseRC_20210225
Diffstat (limited to 'testing/web-platform/tests/dom/common.js')
-rw-r--r-- | testing/web-platform/tests/dom/common.js | 1083 |
1 files changed, 0 insertions, 1083 deletions
diff --git a/testing/web-platform/tests/dom/common.js b/testing/web-platform/tests/dom/common.js deleted file mode 100644 index 70367b2ef..000000000 --- a/testing/web-platform/tests/dom/common.js +++ /dev/null @@ -1,1083 +0,0 @@ -"use strict"; -// Written by Aryeh Gregor <ayg@aryeh.name> - -// TODO: iframes, contenteditable/designMode - -// Everything is done in functions in this test harness, so we have to declare -// all the variables before use to make sure they can be reused. -var testDiv, paras, detachedDiv, detachedPara1, detachedPara2, - foreignDoc, foreignPara1, foreignPara2, xmlDoc, xmlElement, - detachedXmlElement, detachedTextNode, foreignTextNode, - detachedForeignTextNode, xmlTextNode, detachedXmlTextNode, - processingInstruction, detachedProcessingInstruction, comment, - detachedComment, foreignComment, detachedForeignComment, xmlComment, - detachedXmlComment, docfrag, foreignDocfrag, xmlDocfrag, doctype, - foreignDoctype, xmlDoctype; -var testRangesShort, testRanges, testPoints, testNodesShort, testNodes; - -function setupRangeTests() { - testDiv = document.querySelector("#test"); - if (testDiv) { - testDiv.parentNode.removeChild(testDiv); - } - testDiv = document.createElement("div"); - testDiv.id = "test"; - document.body.insertBefore(testDiv, document.body.firstChild); - - paras = []; - paras.push(document.createElement("p")); - paras[0].setAttribute("id", "a"); - // Test some diacritics, to make sure browsers are using code units here - // and not something like grapheme clusters. - paras[0].textContent = "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\n"; - testDiv.appendChild(paras[0]); - - paras.push(document.createElement("p")); - paras[1].setAttribute("id", "b"); - paras[1].setAttribute("style", "display:none"); - paras[1].textContent = "Ijklmnop\n"; - testDiv.appendChild(paras[1]); - - paras.push(document.createElement("p")); - paras[2].setAttribute("id", "c"); - paras[2].textContent = "Qrstuvwx"; - testDiv.appendChild(paras[2]); - - paras.push(document.createElement("p")); - paras[3].setAttribute("id", "d"); - paras[3].setAttribute("style", "display:none"); - paras[3].textContent = "Yzabcdef"; - testDiv.appendChild(paras[3]); - - paras.push(document.createElement("p")); - paras[4].setAttribute("id", "e"); - paras[4].setAttribute("style", "display:none"); - paras[4].textContent = "Ghijklmn"; - testDiv.appendChild(paras[4]); - - detachedDiv = document.createElement("div"); - detachedPara1 = document.createElement("p"); - detachedPara1.appendChild(document.createTextNode("Opqrstuv")); - detachedPara2 = document.createElement("p"); - detachedPara2.appendChild(document.createTextNode("Wxyzabcd")); - detachedDiv.appendChild(detachedPara1); - detachedDiv.appendChild(detachedPara2); - - // Opera doesn't automatically create a doctype for a new HTML document, - // contrary to spec. It also doesn't let you add doctypes to documents - // after the fact through any means I've tried. So foreignDoc in Opera - // will have no doctype, foreignDoctype will be null, and Opera will fail - // some tests somewhat mysteriously as a result. - foreignDoc = document.implementation.createHTMLDocument(""); - foreignPara1 = foreignDoc.createElement("p"); - foreignPara1.appendChild(foreignDoc.createTextNode("Efghijkl")); - foreignPara2 = foreignDoc.createElement("p"); - foreignPara2.appendChild(foreignDoc.createTextNode("Mnopqrst")); - foreignDoc.body.appendChild(foreignPara1); - foreignDoc.body.appendChild(foreignPara2); - - // Now we get to do really silly stuff, which nobody in the universe is - // ever going to actually do, but the spec defines behavior, so too bad. - // Testing is fun! - xmlDoctype = document.implementation.createDocumentType("qorflesnorf", "abcde", "x\"'y"); - xmlDoc = document.implementation.createDocument(null, null, xmlDoctype); - detachedXmlElement = xmlDoc.createElement("everyone-hates-hyphenated-element-names"); - detachedTextNode = document.createTextNode("Uvwxyzab"); - detachedForeignTextNode = foreignDoc.createTextNode("Cdefghij"); - detachedXmlTextNode = xmlDoc.createTextNode("Klmnopqr"); - // PIs only exist in XML documents, so don't bother with document or - // foreignDoc. - detachedProcessingInstruction = xmlDoc.createProcessingInstruction("whippoorwill", "chirp chirp chirp"); - detachedComment = document.createComment("Stuvwxyz"); - // Hurrah, we finally got to "z" at the end! - detachedForeignComment = foreignDoc.createComment("אריה יהודה"); - detachedXmlComment = xmlDoc.createComment("בן חיים אליעזר"); - - // We should also test with document fragments that actually contain stuff - // . . . but, maybe later. - docfrag = document.createDocumentFragment(); - foreignDocfrag = foreignDoc.createDocumentFragment(); - xmlDocfrag = xmlDoc.createDocumentFragment(); - - xmlElement = xmlDoc.createElement("igiveuponcreativenames"); - xmlTextNode = xmlDoc.createTextNode("do re mi fa so la ti"); - xmlElement.appendChild(xmlTextNode); - processingInstruction = xmlDoc.createProcessingInstruction("somePI", 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?'); - xmlDoc.appendChild(xmlElement); - xmlDoc.appendChild(processingInstruction); - xmlComment = xmlDoc.createComment("I maliciously created a comment that will break incautious XML serializers, but Firefox threw an exception, so all I got was this lousy T-shirt"); - xmlDoc.appendChild(xmlComment); - - comment = document.createComment("Alphabet soup?"); - testDiv.appendChild(comment); - - foreignComment = foreignDoc.createComment('"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.'); - foreignDoc.appendChild(foreignComment); - foreignTextNode = foreignDoc.createTextNode("I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now."); - foreignDoc.body.appendChild(foreignTextNode); - - doctype = document.doctype; - foreignDoctype = foreignDoc.doctype; - - testRangesShort = [ - // Various ranges within the text node children of different - // paragraphs. All should be valid. - "[paras[0].firstChild, 0, paras[0].firstChild, 0]", - "[paras[0].firstChild, 0, paras[0].firstChild, 1]", - "[paras[0].firstChild, 2, paras[0].firstChild, 8]", - "[paras[0].firstChild, 2, paras[0].firstChild, 9]", - "[paras[1].firstChild, 0, paras[1].firstChild, 0]", - "[paras[1].firstChild, 2, paras[1].firstChild, 9]", - "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 0]", - "[detachedPara1.firstChild, 2, detachedPara1.firstChild, 8]", - "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 0]", - "[foreignPara1.firstChild, 2, foreignPara1.firstChild, 8]", - // Now try testing some elements, not just text nodes. - "[document.documentElement, 0, document.documentElement, 1]", - "[document.documentElement, 0, document.documentElement, 2]", - "[document.documentElement, 1, document.documentElement, 2]", - "[document.head, 1, document.head, 1]", - "[document.body, 4, document.body, 5]", - "[foreignDoc.documentElement, 0, foreignDoc.documentElement, 1]", - "[paras[0], 0, paras[0], 1]", - "[detachedPara1, 0, detachedPara1, 1]", - // Now try some ranges that span elements. - "[paras[0].firstChild, 0, paras[1].firstChild, 0]", - "[paras[0].firstChild, 0, paras[1].firstChild, 8]", - "[paras[0].firstChild, 3, paras[3], 1]", - // How about something that spans a node and its descendant? - "[paras[0], 0, paras[0].firstChild, 7]", - "[testDiv, 2, paras[4], 1]", - // Then a few more interesting things just for good measure. - "[document, 0, document, 1]", - "[document, 0, document, 2]", - "[comment, 2, comment, 3]", - "[testDiv, 0, comment, 5]", - "[foreignDoc, 1, foreignComment, 2]", - "[foreignDoc.body, 0, foreignTextNode, 36]", - "[xmlDoc, 1, xmlComment, 0]", - "[detachedTextNode, 0, detachedTextNode, 8]", - "[detachedForeignTextNode, 0, detachedForeignTextNode, 8]", - "[detachedXmlTextNode, 0, detachedXmlTextNode, 8]", - "[detachedComment, 3, detachedComment, 4]", - "[detachedForeignComment, 0, detachedForeignComment, 1]", - "[detachedXmlComment, 2, detachedXmlComment, 6]", - "[docfrag, 0, docfrag, 0]", - "[processingInstruction, 0, processingInstruction, 4]", - ]; - - testRanges = testRangesShort.concat([ - "[paras[1].firstChild, 0, paras[1].firstChild, 1]", - "[paras[1].firstChild, 2, paras[1].firstChild, 8]", - "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 1]", - "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 1]", - "[foreignDoc.head, 1, foreignDoc.head, 1]", - "[foreignDoc.body, 0, foreignDoc.body, 0]", - "[paras[0], 0, paras[0], 0]", - "[detachedPara1, 0, detachedPara1, 0]", - "[testDiv, 1, paras[2].firstChild, 5]", - "[document.documentElement, 1, document.body, 0]", - "[foreignDoc.documentElement, 1, foreignDoc.body, 0]", - "[document, 1, document, 2]", - "[paras[2].firstChild, 4, comment, 2]", - "[paras[3], 1, comment, 8]", - "[foreignDoc, 0, foreignDoc, 0]", - "[xmlDoc, 0, xmlDoc, 0]", - "[detachedForeignTextNode, 7, detachedForeignTextNode, 7]", - "[detachedXmlTextNode, 7, detachedXmlTextNode, 7]", - "[detachedComment, 5, detachedComment, 5]", - "[detachedForeignComment, 4, detachedForeignComment, 4]", - "[foreignDocfrag, 0, foreignDocfrag, 0]", - "[xmlDocfrag, 0, xmlDocfrag, 0]", - ]); - - testPoints = [ - // Various positions within the page, some invalid. Remember that - // paras[0] is visible, and paras[1] is display: none. - "[paras[0].firstChild, -1]", - "[paras[0].firstChild, 0]", - "[paras[0].firstChild, 1]", - "[paras[0].firstChild, 2]", - "[paras[0].firstChild, 8]", - "[paras[0].firstChild, 9]", - "[paras[0].firstChild, 10]", - "[paras[0].firstChild, 65535]", - "[paras[1].firstChild, -1]", - "[paras[1].firstChild, 0]", - "[paras[1].firstChild, 1]", - "[paras[1].firstChild, 2]", - "[paras[1].firstChild, 8]", - "[paras[1].firstChild, 9]", - "[paras[1].firstChild, 10]", - "[paras[1].firstChild, 65535]", - "[detachedPara1.firstChild, 0]", - "[detachedPara1.firstChild, 1]", - "[detachedPara1.firstChild, 8]", - "[detachedPara1.firstChild, 9]", - "[foreignPara1.firstChild, 0]", - "[foreignPara1.firstChild, 1]", - "[foreignPara1.firstChild, 8]", - "[foreignPara1.firstChild, 9]", - // Now try testing some elements, not just text nodes. - "[document.documentElement, -1]", - "[document.documentElement, 0]", - "[document.documentElement, 1]", - "[document.documentElement, 2]", - "[document.documentElement, 7]", - "[document.head, 1]", - "[document.body, 3]", - "[foreignDoc.documentElement, 0]", - "[foreignDoc.documentElement, 1]", - "[foreignDoc.head, 0]", - "[foreignDoc.body, 1]", - "[paras[0], 0]", - "[paras[0], 1]", - "[paras[0], 2]", - "[paras[1], 0]", - "[paras[1], 1]", - "[paras[1], 2]", - "[detachedPara1, 0]", - "[detachedPara1, 1]", - "[testDiv, 0]", - "[testDiv, 3]", - // Then a few more interesting things just for good measure. - "[document, -1]", - "[document, 0]", - "[document, 1]", - "[document, 2]", - "[document, 3]", - "[comment, -1]", - "[comment, 0]", - "[comment, 4]", - "[comment, 96]", - "[foreignDoc, 0]", - "[foreignDoc, 1]", - "[foreignComment, 2]", - "[foreignTextNode, 0]", - "[foreignTextNode, 36]", - "[xmlDoc, -1]", - "[xmlDoc, 0]", - "[xmlDoc, 1]", - "[xmlDoc, 5]", - "[xmlComment, 0]", - "[xmlComment, 4]", - "[processingInstruction, 0]", - "[processingInstruction, 5]", - "[processingInstruction, 9]", - "[detachedTextNode, 0]", - "[detachedTextNode, 8]", - "[detachedForeignTextNode, 0]", - "[detachedForeignTextNode, 8]", - "[detachedXmlTextNode, 0]", - "[detachedXmlTextNode, 8]", - "[detachedProcessingInstruction, 12]", - "[detachedComment, 3]", - "[detachedComment, 5]", - "[detachedForeignComment, 0]", - "[detachedForeignComment, 4]", - "[detachedXmlComment, 2]", - "[docfrag, 0]", - "[foreignDocfrag, 0]", - "[xmlDocfrag, 0]", - "[doctype, 0]", - "[doctype, -17]", - "[doctype, 1]", - "[foreignDoctype, 0]", - "[xmlDoctype, 0]", - ]; - - testNodesShort = [ - "paras[0]", - "paras[0].firstChild", - "paras[1].firstChild", - "foreignPara1", - "foreignPara1.firstChild", - "detachedPara1", - "detachedPara1.firstChild", - "document", - "detachedDiv", - "foreignDoc", - "foreignPara2", - "xmlDoc", - "xmlElement", - "detachedTextNode", - "foreignTextNode", - "processingInstruction", - "detachedProcessingInstruction", - "comment", - "detachedComment", - "docfrag", - "doctype", - "foreignDoctype", - ]; - - testNodes = testNodesShort.concat([ - "paras[1]", - "detachedPara2", - "detachedPara2.firstChild", - "testDiv", - "detachedXmlElement", - "detachedForeignTextNode", - "xmlTextNode", - "detachedXmlTextNode", - "xmlComment", - "foreignComment", - "detachedForeignComment", - "detachedXmlComment", - "foreignDocfrag", - "xmlDocfrag", - "xmlDoctype", - ]); -} -if ("setup" in window) { - setup(setupRangeTests); -} else { - // Presumably we're running from within an iframe or something - setupRangeTests(); -} - -/** - * The "length" of a node as defined by the Ranges section of DOM4. - */ -function nodeLength(node) { - // "The length of a node node depends on node: - // - // "DocumentType - // "0." - if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { - return 0; - } - // "Text - // "ProcessingInstruction - // "Comment - // "Its length attribute value." - // Browsers don't historically support the length attribute on - // ProcessingInstruction, so to avoid spurious failures, do - // node.data.length instead of node.length. - if (node.nodeType == Node.TEXT_NODE || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE || node.nodeType == Node.COMMENT_NODE) { - return node.data.length; - } - // "Any other node - // "Its number of children." - return node.childNodes.length; -} - -/** - * Returns the furthest ancestor of a Node as defined by the spec. - */ -function furthestAncestor(node) { - var root = node; - while (root.parentNode != null) { - root = root.parentNode; - } - return root; -} - -/** - * "The ancestor containers of a Node are the Node itself and all its - * ancestors." - * - * Is node1 an ancestor container of node2? - */ -function isAncestorContainer(node1, node2) { - return node1 == node2 || - (node2.compareDocumentPosition(node1) & Node.DOCUMENT_POSITION_CONTAINS); -} - -/** - * Returns the first Node that's after node in tree order, or null if node is - * the last Node. - */ -function nextNode(node) { - if (node.hasChildNodes()) { - return node.firstChild; - } - return nextNodeDescendants(node); -} - -/** - * Returns the last Node that's before node in tree order, or null if node is - * the first Node. - */ -function previousNode(node) { - if (node.previousSibling) { - node = node.previousSibling; - while (node.hasChildNodes()) { - node = node.lastChild; - } - return node; - } - return node.parentNode; -} - -/** - * Returns the next Node that's after node and all its descendants in tree - * order, or null if node is the last Node or an ancestor of it. - */ -function nextNodeDescendants(node) { - while (node && !node.nextSibling) { - node = node.parentNode; - } - if (!node) { - return null; - } - return node.nextSibling; -} - -/** - * Returns the ownerDocument of the Node, or the Node itself if it's a - * Document. - */ -function ownerDocument(node) { - return node.nodeType == Node.DOCUMENT_NODE - ? node - : node.ownerDocument; -} - -/** - * Returns true if ancestor is an ancestor of descendant, false otherwise. - */ -function isAncestor(ancestor, descendant) { - if (!ancestor || !descendant) { - return false; - } - while (descendant && descendant != ancestor) { - descendant = descendant.parentNode; - } - return descendant == ancestor; -} - -/** - * Returns true if ancestor is an inclusive ancestor of descendant, false - * otherwise. - */ -function isInclusiveAncestor(ancestor, descendant) { - return ancestor === descendant || isAncestor(ancestor, descendant); -} - -/** - * Returns true if descendant is a descendant of ancestor, false otherwise. - */ -function isDescendant(descendant, ancestor) { - return isAncestor(ancestor, descendant); -} - -/** - * Returns true if descendant is an inclusive descendant of ancestor, false - * otherwise. - */ -function isInclusiveDescendant(descendant, ancestor) { - return descendant === ancestor || isDescendant(descendant, ancestor); -} - -/** - * The position of two boundary points relative to one another, as defined by - * the spec. - */ -function getPosition(nodeA, offsetA, nodeB, offsetB) { - // "If node A is the same as node B, return equal if offset A equals offset - // B, before if offset A is less than offset B, and after if offset A is - // greater than offset B." - if (nodeA == nodeB) { - if (offsetA == offsetB) { - return "equal"; - } - if (offsetA < offsetB) { - return "before"; - } - if (offsetA > offsetB) { - return "after"; - } - } - - // "If node A is after node B in tree order, compute the position of (node - // B, offset B) relative to (node A, offset A). If it is before, return - // after. If it is after, return before." - if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_FOLLOWING) { - var pos = getPosition(nodeB, offsetB, nodeA, offsetA); - if (pos == "before") { - return "after"; - } - if (pos == "after") { - return "before"; - } - } - - // "If node A is an ancestor of node B:" - if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_CONTAINS) { - // "Let child equal node B." - var child = nodeB; - - // "While child is not a child of node A, set child to its parent." - while (child.parentNode != nodeA) { - child = child.parentNode; - } - - // "If the index of child is less than offset A, return after." - if (indexOf(child) < offsetA) { - return "after"; - } - } - - // "Return before." - return "before"; -} - -/** - * "contained" as defined by DOM Range: "A Node node is contained in a range - * range if node's furthest ancestor is the same as range's root, and (node, 0) - * is after range's start, and (node, length of node) is before range's end." - */ -function isContained(node, range) { - var pos1 = getPosition(node, 0, range.startContainer, range.startOffset); - var pos2 = getPosition(node, nodeLength(node), range.endContainer, range.endOffset); - - return furthestAncestor(node) == furthestAncestor(range.startContainer) - && pos1 == "after" - && pos2 == "before"; -} - -/** - * "partially contained" as defined by DOM Range: "A Node is partially - * contained in a range if it is an ancestor container of the range's start but - * not its end, or vice versa." - */ -function isPartiallyContained(node, range) { - var cond1 = isAncestorContainer(node, range.startContainer); - var cond2 = isAncestorContainer(node, range.endContainer); - return (cond1 && !cond2) || (cond2 && !cond1); -} - -/** - * Index of a node as defined by the spec. - */ -function indexOf(node) { - if (!node.parentNode) { - // No preceding sibling nodes, right? - return 0; - } - var i = 0; - while (node != node.parentNode.childNodes[i]) { - i++; - } - return i; -} - -/** - * extractContents() implementation, following the spec. If an exception is - * supposed to be thrown, will return a string with the name (e.g., - * "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also - * return an arbitrary human-readable string if a condition is hit that implies - * a spec bug. - */ -function myExtractContents(range) { - // "Let frag be a new DocumentFragment whose ownerDocument is the same as - // the ownerDocument of the context object's start node." - var ownerDoc = range.startContainer.nodeType == Node.DOCUMENT_NODE - ? range.startContainer - : range.startContainer.ownerDocument; - var frag = ownerDoc.createDocumentFragment(); - - // "If the context object's start and end are the same, abort this method, - // returning frag." - if (range.startContainer == range.endContainer - && range.startOffset == range.endOffset) { - return frag; - } - - // "Let original start node, original start offset, original end node, and - // original end offset be the context object's start and end nodes and - // offsets, respectively." - var originalStartNode = range.startContainer; - var originalStartOffset = range.startOffset; - var originalEndNode = range.endContainer; - var originalEndOffset = range.endOffset; - - // "If original start node is original end node, and they are a Text, - // ProcessingInstruction, or Comment node:" - if (range.startContainer == range.endContainer - && (range.startContainer.nodeType == Node.TEXT_NODE - || range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE - || range.startContainer.nodeType == Node.COMMENT_NODE)) { - // "Let clone be the result of calling cloneNode(false) on original - // start node." - var clone = originalStartNode.cloneNode(false); - - // "Set the data of clone to the result of calling - // substringData(original start offset, original end offset − original - // start offset) on original start node." - clone.data = originalStartNode.substringData(originalStartOffset, - originalEndOffset - originalStartOffset); - - // "Append clone as the last child of frag." - frag.appendChild(clone); - - // "Call deleteData(original start offset, original end offset − - // original start offset) on original start node." - originalStartNode.deleteData(originalStartOffset, - originalEndOffset - originalStartOffset); - - // "Abort this method, returning frag." - return frag; - } - - // "Let common ancestor equal original start node." - var commonAncestor = originalStartNode; - - // "While common ancestor is not an ancestor container of original end - // node, set common ancestor to its own parent." - while (!isAncestorContainer(commonAncestor, originalEndNode)) { - commonAncestor = commonAncestor.parentNode; - } - - // "If original start node is an ancestor container of original end node, - // let first partially contained child be null." - var firstPartiallyContainedChild; - if (isAncestorContainer(originalStartNode, originalEndNode)) { - firstPartiallyContainedChild = null; - // "Otherwise, let first partially contained child be the first child of - // common ancestor that is partially contained in the context object." - } else { - for (var i = 0; i < commonAncestor.childNodes.length; i++) { - if (isPartiallyContained(commonAncestor.childNodes[i], range)) { - firstPartiallyContainedChild = commonAncestor.childNodes[i]; - break; - } - } - if (!firstPartiallyContainedChild) { - throw "Spec bug: no first partially contained child!"; - } - } - - // "If original end node is an ancestor container of original start node, - // let last partially contained child be null." - var lastPartiallyContainedChild; - if (isAncestorContainer(originalEndNode, originalStartNode)) { - lastPartiallyContainedChild = null; - // "Otherwise, let last partially contained child be the last child of - // common ancestor that is partially contained in the context object." - } else { - for (var i = commonAncestor.childNodes.length - 1; i >= 0; i--) { - if (isPartiallyContained(commonAncestor.childNodes[i], range)) { - lastPartiallyContainedChild = commonAncestor.childNodes[i]; - break; - } - } - if (!lastPartiallyContainedChild) { - throw "Spec bug: no last partially contained child!"; - } - } - - // "Let contained children be a list of all children of common ancestor - // that are contained in the context object, in tree order." - // - // "If any member of contained children is a DocumentType, raise a - // HIERARCHY_REQUEST_ERR exception and abort these steps." - var containedChildren = []; - for (var i = 0; i < commonAncestor.childNodes.length; i++) { - if (isContained(commonAncestor.childNodes[i], range)) { - if (commonAncestor.childNodes[i].nodeType - == Node.DOCUMENT_TYPE_NODE) { - return "HIERARCHY_REQUEST_ERR"; - } - containedChildren.push(commonAncestor.childNodes[i]); - } - } - - // "If original start node is an ancestor container of original end node, - // set new node to original start node and new offset to original start - // offset." - var newNode, newOffset; - if (isAncestorContainer(originalStartNode, originalEndNode)) { - newNode = originalStartNode; - newOffset = originalStartOffset; - // "Otherwise:" - } else { - // "Let reference node equal original start node." - var referenceNode = originalStartNode; - - // "While reference node's parent is not null and is not an ancestor - // container of original end node, set reference node to its parent." - while (referenceNode.parentNode - && !isAncestorContainer(referenceNode.parentNode, originalEndNode)) { - referenceNode = referenceNode.parentNode; - } - - // "Set new node to the parent of reference node, and new offset to one - // plus the index of reference node." - newNode = referenceNode.parentNode; - newOffset = 1 + indexOf(referenceNode); - } - - // "If first partially contained child is a Text, ProcessingInstruction, or - // Comment node:" - if (firstPartiallyContainedChild - && (firstPartiallyContainedChild.nodeType == Node.TEXT_NODE - || firstPartiallyContainedChild.nodeType == Node.PROCESSING_INSTRUCTION_NODE - || firstPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) { - // "Let clone be the result of calling cloneNode(false) on original - // start node." - var clone = originalStartNode.cloneNode(false); - - // "Set the data of clone to the result of calling substringData() on - // original start node, with original start offset as the first - // argument and (length of original start node − original start offset) - // as the second." - clone.data = originalStartNode.substringData(originalStartOffset, - nodeLength(originalStartNode) - originalStartOffset); - - // "Append clone as the last child of frag." - frag.appendChild(clone); - - // "Call deleteData() on original start node, with original start - // offset as the first argument and (length of original start node − - // original start offset) as the second." - originalStartNode.deleteData(originalStartOffset, - nodeLength(originalStartNode) - originalStartOffset); - // "Otherwise, if first partially contained child is not null:" - } else if (firstPartiallyContainedChild) { - // "Let clone be the result of calling cloneNode(false) on first - // partially contained child." - var clone = firstPartiallyContainedChild.cloneNode(false); - - // "Append clone as the last child of frag." - frag.appendChild(clone); - - // "Let subrange be a new Range whose start is (original start node, - // original start offset) and whose end is (first partially contained - // child, length of first partially contained child)." - var subrange = ownerDoc.createRange(); - subrange.setStart(originalStartNode, originalStartOffset); - subrange.setEnd(firstPartiallyContainedChild, - nodeLength(firstPartiallyContainedChild)); - - // "Let subfrag be the result of calling extractContents() on - // subrange." - var subfrag = myExtractContents(subrange); - - // "For each child of subfrag, in order, append that child to clone as - // its last child." - for (var i = 0; i < subfrag.childNodes.length; i++) { - clone.appendChild(subfrag.childNodes[i]); - } - } - - // "For each contained child in contained children, append contained child - // as the last child of frag." - for (var i = 0; i < containedChildren.length; i++) { - frag.appendChild(containedChildren[i]); - } - - // "If last partially contained child is a Text, ProcessingInstruction, or - // Comment node:" - if (lastPartiallyContainedChild - && (lastPartiallyContainedChild.nodeType == Node.TEXT_NODE - || lastPartiallyContainedChild.nodeType == Node.PROCESSING_INSTRUCTION_NODE - || lastPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) { - // "Let clone be the result of calling cloneNode(false) on original - // end node." - var clone = originalEndNode.cloneNode(false); - - // "Set the data of clone to the result of calling substringData(0, - // original end offset) on original end node." - clone.data = originalEndNode.substringData(0, originalEndOffset); - - // "Append clone as the last child of frag." - frag.appendChild(clone); - - // "Call deleteData(0, original end offset) on original end node." - originalEndNode.deleteData(0, originalEndOffset); - // "Otherwise, if last partially contained child is not null:" - } else if (lastPartiallyContainedChild) { - // "Let clone be the result of calling cloneNode(false) on last - // partially contained child." - var clone = lastPartiallyContainedChild.cloneNode(false); - - // "Append clone as the last child of frag." - frag.appendChild(clone); - - // "Let subrange be a new Range whose start is (last partially - // contained child, 0) and whose end is (original end node, original - // end offset)." - var subrange = ownerDoc.createRange(); - subrange.setStart(lastPartiallyContainedChild, 0); - subrange.setEnd(originalEndNode, originalEndOffset); - - // "Let subfrag be the result of calling extractContents() on - // subrange." - var subfrag = myExtractContents(subrange); - - // "For each child of subfrag, in order, append that child to clone as - // its last child." - for (var i = 0; i < subfrag.childNodes.length; i++) { - clone.appendChild(subfrag.childNodes[i]); - } - } - - // "Set the context object's start and end to (new node, new offset)." - range.setStart(newNode, newOffset); - range.setEnd(newNode, newOffset); - - // "Return frag." - return frag; -} - -/** - * insertNode() implementation, following the spec. If an exception is meant - * to be thrown, will return a string with the expected exception name, for - * instance "HIERARCHY_REQUEST_ERR". - */ -function myInsertNode(range, node) { - // "If range's start node is a ProcessingInstruction or Comment node, or is - // a Text node whose parent is null, or is node, throw an - // "HierarchyRequestError" exception and terminate these steps." - if (range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE - || range.startContainer.nodeType == Node.COMMENT_NODE - || (range.startContainer.nodeType == Node.TEXT_NODE - && !range.startContainer.parentNode) - || range.startContainer == node) { - return "HIERARCHY_REQUEST_ERR"; - } - - // "Let referenceNode be null." - var referenceNode = null; - - // "If range's start node is a Text node, set referenceNode to that Text node." - if (range.startContainer.nodeType == Node.TEXT_NODE) { - referenceNode = range.startContainer; - - // "Otherwise, set referenceNode to the child of start node whose index is - // start offset, and null if there is no such child." - } else { - if (range.startOffset < range.startContainer.childNodes.length) { - referenceNode = range.startContainer.childNodes[range.startOffset]; - } else { - referenceNode = null; - } - } - - // "Let parent be range's start node if referenceNode is null, and - // referenceNode's parent otherwise." - var parent_ = referenceNode === null ? range.startContainer : - referenceNode.parentNode; - - // "Ensure pre-insertion validity of node into parent before - // referenceNode." - var error = ensurePreInsertionValidity(node, parent_, referenceNode); - if (error) { - return error; - } - - // "If range's start node is a Text node, set referenceNode to the result - // of splitting it with offset range's start offset." - if (range.startContainer.nodeType == Node.TEXT_NODE) { - referenceNode = range.startContainer.splitText(range.startOffset); - } - - // "If node is referenceNode, set referenceNode to its next sibling." - if (node == referenceNode) { - referenceNode = referenceNode.nextSibling; - } - - // "If node's parent is not null, remove node from its parent." - if (node.parentNode) { - node.parentNode.removeChild(node); - } - - // "Let newOffset be parent's length if referenceNode is null, and - // referenceNode's index otherwise." - var newOffset = referenceNode === null ? nodeLength(parent_) : - indexOf(referenceNode); - - // "Increase newOffset by node's length if node is a DocumentFragment node, - // and one otherwise." - newOffset += node.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? - nodeLength(node) : 1; - - // "Pre-insert node into parent before referenceNode." - parent_.insertBefore(node, referenceNode); - - // "If range's start and end are the same, set range's end to (parent, - // newOffset)." - if (range.startContainer == range.endContainer - && range.startOffset == range.endOffset) { - range.setEnd(parent_, newOffset); - } -} - -// To make filter() calls more readable -function isElement(node) { - return node.nodeType == Node.ELEMENT_NODE; -} - -function isText(node) { - return node.nodeType == Node.TEXT_NODE; -} - -function isDoctype(node) { - return node.nodeType == Node.DOCUMENT_TYPE_NODE; -} - -function ensurePreInsertionValidity(node, parent_, child) { - // "If parent is not a Document, DocumentFragment, or Element node, throw a - // HierarchyRequestError." - if (parent_.nodeType != Node.DOCUMENT_NODE - && parent_.nodeType != Node.DOCUMENT_FRAGMENT_NODE - && parent_.nodeType != Node.ELEMENT_NODE) { - return "HIERARCHY_REQUEST_ERR"; - } - - // "If node is a host-including inclusive ancestor of parent, throw a - // HierarchyRequestError." - // - // XXX Does not account for host - if (isInclusiveAncestor(node, parent_)) { - return "HIERARCHY_REQUEST_ERR"; - } - - // "If child is not null and its parent is not parent, throw a NotFoundError - // exception." - if (child && child.parentNode != parent_) { - return "NOT_FOUND_ERR"; - } - - // "If node is not a DocumentFragment, DocumentType, Element, Text, - // ProcessingInstruction, or Comment node, throw a HierarchyRequestError." - if (node.nodeType != Node.DOCUMENT_FRAGMENT_NODE - && node.nodeType != Node.DOCUMENT_TYPE_NODE - && node.nodeType != Node.ELEMENT_NODE - && node.nodeType != Node.TEXT_NODE - && node.nodeType != Node.PROCESSING_INSTRUCTION_NODE - && node.nodeType != Node.COMMENT_NODE) { - return "HIERARCHY_REQUEST_ERR"; - } - - // "If either node is a Text node and parent is a document, or node is a - // doctype and parent is not a document, throw a HierarchyRequestError." - if ((node.nodeType == Node.TEXT_NODE - && parent_.nodeType == Node.DOCUMENT_NODE) - || (node.nodeType == Node.DOCUMENT_TYPE_NODE - && parent_.nodeType != Node.DOCUMENT_NODE)) { - return "HIERARCHY_REQUEST_ERR"; - } - - // "If parent is a document, and any of the statements below, switched on - // node, are true, throw a HierarchyRequestError." - if (parent_.nodeType == Node.DOCUMENT_NODE) { - switch (node.nodeType) { - case Node.DOCUMENT_FRAGMENT_NODE: - // "If node has more than one element child or has a Text node - // child. Otherwise, if node has one element child and either - // parent has an element child, child is a doctype, or child is not - // null and a doctype is following child." - if ([].filter.call(node.childNodes, isElement).length > 1) { - return "HIERARCHY_REQUEST_ERR"; - } - - if ([].some.call(node.childNodes, isText)) { - return "HIERARCHY_REQUEST_ERR"; - } - - if ([].filter.call(node.childNodes, isElement).length == 1) { - if ([].some.call(parent_.childNodes, isElement)) { - return "HIERARCHY_REQUEST_ERR"; - } - - if (child && child.nodeType == Node.DOCUMENT_TYPE_NODE) { - return "HIERARCHY_REQUEST_ERR"; - } - - if (child && [].slice.call(parent_.childNodes, indexOf(child) + 1) - .filter(isDoctype)) { - return "HIERARCHY_REQUEST_ERR"; - } - } - break; - - case Node.ELEMENT_NODE: - // "parent has an element child, child is a doctype, or child is - // not null and a doctype is following child." - if ([].some.call(parent_.childNodes, isElement)) { - return "HIERARCHY_REQUEST_ERR"; - } - - if (child.nodeType == Node.DOCUMENT_TYPE_NODE) { - return "HIERARCHY_REQUEST_ERR"; - } - - if (child && [].slice.call(parent_.childNodes, indexOf(child) + 1) - .filter(isDoctype)) { - return "HIERARCHY_REQUEST_ERR"; - } - break; - - case Node.DOCUMENT_TYPE_NODE: - // "parent has a doctype child, an element is preceding child, or - // child is null and parent has an element child." - if ([].some.call(parent_.childNodes, isDoctype)) { - return "HIERARCHY_REQUEST_ERR"; - } - - if (child && [].slice.call(parent_.childNodes, 0, indexOf(child)) - .some(isElement)) { - return "HIERARCHY_REQUEST_ERR"; - } - - if (!child && [].some.call(parent_.childNodes, isElement)) { - return "HIERARCHY_REQUEST_ERR"; - } - break; - } - } -} - -/** - * Asserts that two nodes are equal, in the sense of isEqualNode(). If they - * aren't, tries to print a relatively informative reason why not. TODO: Move - * this to testharness.js? - */ -function assertNodesEqual(actual, expected, msg) { - if (!actual.isEqualNode(expected)) { - msg = "Actual and expected mismatch for " + msg + ". "; - - while (actual && expected) { - assert_true(actual.nodeType === expected.nodeType - && actual.nodeName === expected.nodeName - && actual.nodeValue === expected.nodeValue, - "First differing node: expected " + format_value(expected) - + ", got " + format_value(actual) + " [" + msg + "]"); - actual = nextNode(actual); - expected = nextNode(expected); - } - - assert_unreached("DOMs were not equal but we couldn't figure out why"); - } -} - -/** - * Given a DOMException, return the name (e.g., "HIERARCHY_REQUEST_ERR"). - */ -function getDomExceptionName(e) { - var ret = null; - for (var prop in e) { - if (/^[A-Z_]+_ERR$/.test(prop) && e[prop] == e.code) { - return prop; - } - } - - throw "Exception seems to not be a DOMException? " + e; -} - -/** - * Given an array of endpoint data [start container, start offset, end - * container, end offset], returns a Range with those endpoints. - */ -function rangeFromEndpoints(endpoints) { - // If we just use document instead of the ownerDocument of endpoints[0], - // WebKit will throw on setStart/setEnd. This is a WebKit bug, but it's in - // range, not selection, so we don't want to fail anything for it. - var range = ownerDocument(endpoints[0]).createRange(); - range.setStart(endpoints[0], endpoints[1]); - range.setEnd(endpoints[2], endpoints[3]); - return range; -} |