\head>
How are you?<\p><\body> (the '\'s are to avoid validation errors) // ^----------------------^ assertEquals(r.toString(), "ful Kitty", "toString() on range crossing text nodes gave wrong output"); var f = r.extractContents(); //
<\p> // ccccccccccccccccMMMMMMcccccccccccc assertEquals(f.nodeType, 11, "failure 1"); assert(f.childNodes.length == 2, "expected two children in the result, got " + f.childNodes.length); assertEquals(f.childNodes[0].tagName, "H1", "failure 3"); assert(f.childNodes[0] != h1, "failure 4"); assertEquals(f.childNodes[0].childNodes.length, 2, "failure 5"); assertEquals(f.childNodes[0].childNodes[0].tagName, "EM", "failure 6"); assert(f.childNodes[0].childNodes[0] != em, "failure 7"); assertEquals(f.childNodes[0].childNodes[0].childNodes.length, 1, "failure 8"); assertEquals(f.childNodes[0].childNodes[0].childNodes[0].data, "ful", "failure 9"); assert(f.childNodes[0].childNodes[0].childNodes[0] != t2, "failure 10"); assertEquals(f.childNodes[0].childNodes[1], t3, "failure 11"); assert(f.childNodes[0].childNodes[1] != em, "failure 12"); assertEquals(f.childNodes[1].tagName, "P", "failure 13"); assertEquals(f.childNodes[1].childNodes.length, 0, "failure 14"); assert(f.childNodes[1] != p, "failure 15"); return 1; }, function () { // test 10: Ranges and Attribute Nodes // COMMENTED OUT FOR 2011 UPDATE - turns out instead of dropping Attr entirely, as Acid3 originally expected, the API is just being refactored // var e = document.getElementById('result'); // if (!e.getAttributeNode) // return 1; // support for attribute nodes is optional in Acid3, because attribute nodes might be removed from DOM Core in the future. // // however, if they're supported, they'd better work: // var a = e.getAttributeNode('id'); // var r = document.createRange(); // r.selectNodeContents(a); // assertEquals(r.toString(), "result", "toString() didn't work for attribute node"); // var t = a.firstChild; // var f = r.extractContents(); // assertEquals(f.childNodes.length, 1, "extracted contents were the wrong length"); // assertEquals(f.childNodes[0], t, "extracted contents were the wrong node"); // assertEquals(t.textContent, 'result', "extracted contents didn't match old attribute value"); // assertEquals(r.toString(), '', "extracting contents didn't empty attribute value; instead equals '" + r.toString() + "'"); // assertEquals(e.getAttribute('id'), '', "extracting contents didn't change 'id' attribute to empty string"); // e.id = 'result'; return 1; }, function () { // test 11: Ranges and Comments var msg; var doc = getTestDocument(); var c1 = doc.createComment("11111"); doc.appendChild(c1); var r = doc.createRange(); r.selectNode(c1); msg = 'wrong exception raised'; try { r.surroundContents(doc.createElement('a')); msg = 'no exception raised'; } catch (e) { if ('code' in e) msg += '; code = ' + e.code; if (e.code == 3) // HIERARCHY_REQUEST_ERR msg = ''; } assert(msg == '', "when inserting into Document with another child: " + msg); var c2 = doc.createComment("22222"); doc.body.appendChild(c2); var c3 = doc.createComment("33333"); doc.body.appendChild(c3); r.setStart(c2, 2); r.setEnd(c3, 3); var msg = 'wrong exception raised'; try { r.surroundContents(doc.createElement('a')); msg = 'no exception raised'; } catch (e) { // COMMENTED OUT FOR 2011 UPDATE - DOM Core changes the exception from RangeException.BAD_BOUNDARYPOINTS_ERR (1) to DOMException.INVALID_STATE_ERR (11) // if ('code' in e) // msg += '; code = ' + e.code; // if (e.code == 1) msg = ''; } assert(msg == '', "when trying to surround two halves of comment: " + msg); assertEquals(r.toString(), "", "comments returned text"); return 1; }, function () { // test 12: Ranges under mutations: insertion into text nodes var doc = getTestDocument(); var p = doc.createElement('p'); var t1 = doc.createTextNode('12345'); p.appendChild(t1); var t2 = doc.createTextNode('ABCDE'); p.appendChild(t2); doc.body.appendChild(p); var r = doc.createRange(); r.setStart(p.firstChild, 2); r.setEnd(p.firstChild, 3); assert(!r.collapsed, "collapsed is wrong at start"); assertEquals(r.commonAncestorContainer, p.firstChild, "commonAncestorContainer is wrong at start"); assertEquals(r.startContainer, p.firstChild, "startContainer is wrong at start"); assertEquals(r.startOffset, 2, "startOffset is wrong at start"); assertEquals(r.endContainer, p.firstChild, "endContainer is wrong at start"); assertEquals(r.endOffset, 3, "endOffset is wrong at start"); assertEquals(r.toString(), "3", "range in text node stringification failed"); r.insertNode(p.lastChild); assertEquals(p.childNodes.length, 3, "insertion of node made wrong number of child nodes"); assertEquals(p.childNodes[0], t1, "unexpected first text node"); assertEquals(p.childNodes[0].data, "12", "unexpected first text node contents"); assertEquals(p.childNodes[1], t2, "unexpected second text node"); assertEquals(p.childNodes[1].data, "ABCDE", "unexpected second text node"); assertEquals(p.childNodes[2].data, "345", "unexpected third text node contents"); // The spec is very vague about what exactly should be in the range afterwards: // the insertion results in a splitText(), which it says is equivalent to a truncation // followed by an insertion, but it doesn't say what to do when you have a truncation, // so we don't know where either the start or the end boundary points end up. // The spec really should be clarified for how to handle splitText() and // text node truncation in general // The only thing that seems very clear is that the inserted text node should // be in the range, and it has to be at the start, since insertion always puts it at // the start. assert(!r.collapsed, "collapsed is wrong after insertion"); assert(r.toString().match(/^ABCDE/), "range didn't start with the expected text; range stringified to '" + r.toString() + "'"); return 1; }, function () { // test 13: Ranges under mutations: deletion var doc = getTestDocument(); var p = doc.createElement('p'); p.appendChild(doc.createTextNode("12345")); doc.body.appendChild(p); var r = doc.createRange(); r.setEnd(doc.body, 1); r.setStart(p.firstChild, 2); assert(!r.collapsed, "collapsed is wrong at start"); assertEquals(r.commonAncestorContainer, doc.body, "commonAncestorContainer is wrong at start"); assertEquals(r.startContainer, p.firstChild, "startContainer is wrong at start"); assertEquals(r.startOffset, 2, "startOffset is wrong at start"); assertEquals(r.endContainer, doc.body, "endContainer is wrong at start"); assertEquals(r.endOffset, 1, "endOffset is wrong at start"); doc.body.removeChild(p); assert(r.collapsed, "collapsed is wrong after deletion"); assertEquals(r.commonAncestorContainer, doc.body, "commonAncestorContainer is wrong after deletion"); assertEquals(r.startContainer, doc.body, "startContainer is wrong after deletion"); assertEquals(r.startOffset, 0, "startOffset is wrong after deletion"); assertEquals(r.endContainer, doc.body, "endContainer is wrong after deletion"); assertEquals(r.endOffset, 0, "endOffset is wrong after deletion"); return 1; }, // HTTP function () { // test 14: HTTP - Content-Type: image/png assert(!notifications['empty.png'], "privilege escalation security bug: PNG ran script"); var iframe = document.getElementsByTagName('iframe')[0]; assert(iframe, "no
\html> (the '\'s are to avoid validation errors) var iteration = 0; var exception = "Roses"; var test = function(node) { iteration += 1; switch (iteration) { case 1: case 3: case 4: case 6: case 7: case 8: case 9: case 14: case 15: throw exception; case 2: case 5: case 10: case 11: case 12: case 13: return true; // ToNumber(true) => 1 default: throw 0; }; }; var check = function(o, method) { var ok = false; try { o[method](); } catch (e) { if (e === exception) ok = true; } assert(ok, "method " + o + "." + method + "() didn't forward exception"); }; var i = doc.createNodeIterator(doc.documentElement, 0xFFFFFFFF, test, true); check(i, "nextNode"); // 1 assertEquals(i.nextNode(), doc.documentElement, "i.nextNode() didn't return the right node"); // 2 check(i, "previousNode"); // 3 var w = document.createTreeWalker(doc.documentElement, 0xFFFFFFFF, test, true); check(w, "nextNode"); // 4 assertEquals(w.nextNode(), doc.documentElement.firstChild, "w.nextNode() didn't return the right node"); // 5 check(w, "previousNode"); // 6 check(w, "firstChild"); // 7 check(w, "lastChild"); // 8 check(w, "nextSibling"); // 9 assertEquals(iteration, 9, "iterations went wrong"); assertEquals(w.previousSibling(), null, "w.previousSibling() didn't return the right node"); // doesn't call filter assertEquals(iteration, 9, "filter called incorrectly for previousSibling()"); assertEquals(w.lastChild(), doc.getElementsByTagName('title')[0], "w.lastChild() didn't return the right node"); // 10 assertEquals(w.nextSibling(), null, "w.nextSibling() didn't return the right node"); // 11 (filter called on parent, to see if it's included, otherwise it could skip that and find a nextsibling elsewhere) assertEquals(iteration, 11, "filter called incorrectly for nextSibling()"); assertEquals(w.parentNode(), doc.documentElement.firstChild, "w.parentNode() didn't return the right node"); // 12 assertEquals(w.nextSibling(), doc.documentElement.lastChild, "w.nextSibling() didn't return the right node"); // 13 check(w, "previousSibling"); // 14 check(w, "parentNode"); // 15 return 1; }, function () { // test 2: Removing nodes during iteration var count = 0; var expect = function(n, node1, node2) { count += 1; assert(n == count, "reached expectation " + n + " when expecting expectation " + count); assertEquals(node1, node2, "expectation " + count + " failed"); }; var doc = getTestDocument(); var t1 = doc.body.appendChild(doc.createElement('t1')); var t2 = doc.body.appendChild(doc.createElement('t2')); var t3 = doc.body.appendChild(doc.createElement('t3')); var t4 = doc.body.appendChild(doc.createElement('t4')); var callCount = 0; var filterFunctions = [ function (node) { expect(1, node, doc.body); return true; }, // filter 0 function (node) { expect(3, node, t1); return true; }, // filter 1 function (node) { expect(5, node, t2); return true; }, // filter 2 function (node) { expect(7, node, t3); doc.body.removeChild(t4); return true; }, // filter 3 function (node) { expect(9, node, t4); return true; }, // filter 4 function (node) { expect(11, node, t4); doc.body.removeChild(t4); return 2 /* REJECT */; }, // filter 5 function (node) { expect(12, node, t3); return true; }, // filter 6 function (node) { expect(14, node, t2); doc.body.removeChild(t2); return true; }, // filter 7 function (node) { expect(16, node, t1); return true; }, // filter 8 ]; var i = doc.createNodeIterator(doc.documentElement.lastChild, 0xFFFFFFFF, function (node) { return filterFunctions[callCount++](node); }, true); // * B 1 2 3 4 expect(2, i.nextNode(), doc.body); // filter 0 // [B] * 1 2 3 4 expect(4, i.nextNode(), t1); // filter 1 // B [1] * 2 3 4 expect(6, i.nextNode(), t2); // filter 2 // B 1 [2] * 3 4 expect(8, i.nextNode(), t3); // filter 3 // B 1 2 [3] * doc.body.appendChild(t4); // B 1 2 [3] * 4 expect(10, i.nextNode(), t4); // filter 4 // B 1 2 3 [4] * expect(13, i.previousNode(), t3); // filters 5, 6 // B 1 2 3 * (4) // filter 5 // B 1 2 [3] * // between 5 and 6 // B 1 2 * (3) // filter 6 // B 1 2 * [3] expect(15, i.previousNode(), t2); // filter 7 // B 1 * (2) [3] // -- spec says "For instance, if a NodeFilter removes a node // from a document, it can still accept the node, which // means that the node may be returned by the NodeIterator // or TreeWalker even though it is no longer in the subtree // being traversed." // -- but it also says "If changes to the iterated list do not // remove the reference node, they do not affect the state // of the NodeIterator." // B 1 * [3] expect(17, i.previousNode(), t1); // filter 8 // B [1] * 3 return 1; }, function () { // test 3: the infinite iterator var doc = getTestDocument(); for (var i = 0; i < 5; i += 1) { doc.body.appendChild(doc.createElement('section')); doc.body.lastChild.title = i; } var count = 0; var test = function() { if (count > 3 && count < 12) doc.body.appendChild(doc.body.firstChild); count += 1; return (count % 2 == 0) ? 1 : 2; }; var i = doc.createNodeIterator(doc.body, 0xFFFFFFFF, test, true); assertEquals(i.nextNode().title, "0", "failure 1"); assertEquals(i.nextNode().title, "2", "failure 2"); assertEquals(i.nextNode().title, "4", "failure 3"); assertEquals(i.nextNode().title, "1", "failure 4"); assertEquals(i.nextNode().title, "3", "failure 5"); assertEquals(i.nextNode().title, "0", "failure 6"); assertEquals(i.nextNode().title, "2", "failure 7"); assertEquals(i.nextNode(), null, "failure 8"); return 1; }, function () { // test 4: ignoring whitespace text nodes with node iterators var count = 0; var expect = function(node1, node2) { count += 1; assertEquals(node1, node2, "expectation " + count + " failed"); }; var allButWS = function (node) { if (node.nodeType == 3 && node.data.match(/^\s*$/)) return 2; return 1; }; var i = document.createNodeIterator(document.body, 0x01 | 0x04 | 0x08 | 0x10 | 0x20, allButWS, true); // now walk the document body and make sure everything is in the right place expect(i.nextNode(), document.body); // 1 expect(i.nextNode(), document.getElementsByTagName('h1')[0]); expect(i.nextNode(), document.getElementsByTagName('h1')[0].firstChild); expect(i.nextNode(), document.getElementsByTagName('div')[0]); expect(i.nextNode(), document.getElementById('bucket1')); expect(i.nextNode(), document.getElementById('bucket2')); expect(i.nextNode(), document.getElementById('bucket3')); expect(i.nextNode(), document.getElementById('bucket4')); expect(i.nextNode(), document.getElementById('bucket5')); expect(i.nextNode(), document.getElementById('bucket6')); // 10 expect(i.nextNode(), document.getElementById('result')); expect(i.nextNode(), document.getElementById('score')); expect(i.nextNode(), document.getElementById('score').firstChild); expect(i.nextNode(), document.getElementById('slash')); expect(i.nextNode(), document.getElementById('slash').firstChild); expect(i.nextNode(), document.getElementById('slash').nextSibling); expect(i.nextNode(), document.getElementById('slash').nextSibling.firstChild); expect(i.nextNode(), document.getElementsByTagName('map')[0]); expect(i.nextNode(), document.getElementsByTagName('area')[0]); expect(i.nextNode(), document.getElementsByTagName('iframe')[0]); // 20 expect(i.nextNode(), document.getElementsByTagName('iframe')[0].firstChild); expect(i.nextNode(), document.getElementsByTagName('iframe')[1]); expect(i.nextNode(), document.getElementsByTagName('iframe')[1].firstChild); expect(i.nextNode(), document.getElementsByTagName('iframe')[2]); expect(i.nextNode(), document.forms[0]); expect(i.nextNode(), document.forms.form.elements[0]); expect(i.nextNode(), document.getElementsByTagName('table')[0]); expect(i.nextNode(), document.getElementsByTagName('tbody')[0]); expect(i.nextNode(), document.getElementsByTagName('tr')[0]); expect(i.nextNode(), document.getElementsByTagName('td')[0]); expect(i.nextNode(), document.getElementsByTagName('td')[0].getElementsByTagName('p')[0]); expect(i.nextNode(), document.getElementById('instructions')); expect(i.nextNode(), document.getElementById('instructions').firstChild); expect(i.nextNode().nodeName, "SPAN"); expect(i.nextNode().nodeName, "#text"); expect(i.nextNode(), document.links[1]); expect(i.nextNode(), document.links[1].firstChild); expect(i.nextNode(), document.getElementById('instructions').lastChild); expect(i.nextNode(), null); // walk it backwards for good measure expect(i.previousNode(), document.getElementById('instructions').lastChild); expect(i.previousNode(), document.links[1].firstChild); expect(i.previousNode(), document.links[1]); expect(i.previousNode().nodeName, "#text"); expect(i.previousNode().nodeName, "SPAN"); expect(i.previousNode(), document.getElementById('instructions').firstChild); expect(i.previousNode(), document.getElementById('instructions')); expect(i.previousNode(), document.getElementsByTagName('td')[0].getElementsByTagName('p')[0]); expect(i.previousNode(), document.getElementsByTagName('td')[0]); expect(i.previousNode(), document.getElementsByTagName('tr')[0]); expect(i.previousNode(), document.getElementsByTagName('tbody')[0]); expect(i.previousNode(), document.getElementsByTagName('table')[0]); expect(i.previousNode(), document.forms.form.elements[0]); expect(i.previousNode(), document.forms[0]); expect(i.previousNode(), document.getElementsByTagName('iframe')[2]); expect(i.previousNode(), document.getElementsByTagName('iframe')[1].firstChild); expect(i.previousNode(), document.getElementsByTagName('iframe')[1]); expect(i.previousNode(), document.getElementsByTagName('iframe')[0].firstChild); expect(i.previousNode(), document.getElementsByTagName('iframe')[0]); // 20 expect(i.previousNode(), document.getElementsByTagName('area')[0]); expect(i.previousNode(), document.getElementsByTagName('map')[0]); expect(i.previousNode(), document.getElementById('slash').nextSibling.firstChild); expect(i.previousNode(), document.getElementById('slash').nextSibling); expect(i.previousNode(), document.getElementById('slash').firstChild); expect(i.previousNode(), document.getElementById('slash')); expect(i.previousNode(), document.getElementById('score').firstChild); expect(i.previousNode(), document.getElementById('score')); expect(i.previousNode(), document.getElementById('result')); expect(i.previousNode(), document.getElementById('bucket6')); expect(i.previousNode(), document.getElementById('bucket5')); expect(i.previousNode(), document.getElementById('bucket4')); expect(i.previousNode(), document.getElementById('bucket3')); expect(i.previousNode(), document.getElementById('bucket2')); expect(i.previousNode(), document.getElementById('bucket1')); expect(i.previousNode(), document.getElementsByTagName('div')[0]); expect(i.previousNode(), document.getElementsByTagName('h1')[0].firstChild); expect(i.previousNode(), document.getElementsByTagName('h1')[0]); expect(i.previousNode(), document.body); expect(i.previousNode(), null); return 1; }, function () { // test 5: ignoring whitespace text nodes with tree walkers var count = 0; var expect = function(node1, node2) { count += 1; assertEquals(node1, node2, "expectation " + count + " failed"); }; var allButWS = function (node) { if (node.nodeType == 3 && node.data.match(/^\s*$/)) return 3; return 1; }; var w = document.createTreeWalker(document.body, 0x01 | 0x04 | 0x08 | 0x10 | 0x20, allButWS, true); expect(w.currentNode, document.body); expect(w.parentNode(), null); expect(w.currentNode, document.body); expect(w.firstChild(), document.getElementsByTagName('h1')[0]); expect(w.firstChild().nodeType, 3); expect(w.parentNode(), document.getElementsByTagName('h1')[0]); expect(w.nextSibling().previousSibling.nodeType, 3); expect(w.nextSibling(), document.getElementsByTagName('p')[6]); expect(w.nextSibling(), document.getElementsByTagName('map')[0]); expect(w.lastChild(), document.getElementsByTagName('table')[0]); expect(w.lastChild(), document.getElementsByTagName('tbody')[0]); expect(w.nextNode(), document.getElementsByTagName('tr')[0]); expect(w.nextNode(), document.getElementsByTagName('td')[0]); expect(w.nextNode(), document.getElementsByTagName('p')[7]); expect(w.nextNode(), document.getElementsByTagName('p')[8]); // instructions.inc paragraph expect(w.previousSibling(), document.getElementsByTagName('map')[0]); expect(w.previousNode().data, "100"); expect(w.parentNode().tagName, "SPAN"); expect(w.parentNode(), document.getElementById('result')); expect(w.parentNode(), document.body); expect(w.lastChild().id, "instructions"); expect(w.lastChild().data.substr(0,1), "."); expect(w.previousNode(), document.links[1].firstChild); return 1; }, function () { // test 6: walking outside a tree var doc = getTestDocument(); var p = doc.createElement('p'); doc.body.appendChild(p); var b = doc.body; var w = document.createTreeWalker(b, 0xFFFFFFFF, null, true); assertEquals(w.currentNode, b, "basic use of TreeWalker failed: currentNode"); assertEquals(w.lastChild(), p, "basic use of TreeWalker failed: lastChild()"); assertEquals(w.previousNode(), b, "basic use of TreeWalker failed: previousNode()"); doc.documentElement.removeChild(b); assertEquals(w.lastChild(), p, "TreeWalker failed after removing the current node from the tree"); assertEquals(w.nextNode(), null, "failed to walk into the end of a subtree"); doc.documentElement.appendChild(p); assertEquals(w.previousNode(), doc.getElementsByTagName('title')[0], "failed to handle regrafting correctly"); p.appendChild(b); assertEquals(w.nextNode(), p, "couldn't retrace steps"); assertEquals(w.nextNode(), b, "couldn't step back into root"); assertEquals(w.previousNode(), null, "root didn't retake its rootish position"); return 1; }, // DOM Range function () { // test 7: basic ranges tests var r = document.createRange(); assert(r, "range not created"); assert(r.collapsed, "new range wasn't collapsed"); assertEquals(r.commonAncestorContainer, document, "new range's common ancestor wasn't the document"); assertEquals(r.startContainer, document, "new range's start container wasn't the document"); assertEquals(r.startOffset, 0, "new range's start offset wasn't zero"); assertEquals(r.endContainer, document, "new range's end container wasn't the document"); assertEquals(r.endOffset, 0, "new range's end offset wasn't zero"); assert(r.cloneContents(), "cloneContents() didn't return an object"); assertEquals(r.cloneContents().childNodes.length, 0, "nothing cloned was more than nothing"); assertEquals(r.cloneRange().toString(), "", "nothing cloned stringifed to more than nothing"); r.collapse(true); // no effect assertEquals(r.compareBoundaryPoints(r.START_TO_END, r.cloneRange()), 0, "starting boundary point of range wasn't the same as the end boundary point of the clone range"); r.deleteContents(); // no effect assertEquals(r.extractContents().childNodes.length, 0, "nothing removed was more than nothing"); var endOffset = r.endOffset; r.insertNode(document.createComment("commented inserted to test ranges")); r.setEnd(r.endContainer, endOffset + 1); // added to work around spec bug that smaug is blocking the errata for try { assert(!r.collapsed, "range with inserted comment is collapsed"); assertEquals(r.commonAncestorContainer, document, "range with inserted comment has common ancestor that isn't the document"); assertEquals(r.startContainer, document, "range with inserted comment has start container that isn't the document"); assertEquals(r.startOffset, 0, "range with inserted comment has start offset that isn't zero"); assertEquals(r.endContainer, document, "range with inserted comment has end container that isn't the document"); assertEquals(r.endOffset, 1, "range with inserted comment has end offset that isn't after the comment"); } finally { document.removeChild(document.firstChild); } return 1; }, function () { // test 8: moving boundary points var doc = document.implementation.createDocument(null, null, null); var root = doc.createElement("root"); doc.appendChild(root); var e1 = doc.createElement("e"); root.appendChild(e1); var e2 = doc.createElement("e"); root.appendChild(e2); var e3 = doc.createElement("e"); root.appendChild(e3); var r = doc.createRange(); r.setStart(e2, 0); r.setEnd(e3, 0); assert(!r.collapsed, "non-empty range claims to be collapsed"); r.setEnd(e1, 0); assert(r.collapsed, "setEnd() didn't collapse the range"); assertEquals(r.startContainer, e1, "startContainer is wrong after setEnd()"); assertEquals(r.startOffset, 0, "startOffset is wrong after setEnd()"); assertEquals(r.endContainer, e1, "endContainer is wrong after setEnd()"); assertEquals(r.endOffset, 0, "endOffset is wrong after setEnd()"); r.setStartBefore(e3); assert(r.collapsed, "setStartBefore() didn't collapse the range"); assertEquals(r.startContainer, root, "startContainer is wrong after setStartBefore()"); assertEquals(r.startOffset, 2, "startOffset is wrong after setStartBefore()"); assertEquals(r.endContainer, root, "endContainer is wrong after setStartBefore()"); assertEquals(r.endOffset, 2, "endOffset is wrong after setStartBefore()"); r.setEndAfter(root); assert(!r.collapsed, "setEndAfter() didn't uncollapse the range"); assertEquals(r.startContainer, root, "startContainer is wrong after setEndAfter()"); assertEquals(r.startOffset, 2, "startOffset is wrong after setEndAfter()"); assertEquals(r.endContainer, doc, "endContainer is wrong after setEndAfter()"); assertEquals(r.endOffset, 1, "endOffset is wrong after setEndAfter()"); r.setStartAfter(e2); assert(!r.collapsed, "setStartAfter() collapsed the range"); assertEquals(r.startContainer, root, "startContainer is wrong after setStartAfter()"); assertEquals(r.startOffset, 2, "startOffset is wrong after setStartAfter()"); assertEquals(r.endContainer, doc, "endContainer is wrong after setStartAfter()"); assertEquals(r.endOffset, 1, "endOffset is wrong after setStartAfter()"); var msg = ''; try { r.setEndBefore(doc); msg = "no exception thrown for setEndBefore() the document itself"; } catch (e) { // COMMENTED OUT FOR 2011 UPDATE - we may want to merge RangeException and DOMException // if (e.BAD_BOUNDARYPOINTS_ERR != 1) // msg = 'not a RangeException'; // else // if (e.INVALID_NODE_TYPE_ERR != 2) // msg = 'RangeException has no INVALID_NODE_TYPE_ERR'; // else // if ("INVALID_ACCESS_ERR" in e) // msg = 'RangeException has DOMException constants'; // else if (e.code != e.INVALID_NODE_TYPE_ERR) msg = 'wrong exception raised from setEndBefore()'; } assert(msg == "", msg); assert(!r.collapsed, "setEndBefore() collapsed the range"); assertEquals(r.startContainer, root, "startContainer is wrong after setEndBefore()"); assertEquals(r.startOffset, 2, "startOffset is wrong after setEndBefore()"); assertEquals(r.endContainer, doc, "endContainer is wrong after setEndBefore()"); assertEquals(r.endOffset, 1, "endOffset is wrong after setEndBefore()"); r.collapse(false); assert(r.collapsed, "collapse() collapsed the range"); assertEquals(r.startContainer, doc, "startContainer is wrong after collapse()"); assertEquals(r.startOffset, 1, "startOffset is wrong after collapse()"); assertEquals(r.endContainer, doc, "endContainer is wrong after collapse()"); assertEquals(r.endOffset, 1, "endOffset is wrong after collapse()"); r.selectNodeContents(root); assert(!r.collapsed, "collapsed is wrong after selectNodeContents()"); assertEquals(r.startContainer, root, "startContainer is wrong after selectNodeContents()"); assertEquals(r.startOffset, 0, "startOffset is wrong after selectNodeContents()"); assertEquals(r.endContainer, root, "endContainer is wrong after selectNodeContents()"); assertEquals(r.endOffset, 3, "endOffset is wrong after selectNodeContents()"); r.selectNode(e2); assert(!r.collapsed, "collapsed is wrong after selectNode()"); assertEquals(r.startContainer, root, "startContainer is wrong after selectNode()"); assertEquals(r.startOffset, 1, "startOffset is wrong after selectNode()"); assertEquals(r.endContainer, root, "endContainer is wrong after selectNode()"); assertEquals(r.endOffset, 2, "endOffset is wrong after selectNode()"); return 1; }, function () { // test 9: extractContents() in a Document var doc = getTestDocument(); var h1 = doc.createElement('h1'); var t1 = doc.createTextNode('Hello '); h1.appendChild(t1); var em = doc.createElement('em'); var t2 = doc.createTextNode('Wonderful'); em.appendChild(t2); h1.appendChild(em); var t3 = doc.createTextNode(' Kitty'); h1.appendChild(t3); doc.body.appendChild(h1); var p = doc.createElement('p'); var t4 = doc.createTextNode('How are you?'); p.appendChild(t4); doc.body.appendChild(p); var r = doc.createRange(); r.selectNodeContents(doc); assertEquals(r.toString(), "Hello Wonderful KittyHow are you?", "toString() on range selecting Document gave wrong output"); r.setStart(t2, 6); r.setEnd(p, 0); //