/* set the line height of the line of coloured boxes so we can add them without the layout changing height */
.buckets { font: 0/0 Arial, sans-serif; }
.buckets { padding: 0 0 150px 3px; }
/* the next two rules give the six coloured blocks their default styles (they match the same elements); the third hides them */
:first-child + * .buckets p { display: inline-block; vertical-align: 2em; border: 2em dotted red; padding: 1.0em 0 1.0em 2em; }
* + * > * > p { margin: 0; border: 1px solid ! important; }
.z { visibility: hidden; } /* only matches the buckets with no score */
/* The line-height for the .bucket div is worked out as follows:
*
* The div.bucket element has a line box with a few
* inline-blocks. Each inline-block consists of:
*
* 2.0em vertical-align from baseline to bottom of inline-block
* 1px bottom border
* 1.0em bottom padding
* 1.0em top padding
* 1px top border
*
* The biggest inline-block has font-size: 40px.
*
* Thus the distance from the baseline to the top of the biggest
* inline-block is (2em+1em+1em)*2em*20px+2px = 162px.
*
* The line box itself has no other contents, and its strut has zero
* height and there is no half-leading, so the height of the
* div.bucket is 162px.
*
* (Why use line-height:0 and font-size:0? Well:
*
* The div.bucket line box would have a height that is the maximum
* of the following two sums:
*
* 1: half-leading + font descent at 1em + font ascent at 1em + half-leading
* 2: half-leading + font descent at 1em + 162px
*
* Now the half-leading is (line-height - (font-ascent + font-descent))/2, so that is really:
*
* 1: (line-height - (font-ascent + font-descent))/2 + font descent + font ascent + (line-height - (font-ascent + font-descent))/2
* 2: (line-height - (font-ascent + font-descent))/2 + font descent + 162px
*
* Which simplify to:
*
* 1: line-height
* 2: line-height/2 + (font descent - font-ascent)/2 + 162px
*
* So if the following expression is true:
*
* line-height > line-height/2 + (font descent - font-ascent)/2 + 162px
*
* That is, if this is true:
*
* line-height > font descent - font-ascent + 324px
*
* ...then the line-height matters, otherwise the font does. Note
* that font descent - font-ascent will be in the region of
* 10px-30px (with Ahem, exactly 12px). However, if we make the
* line-height big, then the _positioning_ of the inline-blocks will
* depend on the font descent, since that is what will decide the
* distance from the bottom of the line box to the baseline of the
* block (since the baseline is set by the strut).
*
* However, in Acid2 a dependency on the font metrics was introduced
* and this caused all kinds of problems. And we can't require Ahem
* in the Acid tests, since it's unlikely most people will have it
* installed.
*
* What we want is for the font to not matter, and the baseline to
* be as high as possible. We can do that by saying that the font
* and the line-height are zero.
*
* One word of warning. If your browser has a minimum font size feature
* that forces font sizes up even when there is no text, you will need
* to disable it before running this test.
*
*/
<!-- part of the HTTP tests -->
<link rel="stylesheet" href="empty.css"><!-- text/html file (should be ignored, <h1> will go red if it isn't) -->
<!-- the next five script blocks are part of one of the tests -->
<script type="text/javascript"> var d1 = "fail"; var d2 = "fail"; var d3 = "fail"; var d4 = "fail"; var d5 = "fail";
</script>
<script type="text/javascript" src="data:text/javascript,d1%20%3D%20'one'%3B"></script>
<script type="text/javascript" src="data:text/javascript;base64,ZDIgPSAndHdvJzs%3D"></script>
<script type="text/javascript" src="data:text/javascript;base64,%5a%44%4d%67%50%53%41%6e%64%47%68%79%5a%57%55%6e%4f%77%3D%3D"></script>
<script type="text/javascript" src="data:text/javascript;base64,%20ZD%20Qg%0D%0APS%20An%20Zm91cic%0D%0A%207%20"></script>
<script type="text/javascript" src="data:text/javascript,d5%20%3D%20'five%5Cu0027s'%3B"></script>
<!-- part of the JS regexp and \0 value tests test -->
<script type="text/javascript"> var nullInRegexpArgumentResult = 0 < /script/.test('\0script') ? "passed" : "failed";
</script>
<!-- main test body -->
<script type="text/javascript"> var notifications = {};
function notify(file) {
// used in cross-file tests
notifications[file] = 1;
}
function fail(message) {
throw { message: message };
}
function assert(condition, message) {
if (!condition)
fail(message);
}
function assertEquals(expression, value, message) {
if (expression != value) {
expression = (""+expression).replace(/[\r\n]+/g, "\\n");
value = (""+value).replace(/\r?\n/g, "\\n");
fail("expected '" + value + "' but got '" + expression + "' - " + message);
}
}
function getTestDocument() { variframe = document.getElementById("selectors"); var doc = iframe.contentDocument;
for (var i = doc.documentElement.childNodes.length-1; i >= 0; i -= 1)
doc.documentElement.removeChild(doc.documentElement.childNodes[i]);
doc.documentElement.appendChild(doc.createElement('head'));
doc.documentElement.firstChild.appendChild(doc.createElement('title'));
doc.documentElement.appendChild(doc.createElement('body'));
return doc;
}
function selectorTest(tester) { var doc = getTestDocument(); varstyle = doc.createElement('style'); style.appendChild(doc.createTextNode("* { z-index: 0; position: absolute; }\n"));
doc.documentElement.firstChild.appendChild(style); var ruleCount = 0;
tester(doc, function (selector) {
ruleCount += 1; style.appendChild(doc.createTextNode(selector + " { z-index: " + ruleCount + "; }\n"));
return ruleCount;
}, function(node, rule, message) { var value = doc.defaultView.getComputedStyle(node, "").zIndex;
assert(value != 'auto', "underlying problems prevent this test from running properly");
assertEquals(value, rule, message);
});
} var kungFuDeathGrip = null; // used to hold things from test to test var tests = [
// there are 6 buckets with 16 tests each, plus four special tests (0, 97, 98, and 99).
// Remove the "JS required" message and the <script> element in the <body>
function () {
// test 0: whether removing an element that is the last child correctly recomputes styles for the new last child
// also tests support for getComputedStyle, :last-child, pre-wrap, removing a <script> element
// removing script: var scripts = document.getElementsByTagName('script');
document.body.removeChild(scripts[scripts.length-1]);
// removing last child: var last = document.getElementById('remove-last-child-test'); var penultimate = last.previousSibling; // this should be the whitespace node
penultimate = penultimate.previousSibling; // this should now be the actual penultimate element
last.parentNode.removeChild(last);
assertEquals(document.defaultView.getComputedStyle(penultimate, '').whiteSpace, 'pre-wrap', "found unexpected computed style");
return 7;
},
// bucket 1: DOM Traversal, DOM Range, HTTP
// DOM Traversal
function () {
// test 1: NodeFilters and Exceptions var doc = getTestDocument(); // looks like <!DOCTYPE><html><head><title/><\head><body/><\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(); varh1 = doc.createElement('h1'); var t1 = doc.createTextNode('Hello '); h1.appendChild(t1); varem = 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);
// <body><h1>Hello <em>Wonder ful<\em> Kitty<\h1><p> 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();
// <h1><em>ful<\em> Kitty<\h1><p><\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"); variframe = document.getElementsByTagName('iframe')[0];
assert(iframe, "no );
if (iframe && iframe.contentDocument) { var ps = iframe.contentDocument.getElementsByTagName('p');
if (ps.length > 0) {
if (ps[0].firstChild && ps[0].firstChild.data && ps[0].firstChild.data == 'FAIL')
fail("PNG was parsed as HTML.");
}
}
return 1;
},
function () {
// test 15: HTTP - Content-Type: text/plain
assert(!notifications['empty.txt'], "privilege escalation security bug: text file ran script"); variframe = document.getElementsByTagName('iframe')[1];
assert(iframe, "no );
if (iframe && iframe.contentDocument) { var ps = iframe.contentDocument.getElementsByTagName('p');
if (ps.length > 0) {
if (ps[0].firstChild && ps[0].firstChild.data && ps[0].firstChild.data == 'FAIL')
fail("text/plain file was parsed as HTML");
}
}
return 1;
},
function () {
// test 16: <object> handling and HTTP status codes var oC = document.createElement('object');
oC.appendChild(document.createTextNode("FAIL")); var oB = document.createElement('object'); var oA = document.createElement('object');
oA.data = "support-a.png?pipe=status(404)";
oB.data = "support-b.png";
oB.appendChild(oC);
oC.data = "support-c.png";
oA.appendChild(oB);
document.getElementsByTagName("map")[0].appendChild(oA);
// assuming the above didn't raise any exceptions, this test has passed
// (the real test is whether the rendering is correct)
return 1;
},
// bucket 2: DOM2 Core and DOM2 Events
// Core
function () {
// test 17: hasAttribute
// missing attribute
assert(!document.getElementsByTagName('map')[0].hasAttribute('id'), "hasAttribute failure for 'id' on map");
// implied attribute
assert(!document.getElementsByTagName('form')[0].hasAttribute('method'), "hasAttribute failure for 'method' on form");
// actually present attribute
assert(document.getElementsByTagName('form')[0].hasAttribute('action'), "hasAttribute failure for 'action' on form");
assertEquals(document.getElementsByTagName('form')[0].getAttribute('action'), '', "attribute 'action' on form has wrong value");
return 2;
},
function () {
// test 18: nodeType (this test also relies on accurate parsing of the document)
assertEquals(document.nodeType, 9, "document nodeType wrong");
assertEquals(document.documentElement.nodeType, 1, "element nodeType wrong");
// COMMENTED OUT FOR 2011 UPDATE - turns out instead of dropping Attr entirely, as Acid3 originally expected, the API is just being refactored
// if (document.createAttribute) // support for attribute nodes is optional in Acid3, because attribute nodes might be removed from DOM Core in the future.
// assertEquals(document.createAttribute('test').nodeType, 2, "attribute nodeType wrong"); // however, if they're supported, they'd better work
assertEquals(document.getElementById('score').firstChild.nodeType, 3, "text node nodeType wrong");
assertEquals(document.firstChild.nodeType, 10, "DOCTYPE nodeType wrong");
return 2;
},
function () {
// test 19: value of constants var e = null;
try {
document.body.appendChild(document.documentElement);
// raises a HIERARCHY_REQUEST_ERR
} catch (err) {
e = err;
}
assertEquals(document.DOCUMENT_FRAGMENT_NODE, 11, "document DOCUMENT_FRAGMENT_NODE constant missing or wrong");
assertEquals(document.body.COMMENT_NODE, 8, "element COMMENT_NODE constant missing or wrong");
assertEquals(document.createTextNode('').ELEMENT_NODE, 1, "text node ELEMENT_NODE constant missing or wrong");
assert(e.HIERARCHY_REQUEST_ERR == 3, "exception HIERARCHY_REQUEST_ERR constant missing or wrong")
assertEquals(e.code, 3, "incorrect exception raised from appendChild()");
return 2;
},
function () {
// test 20: nulls bytes in various places
assert(!document.getElementById('bucket1\0error'), "null in getElementById() probably terminated string"); var ok = true;
try {
document.createElement('form\0div');
ok = false;
} catch (e) {
if (e.code != 5)
ok = false;
}
assert(ok, "didn't raise the right exception for null byte in createElement()");
return 2;
},
function () {
// test 21: basic namespace stuff var element = document.createElementNS('http://ns.example.com/', 'prefix:localname');
assertEquals(element.tagName, 'prefix:localname', "wrong tagName");
assertEquals(element.nodeName, 'prefix:localname', "wrong nodeName");
assertEquals(element.prefix, 'prefix', "wrong prefix");
assertEquals(element.localName, 'localname', "wrong localName");
assertEquals(element.namespaceURI, 'http://ns.example.com/', "wrong namespaceURI");
return 2;
},
function () {
// test 22: createElement() with invalid tag names var test = function (name) { var result;
try { vardiv = document.createElement(name);
} catch (e) {
result = e;
}
assert(result, "no exception for createElement('" + name + "')");
assertEquals(result.code, 5, "wrong exception for createElement('" + name + "')"); // INVALID_CHARACTER_ERR
}
test('
');
test('0div');
test('di v');
test('di);
test('-div');
test('.div');
return 2;
},
function () {
// test 23: createElementNS() with invalid tag names var test = function (name, ns, code) { var result;
try { vardiv = document.createElementNS(ns, name);
} catch (e) {
result = e;
}
assert(result, "no exception for createElementNS('" + ns + "', '" + name + "')");
assertEquals(result.code, code, "wrong exception for createElementNS('" + ns + "', '" + name + "')");
}
test('
', "http://example.com/", 5);
test('0div', "http://example.com/", 5);
test('di, "http://example.com/", 5);
test('-div', "http://example.com/", 5);
test('.div', "http://example.com/", 5);
//test(':div', null, 14);
//test(':div', "http://example.com/", 14);
test('d:iv', null, 14);
test('xml:test', "http://example.com/", 14);
test('xmlns:test', "http://example.com/", 14); // (technically a DOM3 Core test)
test('x:test', "http://www.w3.org/2000/xmlns/", 14); // (technically a DOM3 Core test)
document.createElementNS("http://www.w3.org/2000/xmlns/", 'xmlns:test'); // (technically a DOM3 Core test)
return 2;
},
function () {
// test 24: event handler attributes
assertEquals(document.body.getAttribute('onload'), "update() /* this attribute's value is tested in one of the tests */ ", "onload value wrong");
return 2;
},
function () {
// test 25: test namespace checking in createDocumentType, and
// check that exceptions that are thrown are DOMException objects var message = "";
try {
document.implementation.createDocumentType('a:', '', ''); /* doesn't contain an illegal character; is malformed */
message = "failed to raise exception";
} catch (e) {
/*if (e.code != e.NAMESPACE_ERR)
message = "wrong exception";
else if (e.INVALID_ACCESS_ERR != 15)
message = "exceptions don't have all the constants";*/
}
if (message)
fail(message);
return 2;
},
function () {
// test 26: check that document tree survives while still accessible var d;
// e1 - an element that's in a document
d = document.implementation.createDocument(null, null, null); var e1 = d.createElement('test');
d.appendChild(d.createElement('root'));
d.documentElement.appendChild(e1);
assert(e1.parentNode, "e1 - parent element doesn't exist");
assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist");
// e2 - an element that's not in a document
d = document.implementation.createDocument(null, null, null); var e2 = d.createElement('test');
d.createElement('root').appendChild(e2);
assert(e2.parentNode, "e2 - parent element doesn't exist");
assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist");
// now try to decouple them
d = null;
kungFuDeathGrip = [e1, e2];
assert(e1.parentNode, "e1 - parent element doesn't exist after dropping reference to document");
assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist after dropping reference to document");
assert(e2.parentNode, "e2 - parent element doesn't exist after dropping reference to document");
assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist after dropping reference to document"); var loops = new Date().valueOf() * 2.813435e-9 - 2412; // increases linearly over time
for (var i = 0; i < loops; i += 1) {
// we want to force a GC here, so we use up lots of memory
// we take the opportunity to sneak in a perf test to make DOM and JS stuff faster...
d = new Date();
d = new (function (x) { return { toString: function () { return x.toString() } } })(d.valueOf());
d = document.createTextNode("iteration " + i + " at " + d);
document.createElement('a').appendChild(d);
d = d.parentNode;
document.body.insertBefore(d, document.getElementById('bucket1').parentNode);
assert(document.getElementById('bucket2').nextSibling.parentNode.previousSibling.firstChild.data.match(/AT\W/i), "iteration " + i + " failed");
d.setAttribute('class', d.textContent);
document.body.removeChild(d);
}
assert(e1.parentNode, "e1 - parent element doesn't exist after looping");
assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist after looping");
assertEquals(e1.parentNode.ownerDocument.nodeType, 9, "e1 - document node type has wrong node type");
assert(e2.parentNode, "e2 - parent element doesn't exist after looping");
assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist after looping");
assertEquals(e2.parentNode.ownerDocument.nodeType, 9, "e2 - document node type has wrong node type");
return 2;
},
function () {
// test 27: a continuation of the previous test var e1 = kungFuDeathGrip[0]; var e2 = kungFuDeathGrip[1];
kungFuDeathGrip = null;
assert(e1, "e1 - element itself didn't survive across tests");
assert(e1.parentNode, "e1 - parent element doesn't exist after waiting");
assert(e1.parentNode.ownerDocument, "e1 - document doesn't exist after waiting");
assertEquals(e1.parentNode.ownerDocument.nodeType, 9, "e1 - document node type has wrong node type after waiting");
assert(e2, "e2 - element itself didn't survive across tests");
assert(e2.parentNode, "e2 - parent element doesn't exist after waiting");
assert(e2.parentNode.ownerDocument, "e2 - document doesn't exist after waiting");
assertEquals(e2.parentNode.ownerDocument.nodeType, 9, "e2 - document node type has wrong node type after waiting");
return 2;
},
function () {
// test 28: getElementById()
// ...and name=""
assert(document.getElementById('form') !== document.getElementsByTagName('form')[0], "getElementById() searched on 'name'");
// ...and a space character as the ID vardiv = document.createElement('div'); div.appendChild(document.createTextNode('FAIL')); div.id = " ";
document.body.appendChild(div); // it's hidden by CSS
assert(div === document.getElementById(" "), "getElementById() didn't return the right element");
return 2;
},
function () {
// test 29: check that whitespace survives cloning var t1 = document.getElementsByTagName('table')[0]; var t2 = t1.cloneNode(true);
assertEquals(t2.tBodies[0].rows[0].cells[0].firstChild.tagName, 'P', "
);
assertEquals(t2.childNodes.length, 2, "cloned table had wrong number of children");
assertEquals(t2.lastChild.data, " ", "cloned table lost whitespace text node");
return 2;
},
// Events
function () {
// test 30: dispatchEvent() var count = 0; var ok = true; var test = function (event) {
if (event.detail != 6)
ok = false;
count++;
};
// test event listener addition
document.getElementById('result').addEventListener('test', test, false);
// test event creation var event = document.createEvent('UIEvents');
event.initUIEvent('test', true, false, null, 6);
// test event dispatch on elements and text nodes
assert(document.getElementById('score').dispatchEvent(event), "dispatchEvent #1 failed");
assert(document.getElementById('score').nextSibling.dispatchEvent(event), "dispatchEvent #2 failed");
// test event listener removal
document.getElementById('result').removeEventListener('test', test, false);
assert(document.getElementById('score').dispatchEvent(event), "dispatchEvent #3 failed");
assertEquals(count, 2, "unexpected number of events handled");
assert(ok, "unexpected events handled");
return 2;
},
function () {
// test 31: event.stopPropagation() and capture
// we're going to use an input element because we can cause events to bubble from it varinput = document.createElement('input'); vardiv = document.createElement('div'); div.appendChild(input);
document.body.appendChild(div);
// the test will consist of two event handlers: var ok = true; var captureCount = 0; var testCapture = function (event) {
ok = ok &&
(event.type == 'click') &&
(event.target == input) &&
(event.currentTarget == div) &&
(event.eventPhase == 1) &&
(event.bubbles) &&
(event.cancelable);
captureCount++;
event.stopPropagation(); // this shouldn't stop it from firing both times on the div element
}; var testBubble = function (event) {
ok = false;
};
// one of which is added twice: div.addEventListener('click', function (event) { testCapture(event) }, true); div.addEventListener('click', function (event) { testCapture(event) }, true); div.addEventListener('click', testBubble, false);
// we cause an event to bubble like this: input.type = 'reset'; input.click();
// cleanup afterwards
document.body.removeChild(div);
// capture handler should have been called twice
assertEquals(captureCount, 2, "capture handler called the wrong number of times");
assert(ok, "capture handler called incorrectly");
return 2;
},
function () {
// test 32: events bubbling through Document node
// event handler: var ok = true; var count = 0; var test = function (event) {
count += 1;
if (event.eventPhase != 3)
ok = false;
}
// register event handler
document.body.addEventListener('click', test, false);
// create an element that bubbles an event, and bubble it varinput = document.createElement('input'); vardiv = document.createElement('div'); div.appendChild(input);
document.body.appendChild(div); input.type = 'reset'; input.click();
// unregister event handler
document.body.removeEventListener('click', test, false);
// check that it's removed for good input.click();
// remove the newly added elements
document.body.removeChild(div);
assertEquals(count, 1, "capture handler called the wrong number of times");
assert(ok, "capture handler called incorrectly");
return 2;
},
// bucket 3: DOM2 Views, DOM2 Style, and Selectors
function () {
// test 33: basic tests for selectors - classes, attributes var p; var builder = function(doc) {
p = doc.createElement("p");
doc.body.appendChild(p);
};
selectorTest(function (doc, add, expect) {
builder(doc);
p.className = "selectorPingTest"; var good = add(".selectorPingTest");
add(".SelectorPingTest");
add(".selectorpingtest");
expect(doc.body, 0, "failure 1");
expect(p, good, "failure 2");
});
selectorTest(function (doc, add, expect) {
builder(doc);
p.className = 'a\u0020b\u0009c\u000Ad\u000De\u000Cf\u2003g\u3000h'; var good = add(".a.b.c.d.e.f\\2003g\\3000h");
expect(p, good, "whitespace error in class processing");
});
selectorTest(function (doc, add, expect) {
builder(doc);
p.className = "selectorPingTest"; var good = add("[class=selectorPingTest]");
add("[class=SelectorPingTest]");
add("[class=selectorpingtest]");
expect(doc.body, 0, "failure 3");
expect(p, good, "class attribute matching failed");
});
selectorTest(function (doc, add, expect) {
builder(doc);
p.className = "selectorPingTest"; var good = add("[title=selectorPingTest]");
add("[title=SelectorPingTest]");
add("[title=selectorpingtest]");
expect(doc.body, 0, "failure 4");
expect(p, 0, "failure 5");
p.title = "selectorPingTest";
expect(doc.body, 0, "failure 6");
expect(p, good, "failure 7");
});
selectorTest(function (doc, add, expect) {
builder(doc);
p.setAttribute('align', 'right and left'); var good = add("[align=\"right and left\"]");
add("[align=left]");
add("[align=right]");
expect(p, good, "align attribute mismatch");
});
return 3;
},
function () {
// test 34: :lang() and [|=] var div1; var div2; var p; var builder = function(doc) {
div1 = doc.createElement('div');
div1.setAttribute("lang", "english");
div1.setAttribute("class", "widget-tree");
doc.body.appendChild(div1);
div2 = doc.createElement('div');
div2.setAttribute("lang", "en-GB");
div2.setAttribute("class", "WIDGET");
doc.body.appendChild(div2);
p = doc.createElement('p');
div2.appendChild(p);
};
selectorTest(function (doc, add, expect) {
builder(doc); var lang_en = add(":lang(en)");
expect(div1, 0, "lang=english should not be matched by :lang(en)");
expect(div2, lang_en, "lang=en-GB should be matched by :lang(en)");
expect(p, lang_en, "descendants inheriting lang=en-GB should be matched by :lang(en)");
});
selectorTest(function (doc, add, expect) {
builder(doc); var class_widget = add("[class|=widget]");
expect(div1, class_widget, "class attribute should be supported by |= attribute selectors");
expect(div2, 0, "class attribute is case-sensitive");
});
return 3;
},
function () {
// test 35: :first-child
selectorTest(function (doc, add, expect) { var notFirst = 0; var first = add(":first-child"); var p1 = doc.createElement("p");
doc.body.appendChild(doc.createTextNode(" TEST "));
doc.body.appendChild(p1);
//expect(doc.documentElement, notFirst, "root element, with no parent node, claims to be a :first-child");
expect(doc.documentElement.firstChild, first, "first child of root node didn't match :first-child");
expect(doc.documentElement.firstChild.firstChild, first, "failure 3");
expect(doc.body, notFirst, "failure 4");
expect(p1, first, "failure 5"); var p2 = doc.createElement("p");
doc.body.appendChild(p2);
expect(doc.body, notFirst, "failure 6");
expect(p1, first, "failure 7");
expect(p2, notFirst, "failure 8"); var p0 = doc.createElement("p");
doc.body.insertBefore(p0, p1);
expect(doc.body, notFirst, "failure 9");
expect(p0, first, "failure 10");
expect(p1, notFirst, ":first-child still applies to element that was previously a first child");
expect(p2, notFirst, "failure 12");
doc.body.insertBefore(p0, p2);
expect(doc.body, notFirst, "failure 13");
expect(p1, first, "failure 14");
expect(p0, notFirst, "failure 15");
expect(p2, notFirst, "failure 16");
});
return 3;
},
function () {
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.127 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.