12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298 |
- <!DOCTYPE HTML>
- <html>
- <head>
- <title>Test for CSS Selectors</title>
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
- </head>
- <body onload="run()">
- <p id="display"><iframe id="iframe" src="about:blank"></iframe><iframe id="cloneiframe" src="about:blank"></iframe></p>
- <pre id="test">
- <script class="testbody" type="text/javascript">
- SimpleTest.waitForExplicitFinish();
- SimpleTest.requestLongerTimeout(2);
- var cloneiframe;
- function run() {
- var iframe = document.getElementById("iframe");
- var ifwin = iframe.contentWindow;
- var ifdoc = iframe.contentDocument;
- cloneiframe = document.getElementById("cloneiframe");
- var style_elem = ifdoc.createElement("style");
- style_elem.setAttribute("type", "text/css");
- ifdoc.getElementsByTagName("head")[0].appendChild(style_elem);
- var style_text = ifdoc.createTextNode("");
- style_elem.appendChild(style_text);
- var gCounter = 0;
- /*
- * selector: the selector to test
- * body_contents: what to set the body's innerHTML to
- * match_fn: a function that, given the document object into which
- * body_contents has been inserted, produces an array of nodes that
- * should match selector
- * notmatch_fn: likewise, but for nodes that should not match
- * namespaces (optional): @namespace rules to be included in the sheet
- */
- function test_selector_in_html(selector, body_contents, match_fn, notmatch_fn, namespaces)
- {
- var zi = ++gCounter;
- if (typeof(body_contents) == "string") {
- ifdoc.body.innerHTML = body_contents;
- } else {
- // It's a function.
- ifdoc.body.innerHTML = "";
- body_contents(ifdoc.body);
- }
- if (!namespaces) {
- namespaces = "";
- }
- style_text.data = namespaces + selector + "{ z-index: " + zi + " }";
- var idx = style_text.parentNode.sheet.cssRules.length - 1;
- if (namespaces == "") {
- is(idx, 0, "unexpected rule index");
- }
- if (idx < 0 ||
- style_text.parentNode.sheet.cssRules[idx].type !=
- CSSRule.STYLE_RULE)
- {
- ok(false, "selector " + selector + " could not be parsed");
- return;
- }
- var should_match = match_fn(ifdoc);
- var should_not_match = notmatch_fn(ifdoc);
- if (should_match.length + should_not_match.length == 0) {
- ok(false, "nothing to check");
- }
- for (var i = 0; i < should_match.length; ++i) {
- var e = should_match[i];
- is(ifwin.getComputedStyle(e, "").zIndex, String(zi),
- "element in " + body_contents + " matched " + selector);
- }
- for (var i = 0; i < should_not_match.length; ++i) {
- var e = should_not_match[i];
- is(ifwin.getComputedStyle(e, "").zIndex, "auto",
- "element in " + body_contents + " did not match " + selector);
- }
- // Now, since we're here, may as well make sure serialization
- // works correctly. It need not produce the exact same text,
- // but it should produce a selector that matches the same
- // elements.
- zi = ++gCounter;
- var ser1 = style_text.parentNode.sheet.cssRules[idx].selectorText;
- style_text.data = namespaces + ser1 + "{ z-index: " + zi + " }";
- for (var i = 0; i < should_match.length; ++i) {
- var e = should_match[i];
- is(ifwin.getComputedStyle(e, "").zIndex, String(zi),
- "element in " + body_contents + " matched " + ser1 +
- " which is the reserialization of " + selector);
- }
- for (var i = 0; i < should_not_match.length; ++i) {
- var e = should_not_match[i];
- is(ifwin.getComputedStyle(e, "").zIndex, "auto",
- "element in " + body_contents + " did not match " + ser1 +
- " which is the reserialization of " + selector);
- }
- // But when we serialize the serialized result, we should get
- // the same text.
- var ser2 = style_text.parentNode.sheet.cssRules[idx].selectorText;
- is(ser2, ser1, "parse+serialize of selector \"" + selector +
- "\" is idempotent");
- ifdoc.body.innerHTML = "";
- style_text.data = "";
- // And now test that when we clone the style sheet, we end up
- // with the same selector (serializes to same string, and
- // matches the same things).
- zi = ++gCounter;
- var style_sheet = "data:text/css," +
- escape(namespaces + selector + "{ z-index: " + zi + " }");
- var style_sheet_link =
- "<link rel='stylesheet' href='" + style_sheet + "'>";
- var html_doc = "<!DOCTYPE HTML>" +
- style_sheet_link + style_sheet_link +
- "<body>";
- if (typeof(body_contents) == "string") {
- html_doc += body_contents;
- }
- var docurl = "data:text/html," + escape(html_doc);
- defer_clonedoc_tests(docurl, function() {
- var clonedoc = cloneiframe.contentDocument;
- var clonewin = cloneiframe.contentWindow;
- if (typeof(body_contents) != "string") {
- body_contents(clonedoc.body);
- }
- var links = clonedoc.getElementsByTagName("link");
- // cause a clone
- links[1].sheet.insertRule("#nonexistent { color: purple}", idx + 1);
- // remove the uncloned sheet
- links[0].parentNode.removeChild(links[0]);
- var should_match = match_fn(clonedoc);
- var should_not_match = notmatch_fn(clonedoc);
- if (should_match.length + should_not_match.length == 0) {
- ok(false, "nothing to check");
- }
- for (var i = 0; i < should_match.length; ++i) {
- var e = should_match[i];
- is(clonewin.getComputedStyle(e, "").zIndex, String(zi),
- "element in " + body_contents + " matched clone of " +
- selector);
- }
- for (var i = 0; i < should_not_match.length; ++i) {
- var e = should_not_match[i];
- is(clonewin.getComputedStyle(e, "").zIndex, "auto",
- "element in " + body_contents + " did not match clone of " +
- selector);
- }
- var ser3 = links[0].sheet.cssRules[idx].selectorText;
- is(ser3, ser1,
- "selector " + selector + " serializes correctly after cloning");
- });
- }
- function should_serialize_to(selector, serialization)
- {
- style_text.data = selector + "{ z-index: 0 }";
- is(style_text.parentNode.sheet.cssRules[0].selectorText,
- serialization,
- "selector '" + selector + "' should serialize to '" +
- serialization + "'.");
- }
- function test_parseable(selector)
- {
- ifdoc.body.innerHTML = "<p></p>";
- var zi = ++gCounter;
- style_text.data = "p, " + selector + "{ z-index: " + zi + " }";
- var should_match = ifdoc.getElementsByTagName("p")[0];
- var parsed = ifwin.getComputedStyle(should_match, "").zIndex == zi;
- ok(parsed, "selector " + selector + " was parsed");
- if (!parsed) {
- return;
- }
- // Test that it serializes to something that is also parseable.
- var ser1 = style_elem.sheet.cssRules[0].selectorText;
- zi = ++gCounter;
- style_text.data = ser1 + "{ z-index: " + zi + " }";
- is(ifwin.getComputedStyle(should_match, "").zIndex, String(zi),
- "serialization " + ser1 + " of selector p, " + selector +
- " was parsed");
- var ser2 = style_elem.sheet.cssRules[0].selectorText;
- is(ser2, ser1,
- "parse+serialize of selector " + selector + " is idempotent");
- ifdoc.body.innerHTML = "";
- style_text.data = "";
- // Test that it clones to the same thing it serializes to.
- zi = ++gCounter;
- var style_sheet = "data:text/css," +
- escape("p, " + selector + "{ z-index: " + zi + " }");
- var style_sheet_link =
- "<link rel='stylesheet' href='" + style_sheet + "'>";
- var html_doc = "<!DOCTYPE HTML>" +
- style_sheet_link + style_sheet_link +
- "<p></p>";
- var docurl = "data:text/html," + escape(html_doc);
- defer_clonedoc_tests(docurl, function() {
- var clonedoc = cloneiframe.contentDocument;
- var clonewin = cloneiframe.contentWindow;
- var links = clonedoc.getElementsByTagName("link");
- // cause a clone
- links[1].sheet.insertRule("#nonexistent { color: purple}", 0);
- // remove the uncloned sheet
- links[0].parentNode.removeChild(links[0]);
- should_match = clonedoc.getElementsByTagName("p")[0];
- is(clonewin.getComputedStyle(should_match, "").zIndex, String(zi),
- "selector " + selector + " was cloned correctly");
- var ser3 = links[0].sheet.cssRules[1].selectorText;
- is(ser3, ser1,
- "selector " + selector + " serializes correctly after cloning");
- });
- }
- function test_unparseable_via_api(selector)
- {
- try {
- // Test that it is also unparseable when followed by EOF.
- ifdoc.body.matches(selector);
- ok(false, "selector '" + selector + "' plus EOF is parse error");
- } catch(ex) {
- is(ex.name, "SyntaxError",
- "selector '" + selector + "' plus EOF is parse error");
- is(ex.code, DOMException.SYNTAX_ERR,
- "selector '" + selector + "' plus EOF is parse error");
- }
- }
- function test_parseable_via_api(selector)
- {
- var threw = false;
- try {
- // Test that a selector is parseable when followed by EOF.
- ifdoc.body.matches(selector);
- } catch(ex) {
- threw = true;
- }
- ok(!threw, "selector '" + selector + "' was parsed");
- }
- function test_balanced_unparseable(selector)
- {
- var zi1 = ++gCounter;
- var zi2 = ++gCounter;
- ifdoc.body.innerHTML = "<p></p><div></div>";
- style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }" +
- "div { z-index: " + zi2 + " }";
- var should_not_match = ifdoc.getElementsByTagName("p")[0];
- var should_match = ifdoc.getElementsByTagName("div")[0];
- is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
- "selector " + selector + " was a parser error");
- is(ifwin.getComputedStyle(should_match, "").zIndex, String(zi2),
- "selector " + selector + " error was recovered from");
- ifdoc.body.innerHTML = "";
- style_text.data = "";
- test_unparseable_via_api(selector);
- }
- function test_unbalanced_unparseable(selector)
- {
- var zi1 = ++gCounter;
- var zi2 = ++gCounter;
- ifdoc.body.innerHTML = "<p></p>";
- style_text.data = "p, " + selector + "{ z-index: " + zi1 + " }";
- var should_not_match = ifdoc.getElementsByTagName("p")[0];
- is(ifwin.getComputedStyle(should_not_match, "").zIndex, "auto",
- "selector " + selector + " was a parser error");
- is(style_text.parentNode.sheet.cssRules.length, 0,
- "sheet should have no rules since " + selector + " is parse error");
- ifdoc.body.innerHTML = "";
- style_text.data = "";
- test_unparseable_via_api(selector);
- }
- // [attr] selector
- test_parseable("[attr]")
- test_parseable_via_api("[attr");
- // [attr= ] selector
- test_parseable("[attr=\"x\"]");
- test_parseable("[attr='x']");
- test_parseable("[attr=x]");
- test_parseable("[attr=\"\"]");
- test_parseable("[attr='']");
- test_parseable("[attr=\"foo bar\"]");
- test_parseable_via_api("[attr=x");
- test_balanced_unparseable("[attr=]");
- test_balanced_unparseable("[attr=foo bar]");
- test_selector_in_html(
- '[title=""]',
- '<p title=""></p>'
- + '<div lang=" "></div><div lang="\t"></div><div lang="\n"></div>',
- function(doc) { return doc.getElementsByTagName("p"); },
- function(doc) { return doc.getElementsByTagName("div"); }
- );
- // [attr~= ] selector
- test_parseable("[attr~=\"x\"]");
- test_parseable("[attr~='x']");
- test_parseable("[attr~=x]");
- test_parseable("[attr~=\"\"]");
- test_parseable("[attr~='']");
- test_parseable("[attr~=\"foo bar\"]");
- test_parseable_via_api("[attr~=x");
- test_balanced_unparseable("[attr~=]");
- test_balanced_unparseable("[attr~=foo bar]");
- test_selector_in_html(
- '[class~="x x"]',
- '<div class="x x"></div><div class="x"></div><div class="x\tx"></div>div class="x\nx"></div>',
- function(doc) { return []; },
- function(doc) { return doc.getElementsByTagName("div"); }
- );
- // [attr|="x"]
- test_parseable('[attr|="x"]');
- test_parseable("[attr|='x']");
- test_parseable('[attr|=x]');
- test_parseable_via_api("[attr|=x");
- test_parseable('[attr|=""]');
- test_parseable("[attr|='']");
- test_balanced_unparseable('[attr|=]');
- test_selector_in_html(
- '[lang|=""]',
- '<p lang=""></p><p lang="-"></p><p lang="-GB"></p>'
- + '<div lang="en-GB"></div><div lang="en-"></div>',
- function(doc) { return doc.getElementsByTagName("p"); },
- function(doc) { return doc.getElementsByTagName("div"); }
- );
- // [attr$= ] selector
- test_parseable("[attr$=\"x\"]");
- test_parseable("[attr$='x']");
- test_parseable("[attr$=x]");
- test_parseable("[attr$=\"\"]");
- test_parseable("[attr$='']");
- test_parseable("[attr$=\"foo bar\"]");
- test_parseable_via_api("[attr$=x");
- test_balanced_unparseable("[attr$=]");
- test_balanced_unparseable("[attr$=foo bar]");
- // [attr^= ] selector
- test_parseable("[attr^=\"x\"]");
- test_parseable("[attr^='x']");
- test_parseable("[attr^=x]");
- test_parseable("[attr^=\"\"]");
- test_parseable("[attr^='']");
- test_parseable("[attr^=\"foo bar\"]");
- test_parseable_via_api("[attr^=x");
- test_balanced_unparseable("[attr^=]");
- test_balanced_unparseable("[attr^=foo bar]");
- // attr[*= ] selector
- test_parseable("[attr*=\"x\"]");
- test_parseable("[attr*='x']");
- test_parseable("[attr*=x]");
- test_parseable("[attr*=\"\"]");
- test_parseable("[attr*='']");
- test_parseable("[attr*=\"foo bar\"]");
- test_parseable_via_api("[attr^=x");
- test_balanced_unparseable("[attr*=]");
- test_balanced_unparseable("[attr*=foo bar]");
- // Bug 420814
- test_selector_in_html(
- "div ~ div p",
- "<div></div><div><div><p>match</p></div></div>",
- function(doc) { return doc.getElementsByTagName("p"); },
- function(doc) { return []; }
- );
- // Bug 420245
- test_selector_in_html(
- "p[attr$=\"\"]",
- "<p attr=\"foo\">This should not match</p>",
- function(doc) { return []; },
- function(doc) { return doc.getElementsByTagName("p"); }
- );
- test_selector_in_html(
- "div + p[attr~=\"\"]",
- "<div>Dummy</div><p attr=\"foo\">This should not match</p>",
- function(doc) { return []; },
- function(doc) { return doc.getElementsByTagName("p"); }
- );
- test_selector_in_html(
- "div[attr^=\"\"]",
- "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
- function(doc) { return []; },
- function(doc) { return doc.getElementsByTagName("div"); }
- );
- test_selector_in_html(
- "div[attr*=\"\"]",
- "<div attr=\"dummy1\">Dummy</div><div attr=\"dummy2\">Dummy</div>",
- function(doc) { return []; },
- function(doc) { return doc.getElementsByTagName("div"); }
- );
- // :nth-child(), etc.
- // Follow the whitespace rules as proposed in
- // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html
- test_balanced_unparseable(":nth-child()");
- test_balanced_unparseable(":nth-of-type( )");
- test_parseable(":nth-last-child( odd)");
- test_parseable(":nth-last-of-type(even )");
- test_parseable(":nth-child(n )");
- test_parseable(":nth-of-type( 2n)");
- test_parseable(":nth-last-child( -n)");
- test_parseable(":nth-last-of-type(-2n )");
- test_balanced_unparseable(":nth-child(- n)");
- test_balanced_unparseable(":nth-of-type(-2 n)");
- test_balanced_unparseable(":nth-last-of-type(2n1)");
- test_balanced_unparseable(":nth-child(2n++1)");
- test_balanced_unparseable(":nth-of-type(2n-+1)");
- test_balanced_unparseable(":nth-last-child(2n+-1)");
- test_balanced_unparseable(":nth-last-of-type(2n--1)");
- test_parseable(":nth-child( 3n + 1 )");
- test_parseable(":nth-child( +3n - 2 )");
- test_parseable(":nth-child( -n+ 6)");
- test_parseable(":nth-child( +6 )");
- test_balanced_unparseable(":nth-child(3 n)");
- test_balanced_unparseable(":nth-child(+ 2n)");
- test_balanced_unparseable(":nth-child(+ 2)");
- test_parseable(":nth-child(3)");
- test_parseable(":nth-of-type(-3)");
- test_parseable(":nth-last-child(+3)");
- test_parseable(":nth-last-of-type(0)");
- test_parseable(":nth-child(-0)");
- test_parseable(":nth-of-type(3n)");
- test_parseable(":nth-last-child(-3n)");
- test_parseable(":nth-last-of-type(+3n)");
- test_parseable(":nth-last-of-type(0n)");
- test_parseable(":nth-child(-0n)");
- test_parseable(":nth-of-type(n)");
- test_parseable(":nth-last-child(-n)");
- test_parseable(":nth-last-of-type(2n+1)");
- test_parseable(":nth-child(2n-1)");
- test_parseable(":nth-of-type(2n+0)");
- test_parseable(":nth-last-child(2n-0)");
- test_parseable(":nth-child(-0n+0)");
- test_parseable(":nth-of-type(n+1)");
- test_parseable(":nth-last-child(n-1)");
- test_parseable(":nth-last-of-type(-n+1)");
- test_parseable(":nth-child(-n-1)");
- test_balanced_unparseable(":nth-child(2-n)");
- test_balanced_unparseable(":nth-child(2-n-1)");
- test_balanced_unparseable(":nth-child(n-2-1)");
- // Bug 750388
- test_parseable(":nth-child(+n)");
- test_balanced_unparseable(":nth-child(+ n)");
- test_parseable(":nth-child(+n+2)");
- test_parseable(":nth-child(+n-2)");
- test_parseable(":nth-child(+n + 2)");
- test_parseable(":nth-child(+n - 2)");
- test_balanced_unparseable(":nth-child(+ n+2)");
- test_balanced_unparseable(":nth-child(+ n-2)");
- test_balanced_unparseable(":nth-child(+ n + 2)");
- test_balanced_unparseable(":nth-child(+ n - 2)");
- test_parseable(":nth-child(+n-100)");
- test_parseable(":nth-child(+n - 100)");
- test_balanced_unparseable(":nth-child(+ n-100)");
- test_balanced_unparseable(":nth-child(+-n+2)");
- test_balanced_unparseable(":nth-child(+ -n+2)");
- test_balanced_unparseable(":nth-child(+-n-100)");
- test_balanced_unparseable(":nth-child(+ -n-100)");
- test_balanced_unparseable(":nth-child(++n-100)");
- test_balanced_unparseable(":nth-child(-+n-100)");
- test_balanced_unparseable(":nth-child(++2n - 100)");
- test_balanced_unparseable(":nth-child(+-2n - 100)");
- test_balanced_unparseable(":nth-child(-+2n - 100)");
- test_balanced_unparseable(":nth-child(--2n - 100)");
- test_balanced_unparseable(":nth-child(+/**/+2n - 100)");
- test_balanced_unparseable(":nth-child(+/**/-2n - 100)");
- test_balanced_unparseable(":nth-child(-/**/+2n - 100)");
- test_balanced_unparseable(":nth-child(-/**/-2n - 100)");
- test_balanced_unparseable(":nth-child(+/**/+/**/2n - 100)");
- test_balanced_unparseable(":nth-child(+/**/-/**/2n - 100)");
- test_balanced_unparseable(":nth-child(-/**/+/**/2n - 100)");
- test_balanced_unparseable(":nth-child(-/**/-/**/2n - 100)");
- test_balanced_unparseable(":nth-child(++/**/2n - 100)");
- test_balanced_unparseable(":nth-child(+-/**/2n - 100)");
- test_balanced_unparseable(":nth-child(-+/**/2n - 100)");
- test_balanced_unparseable(":nth-child(--/**/2n - 100)");
- test_balanced_unparseable(":nth-child(-even)");
- test_balanced_unparseable(":nth-child(-odd)");
- test_balanced_unparseable(":nth-child(+even)");
- test_balanced_unparseable(":nth-child(+odd)");
- test_balanced_unparseable(":nth-child(+ even)");
- test_balanced_unparseable(":nth-child(+ odd)");
- test_balanced_unparseable(":nth-child(+-n)");
- test_balanced_unparseable(":nth-child(+-n-)");
- test_balanced_unparseable(":nth-child(-+n)");
- test_balanced_unparseable(":nth-child(+n--)");
- test_parseable(":nth-child(n+2)");
- test_parseable(":nth-child(n/**/+/**/2)");
- test_parseable(":nth-child(n-2)");
- test_parseable(":nth-child(n/**/-/**/2)");
- test_balanced_unparseable(":nth-child(n++2)");
- test_balanced_unparseable(":nth-child(n+-2)");
- test_balanced_unparseable(":nth-child(n-+2)");
- test_balanced_unparseable(":nth-child(n--2)");
- test_balanced_unparseable(":nth-child(n/**/++2)");
- test_balanced_unparseable(":nth-child(n/**/+-2)");
- test_balanced_unparseable(":nth-child(n/**/-+2)");
- test_balanced_unparseable(":nth-child(n/**/--2)");
- test_balanced_unparseable(":nth-child(n/**/+/**/+2)");
- test_balanced_unparseable(":nth-child(n/**/+/**/-2)");
- test_balanced_unparseable(":nth-child(n/**/-/**/+2)");
- test_balanced_unparseable(":nth-child(n/**/-/**/-2)");
- test_balanced_unparseable(":nth-child(n+/**/+2)");
- test_balanced_unparseable(":nth-child(n+/**/-2)");
- test_balanced_unparseable(":nth-child(n-/**/+2)");
- test_balanced_unparseable(":nth-child(n-/**/-2)");
- test_balanced_unparseable(":nth-child(n++/**/2)");
- test_balanced_unparseable(":nth-child(n+-/**/2)");
- test_balanced_unparseable(":nth-child(n-+/**/2)");
- test_balanced_unparseable(":nth-child(n--/**/2)");
- test_balanced_unparseable(":nth-child(n/**/++/**/2)");
- test_balanced_unparseable(":nth-child(n/**/+-/**/2)");
- test_balanced_unparseable(":nth-child(n/**/-+/**/2)");
- test_balanced_unparseable(":nth-child(n/**/--/**/2)");
- test_balanced_unparseable(":nth-child(n/**/+/**/+/**/2)");
- test_balanced_unparseable(":nth-child(n/**/+/**/-/**/2)");
- test_balanced_unparseable(":nth-child(n/**/-/**/+/**/2)");
- test_balanced_unparseable(":nth-child(n/**/-/**/-/**/2)");
- test_balanced_unparseable(":nth-child(n+/**/+/**/2)");
- test_balanced_unparseable(":nth-child(n+/**/-/**/2)");
- test_balanced_unparseable(":nth-child(n-/**/+/**/2)");
- test_balanced_unparseable(":nth-child(n-/**/-/**/2)");
- test_parseable(":nth-child(2n+2)");
- test_parseable(":nth-child(2n/**/+/**/2)");
- test_parseable(":nth-child(2n-2)");
- test_parseable(":nth-child(2n/**/-/**/2)");
- test_balanced_unparseable(":nth-child(2n++2)");
- test_balanced_unparseable(":nth-child(2n+-2)");
- test_balanced_unparseable(":nth-child(2n-+2)");
- test_balanced_unparseable(":nth-child(2n--2)");
- test_balanced_unparseable(":nth-child(2n/**/++2)");
- test_balanced_unparseable(":nth-child(2n/**/+-2)");
- test_balanced_unparseable(":nth-child(2n/**/-+2)");
- test_balanced_unparseable(":nth-child(2n/**/--2)");
- test_balanced_unparseable(":nth-child(2n/**/+/**/+2)");
- test_balanced_unparseable(":nth-child(2n/**/+/**/-2)");
- test_balanced_unparseable(":nth-child(2n/**/-/**/+2)");
- test_balanced_unparseable(":nth-child(2n/**/-/**/-2)");
- test_balanced_unparseable(":nth-child(2n+/**/+2)");
- test_balanced_unparseable(":nth-child(2n+/**/-2)");
- test_balanced_unparseable(":nth-child(2n-/**/+2)");
- test_balanced_unparseable(":nth-child(2n-/**/-2)");
- test_balanced_unparseable(":nth-child(2n++/**/2)");
- test_balanced_unparseable(":nth-child(2n+-/**/2)");
- test_balanced_unparseable(":nth-child(2n-+/**/2)");
- test_balanced_unparseable(":nth-child(2n--/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/++/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/+-/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/-+/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/--/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/+/**/+/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/+/**/-/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/-/**/+/**/2)");
- test_balanced_unparseable(":nth-child(2n/**/-/**/-/**/2)");
- test_balanced_unparseable(":nth-child(2n+/**/+/**/2)");
- test_balanced_unparseable(":nth-child(2n+/**/-/**/2)");
- test_balanced_unparseable(":nth-child(2n-/**/+/**/2)");
- test_balanced_unparseable(":nth-child(2n-/**/-/**/2)");
- test_parseable(":nth-child(+/**/n+2)");
- test_parseable(":nth-child(+n/**/+2)");
- test_parseable(":nth-child(+n/**/+2)");
- test_parseable(":nth-child(+n+/**/2)");
- test_parseable(":nth-child(+n+2/**/)");
- test_parseable(":nth-child(+1/**/n+2)");
- test_parseable(":nth-child(+1n/**/+2)");
- test_parseable(":nth-child(+1n/**/+2)");
- test_parseable(":nth-child(+1n+/**/2)");
- test_parseable(":nth-child(+1n+2/**/)");
- test_parseable(":nth-child(-/**/n+2)");
- test_parseable(":nth-child(-n/**/+2)");
- test_parseable(":nth-child(-n/**/+2)");
- test_parseable(":nth-child(-n+/**/2)");
- test_parseable(":nth-child(-n+2/**/)");
- test_parseable(":nth-child(-1/**/n+2)");
- test_parseable(":nth-child(-1n/**/+2)");
- test_parseable(":nth-child(-1n/**/+2)");
- test_parseable(":nth-child(-1n+/**/2)");
- test_parseable(":nth-child(-1n+2/**/)");
- test_balanced_unparseable(":nth-child(-/**/ n+2)");
- test_balanced_unparseable(":nth-child(- /**/n+2)");
- test_balanced_unparseable(":nth-child(+/**/ n+2)");
- test_balanced_unparseable(":nth-child(+ /**/n+2)");
- test_parseable(":nth-child(+/**/n-2)");
- test_parseable(":nth-child(+n/**/-2)");
- test_parseable(":nth-child(+n/**/-2)");
- test_parseable(":nth-child(+n-/**/2)");
- test_parseable(":nth-child(+n-2/**/)");
- test_parseable(":nth-child(+1/**/n-2)");
- test_parseable(":nth-child(+1n/**/-2)");
- test_parseable(":nth-child(+1n/**/-2)");
- test_parseable(":nth-child(+1n-/**/2)");
- test_parseable(":nth-child(+1n-2/**/)");
- test_parseable(":nth-child(-/**/n-2)");
- test_parseable(":nth-child(-n/**/-2)");
- test_parseable(":nth-child(-n/**/-2)");
- test_parseable(":nth-child(-n-/**/2)");
- test_parseable(":nth-child(-n-2/**/)");
- test_parseable(":nth-child(-1/**/n-2)");
- test_parseable(":nth-child(-1n/**/-2)");
- test_parseable(":nth-child(-1n/**/-2)");
- test_parseable(":nth-child(-1n-/**/2)");
- test_parseable(":nth-child(-1n-2/**/)");
- test_balanced_unparseable(":nth-child(-/**/ n-2)");
- test_balanced_unparseable(":nth-child(- /**/n-2)");
- test_balanced_unparseable(":nth-child(+/**/ n-2)");
- test_balanced_unparseable(":nth-child(+ /**/n-2)");
- test_parseable(":nth-child(+/**/N-2)");
- test_parseable(":nth-child(+N/**/-2)");
- test_parseable(":nth-child(+N/**/-2)");
- test_parseable(":nth-child(+N-/**/2)");
- test_parseable(":nth-child(+N-2/**/)");
- test_parseable(":nth-child(+1/**/N-2)");
- test_parseable(":nth-child(+1N/**/-2)");
- test_parseable(":nth-child(+1N/**/-2)");
- test_parseable(":nth-child(+1N-/**/2)");
- test_parseable(":nth-child(+1N-2/**/)");
- test_parseable(":nth-child(-/**/N-2)");
- test_parseable(":nth-child(-N/**/-2)");
- test_parseable(":nth-child(-N/**/-2)");
- test_parseable(":nth-child(-N-/**/2)");
- test_parseable(":nth-child(-N-2/**/)");
- test_parseable(":nth-child(-1/**/N-2)");
- test_parseable(":nth-child(-1N/**/-2)");
- test_parseable(":nth-child(-1N/**/-2)");
- test_parseable(":nth-child(-1N-/**/2)");
- test_parseable(":nth-child(-1N-2/**/)");
- test_balanced_unparseable(":nth-child(-/**/ N-2)");
- test_balanced_unparseable(":nth-child(- /**/N-2)");
- test_balanced_unparseable(":nth-child(+/**/ N-2)");
- test_balanced_unparseable(":nth-child(+ /**/N-2)");
- test_parseable(":nth-child( +n + 1 )");
- test_parseable(":nth-child( +/**/n + 1 )");
- test_parseable(":nth-child( -/**/2/**/n/**/+/**/4 )");
- test_balanced_unparseable(":nth-child( -/**/ 2/**/n/**/+/**/4 )");
- test_balanced_unparseable(":nth-child( -/**/2 /**/n/**/+/**/4 )");
- test_balanced_unparseable(":nth-child( -/**/2/**/ n/**/+/**/4 )");
- test_parseable(":nth-child( -/**/2/**/n /**/+/**/4 )");
- test_parseable(":nth-child( -/**/2/**/n/**/ +/**/4 )");
- test_parseable(":nth-child(+1/**/n-1)");
- test_parseable(":nth-child(1/**/n-1)");
- // bug 876570
- test_balanced_unparseable(":nth-child(+2n-)");
- test_balanced_unparseable(":nth-child(+n-)");
- test_balanced_unparseable(":nth-child(-2n-)");
- test_balanced_unparseable(":nth-child(-n-)");
- test_balanced_unparseable(":nth-child(2n-)");
- test_balanced_unparseable(":nth-child(n-)");
- test_balanced_unparseable(":nth-child(+2n+)");
- test_balanced_unparseable(":nth-child(+n+)");
- test_balanced_unparseable(":nth-child(-2n+)");
- test_balanced_unparseable(":nth-child(-n+)");
- test_balanced_unparseable(":nth-child(2n+)");
- test_balanced_unparseable(":nth-child(n+)");
- // exercise the an+b matching logic particularly hard for
- // :nth-child() (since we know we use the same code for all 4)
- var seven_ps = "<p></p><p></p><p></p><p></p><p></p><p></p><p></p>";
- function pset(indices) { // takes an array of 1-based indices
- return function pset_filter(doc) {
- var a = doc.getElementsByTagName("p");
- var result = [];
- for (var i in indices)
- result.push(a[indices[i] - 1]);
- return result;
- }
- }
- test_selector_in_html(":nth-child(0)", seven_ps,
- pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(-3)", seven_ps,
- pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(3)", seven_ps,
- pset([3]), pset([1, 2, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(0n+3)", seven_ps,
- pset([3]), pset([1, 2, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(-0n+3)", seven_ps,
- pset([3]), pset([1, 2, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(8)", seven_ps,
- pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(odd)", seven_ps,
- pset([1, 3, 5, 7]), pset([2, 4, 6]));
- test_selector_in_html(":nth-child(even)", seven_ps,
- pset([2, 4, 6]), pset([1, 3, 5, 7]));
- test_selector_in_html(":nth-child(2n-1)", seven_ps,
- pset([1, 3, 5, 7]), pset([2, 4, 6]));
- test_selector_in_html(":nth-child( 2n - 1 )", seven_ps,
- pset([1, 3, 5, 7]), pset([2, 4, 6]));
- test_selector_in_html(":nth-child(2n+1)", seven_ps,
- pset([1, 3, 5, 7]), pset([2, 4, 6]));
- test_selector_in_html(":nth-child( 2n + 1 )", seven_ps,
- pset([1, 3, 5, 7]), pset([2, 4, 6]));
- test_selector_in_html(":nth-child(2n+0)", seven_ps,
- pset([2, 4, 6]), pset([1, 3, 5, 7]));
- test_selector_in_html(":nth-child(2n-0)", seven_ps,
- pset([2, 4, 6]), pset([1, 3, 5, 7]));
- test_selector_in_html(":nth-child(-n+3)", seven_ps,
- pset([1, 2, 3]), pset([4, 5, 6, 7]));
- test_selector_in_html(":nth-child(-n-3)", seven_ps,
- pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":nth-child(n)", seven_ps,
- pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
- test_selector_in_html(":nth-child(n-3)", seven_ps,
- pset([1, 2, 3, 4, 5, 6, 7]), pset([]));
- test_selector_in_html(":nth-child(n+3)", seven_ps,
- pset([3, 4, 5, 6, 7]), pset([1, 2]));
- test_selector_in_html(":nth-child(2n+3)", seven_ps,
- pset([3, 5, 7]), pset([1, 2, 4, 6]));
- test_selector_in_html(":nth-child(2n)", seven_ps,
- pset([2, 4, 6]), pset([1, 3, 5, 7]));
- test_selector_in_html(":nth-child(2n-3)", seven_ps,
- pset([1, 3, 5, 7]), pset([2, 4, 6]));
- test_selector_in_html(":nth-child(-1n+3)", seven_ps,
- pset([1, 2, 3]), pset([4, 5, 6, 7]));
- test_selector_in_html(":nth-child(-2n+3)", seven_ps,
- pset([1, 3]), pset([2, 4, 5, 6, 7]));
- // And a few spot-checks for the other :nth-* selectors
- test_selector_in_html(":nth-child(4n+1)", seven_ps,
- pset([1, 5]), pset([2, 3, 4, 6, 7]));
- test_selector_in_html(":nth-last-child(4n+1)", seven_ps,
- pset([3, 7]), pset([1, 2, 4, 5, 6]));
- test_selector_in_html(":nth-of-type(4n+1)", seven_ps,
- pset([1, 5]), pset([2, 3, 4, 6, 7]));
- test_selector_in_html(":nth-last-of-type(4n+1)", seven_ps,
- pset([3, 7]), pset([1, 2, 4, 5, 6]));
- test_selector_in_html(":nth-child(6)", seven_ps,
- pset([6]), pset([1, 2, 3, 4, 5, 7]));
- test_selector_in_html(":nth-last-child(6)", seven_ps,
- pset([2]), pset([1, 3, 4, 5, 6, 7]));
- test_selector_in_html(":nth-of-type(6)", seven_ps,
- pset([6]), pset([1, 2, 3, 4, 5, 7]));
- test_selector_in_html(":nth-last-of-type(6)", seven_ps,
- pset([2]), pset([1, 3, 4, 5, 6, 7]));
- // Test [first|last|only]-[child|node|of-type]
- var interesting_doc = "<!----> <div id='p1'> <!---->x<p id='s1'></p> <!----><p id='s2'></p> <!----></div> <!----><p id='p2'> <!----><span id='s3'></span> <!----><span id='s4'></span> <!---->x</p> <!----><div id='p3'> <!----><p id='s5'></p> <!----></div> <!---->";
- function idset(ids) { // takes an array of ids
- return function idset_filter(doc) {
- var result = [];
- for (var id of ids)
- result.push(doc.getElementById(id));
- return result;
- }
- }
- function classset(classes) { // takes an array of classes
- return function classset_filter(doc) {
- var i, j, els;
- var result = [];
- for (i = 0; i < classes.length; i++) {
- els = doc.getElementsByClassName(classes[i]);
- for (j = 0; j < els.length; j++) {
- result.push(els[j]);
- }
- }
- return result;
- }
- }
- function emptyset(doc) { return []; }
- test_parseable(":first-child");
- test_parseable(":last-child");
- test_parseable(":only-child");
- test_parseable(":-moz-first-node");
- test_parseable(":-moz-last-node");
- test_parseable(":first-of-type");
- test_parseable(":last-of-type");
- test_parseable(":only-of-type");
- test_selector_in_html(":first-child", seven_ps,
- pset([1]), pset([2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":first-child", interesting_doc,
- idset(["p1", "s1", "s3", "s5"]),
- idset(["s2", "p2", "s4", "p3"]));
- test_selector_in_html(":-moz-first-node", interesting_doc,
- idset(["p1", "s3", "s5"]),
- idset(["s1", "s2", "p2", "s4", "p3"]));
- test_selector_in_html(":last-child", seven_ps,
- pset([7]), pset([1, 2, 3, 4, 5, 6]));
- test_selector_in_html(":last-child", interesting_doc,
- idset(["s2", "s4", "p3", "s5"]),
- idset(["p1", "s1", "p2", "s3"]));
- test_selector_in_html(":-moz-last-node", interesting_doc,
- idset(["s2", "p3", "s5"]),
- idset(["p1", "s1", "p2", "s3", "s4"]));
- test_selector_in_html(":only-child", seven_ps,
- pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":only-child", interesting_doc,
- idset(["s5"]),
- idset(["p1", "s1", "s2", "p2", "s3", "s4", "p3"]));
- test_selector_in_html(":first-of-type", seven_ps,
- pset([1]), pset([2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":first-of-type", interesting_doc,
- idset(["p1", "s1", "p2", "s3", "s5"]),
- idset(["s2", "s4", "p3"]));
- test_selector_in_html(":last-of-type", seven_ps,
- pset([7]), pset([1, 2, 3, 4, 5, 6]));
- test_selector_in_html(":last-of-type", interesting_doc,
- idset(["s2", "p2", "s4", "p3", "s5"]),
- idset(["p1", "s1", "s3"]));
- test_selector_in_html(":only-of-type", seven_ps,
- pset([]), pset([1, 2, 3, 4, 5, 6, 7]));
- test_selector_in_html(":only-of-type", interesting_doc,
- idset(["p2", "s5"]),
- idset(["p1", "s1", "s2", "s3", "s4", "p3"]));
- // And a bunch of tests for the of-type aspect of :nth-of-type() and
- // :nth-last-of-type(). Note that the last div here contains two
- // children.
- var mixed_elements="<p></p><p></p><div></div><p></p><div><p></p><address></address></div><address></address>";
- function pdaset(ps, divs, addresses) { // takes an array of 1-based indices
- var l = { p: ps, div: divs, address: addresses };
- return function pdaset_filter(doc) {
- var result = [];
- for (var tag in l) {
- var a = doc.getElementsByTagName(tag);
- var indices = l[tag];
- for (var i in indices)
- result.push(a[indices[i] - 1]);
- }
- return result;
- }
- }
- test_selector_in_html(":nth-of-type(odd)", mixed_elements,
- pdaset([1, 3, 4], [1], [1, 2]),
- pdaset([2], [2], []));
- test_selector_in_html(":nth-of-type(2n-0)", mixed_elements,
- pdaset([2], [2], []),
- pdaset([1, 3, 4], [1], [1, 2]));
- test_selector_in_html(":nth-last-of-type(even)", mixed_elements,
- pdaset([2], [1], []),
- pdaset([1, 3, 4], [2], [1, 2]));
- // Test greediness of descendant combinators.
- var four_children="<div id='a'><div id='b'><div id='c'><div id='d'><\/div><\/div><\/div><\/div>";
- test_selector_in_html("#a > div div", four_children,
- idset(["c", "d"]), idset(["a", "b"]));
- test_selector_in_html("#a > #b div", four_children,
- idset(["c", "d"]), idset(["a", "b"]));
- test_selector_in_html("#a div > div", four_children,
- idset(["c", "d"]), idset(["a", "b"]));
- test_selector_in_html("#a #b > div", four_children,
- idset(["c"]), idset(["a", "b", "d"]));
- test_selector_in_html("#a > #b div", four_children,
- idset(["c", "d"]), idset(["a", "b"]));
- test_selector_in_html("#a #c > div", four_children,
- idset(["d"]), idset(["a", "b", "c"]));
- test_selector_in_html("#a > #c div", four_children,
- idset([]), idset(["a", "b", "c", "d"]));
- // More descendant combinator greediness (bug 511147)
- test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div></div>',
- classset(["match"]), classset(["a", "b"]));
- test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="x"></div><div class="match"></div></div>',
- classset(["match"]), classset(["a", "b", "x"]));
- test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"><p>filler filler <i>filler</i> filler</p></div><div class="match"></div></div>',
- classset(["match"]), classset(["a", "b", "x"]));
- test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="x"><p>filler filler <i>filler</i> filler</p></div><div></div><div class="b"></div><div></div><div class="x"><p>filler filler <i>filler</i> filler</p></div><div class="match"></div></div>',
- classset(["match"]), classset(["a", "b", "x"]));
- test_selector_in_html(".a > .b ~ .match", '<div class="a"><div class="b"></div><div class="match"></div><div class="match"></div></div>',
- classset(["match"]), classset(["a", "b"]));
- test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div></div>',
- emptyset, classset(["a", "b", "nomatch"]));
- test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div><div class="b"></div><div class="nomatch"></div></div><div class="nomatch"></div></div>',
- emptyset, classset(["a", "b", "nomatch"]));
- test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div><div><div class="nomatch"></div></div><div></div></div>',
- emptyset, classset(["a", "b", "nomatch"]));
- test_selector_in_html(".a > .b ~ .nomatch", '<div class="a"><div class="b"></div></div><div class="nomatch"></div>',
- emptyset, classset(["a", "b", "nomatch"]));
- // Test serialization of pseudo-elements.
- should_serialize_to("p::first-letter", "p::first-letter");
- should_serialize_to("p:first-letter", "p::first-letter");
- should_serialize_to("div>p:first-letter", "div > p::first-letter");
- should_serialize_to("span +div:first-line", "span + div::first-line");
- should_serialize_to("input::placeholder", "input::placeholder");
- should_serialize_to("input:placeholder-shown", "input:placeholder-shown");
- // Test serialization of non CSS2 pseudo-element.
- should_serialize_to("input::-moz-placeholder", "input::-moz-placeholder");
- // Test default namespaces, including inside :not().
- var html_default_ns = "@namespace url(http://www.w3.org/1999/xhtml);";
- var html_ns = "@namespace html url(http://www.w3.org/1999/xhtml);";
- var xul_default_ns = "@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);";
- var single_a = "<a id='a' href='data:text/plain,this_better_be_unvisited'></a>";
- var set_single = idset(['a']);
- var empty_set = idset([]);
- test_selector_in_html("a", single_a, set_single, empty_set,
- html_default_ns);
- test_selector_in_html("a", single_a, empty_set, set_single,
- xul_default_ns);
- test_selector_in_html("*|a", single_a, set_single, empty_set,
- xul_default_ns);
- test_selector_in_html("html|a", single_a, set_single, empty_set,
- xul_default_ns + html_ns);
- // Type selectors inside :not() bring in default namespaces, but
- // non-type selectors don't.
- test_selector_in_html("*|a:not(*)", single_a, set_single, empty_set,
- xul_default_ns);
- test_selector_in_html("*|a:not(a)", single_a, set_single, empty_set,
- xul_default_ns);
- test_selector_in_html("*|a:not(*|*)", single_a, empty_set, set_single,
- xul_default_ns);
- test_selector_in_html("*|a:not(*|a)", single_a, empty_set, set_single,
- xul_default_ns);
- test_selector_in_html("*|a:not(:link)", single_a + "<a id='b'></a>",
- idset(["b"]), set_single,
- xul_default_ns);
- test_selector_in_html("*|a:not(:visited)", single_a + "<a id='b'></a>",
- idset(["a", "b"]), empty_set,
- xul_default_ns);
- test_selector_in_html("*|a:not(html|*)", single_a, empty_set, set_single,
- xul_default_ns + html_ns);
- test_selector_in_html("*|a:not(html|a)", single_a, empty_set, set_single,
- xul_default_ns + html_ns);
- test_selector_in_html("*|a:not(|*)", single_a, set_single, empty_set,
- xul_default_ns + html_ns);
- test_selector_in_html("*|a:not(|a)", single_a, set_single, empty_set,
- xul_default_ns + html_ns);
- test_selector_in_html("html|a:not(|*)", single_a, set_single, empty_set,
- xul_default_ns + html_ns);
- test_selector_in_html("html|a:not(|a)", single_a, set_single, empty_set,
- xul_default_ns + html_ns);
- test_selector_in_html("html|a:not(*|*)", single_a, empty_set, set_single,
- xul_default_ns + html_ns);
- test_selector_in_html("html|a:not(*|a)", single_a, empty_set, set_single,
- xul_default_ns + html_ns);
- // Test -moz-locale-dir
- test_parseable(":-moz-locale-dir(ltr)");
- test_parseable(":-moz-locale-dir(rtl)");
- test_parseable(":-moz-locale-dir(rTl)");
- test_parseable(":-moz-locale-dir(LTR)");
- test_parseable(":-moz-locale-dir(other)");
- if (document.body.matches(":-moz-locale-dir(ltr)")) {
- test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:-moz-locale-dir(ltR)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:-moz-locale-dir(LTR)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
- empty_set, set_single);
- } else {
- test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:-moz-locale-dir(rtL)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:-moz-locale-dir(RTL)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
- empty_set, set_single);
- }
- test_selector_in_html("a:-moz-locale-dir(other)", single_a,
- empty_set, set_single);
- test_balanced_unparseable(":-moz-locale-dir()");
- test_balanced_unparseable(":-moz-locale-dir(())");
- test_balanced_unparseable(":-moz-locale-dir(3())");
- test_balanced_unparseable(":-moz-locale-dir(f{})");
- test_balanced_unparseable(":-moz-locale-dir('ltr')");
- test_balanced_unparseable(":-moz-locale-dir(ltr, other)");
- test_balanced_unparseable(":-moz-locale-dir(ltr other)");
- test_balanced_unparseable(":-moz-locale-dir");
- // Test :dir()
- test_parseable(":dir(ltr)");
- test_parseable(":dir(rtl)");
- test_parseable(":dir(rTl)");
- test_parseable(":dir(LTR)");
- test_parseable(":dir(other)");
- if (document.body.matches(":dir(ltr)")) {
- test_selector_in_html("a:dir(LTr)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:dir(ltR)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:dir(LTR)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:dir(RTl)", single_a,
- empty_set, set_single);
- } else {
- test_selector_in_html("a:dir(RTl)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:dir(rtL)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:dir(RTL)", single_a,
- set_single, empty_set);
- test_selector_in_html("a:dir(LTr)", single_a,
- empty_set, set_single);
- }
- test_selector_in_html("a:dir(other)", single_a,
- empty_set, set_single);
- test_balanced_unparseable(":dir()");
- test_balanced_unparseable(":dir(())");
- test_balanced_unparseable(":dir(3())");
- test_balanced_unparseable(":dir(f{})");
- test_balanced_unparseable(":dir('ltr')");
- test_balanced_unparseable(":dir(ltr, other)");
- test_balanced_unparseable(":dir(ltr other)");
- test_balanced_unparseable(":dir");
- // Test -moz-lwtheme and -moz-lwtheme-[darktext|brighttext]
- test_parseable(":-moz-lwtheme");
- test_parseable(":-moz-lwtheme-brighttext");
- test_parseable(":-moz-lwtheme-darktext");
- test_parseable(":-moz-tree-row(selected)");
- test_parseable("::-moz-tree-row(selected)");
- test_parseable(":-moz-tree-row(selected focus)");
- test_parseable(":-moz-tree-row(selected , focus)");
- test_parseable("::-moz-tree-row(selected ,focus)");
- test_parseable(":-moz-tree-row(selected, focus)");
- test_parseable("::-moz-tree-row(selected,focus)");
- test_parseable(":-moz-tree-row(selected focus)");
- test_parseable("::-moz-tree-row(selected , focus)");
- test_parseable("::-moz-tree-twisty( hover open )");
- test_balanced_unparseable("::-moz-tree-row(selected {[]} )");
- test_balanced_unparseable(":-moz-tree-twisty(open())");
- test_balanced_unparseable("::-moz-tree-twisty(hover ())");
- test_parseable(":-moz-window-inactive");
- test_parseable("div p:-moz-window-inactive:hover span");
- // Chrome-only
- test_unbalanced_unparseable(":-moz-browser-frame");
- // Plugin pseudoclasses are chrome-only:
- test_unbalanced_unparseable(":-moz-type-unsupported");
- test_unbalanced_unparseable(":-moz-user-disabled");
- test_unbalanced_unparseable(":-moz-suppressed");
- test_unbalanced_unparseable(":-moz-type-unsupported");
- test_unbalanced_unparseable(":-moz-type-unsupported-platform");
- test_unbalanced_unparseable(":-moz-handler-clicktoplay");
- test_unbalanced_unparseable(":-moz-handler-vulnerable-updatable");
- test_unbalanced_unparseable(":-moz-handler-vulnerable-no-update");
- test_unbalanced_unparseable(":-moz-handler-disabled");
- test_unbalanced_unparseable(":-moz-handler-blocked");
- test_unbalanced_unparseable(":-moz-handler-crashed");
- // We're not in a UA sheet, so this should be invalid.
- test_balanced_unparseable(":-moz-native-anonymous");
- // Case sensitivity of tag selectors
- function setup_cased_spans(body) {
- var data = [
- { tag: "span" },
- { tag: "sPaN" },
- { tag: "Span" },
- { tag: "SPAN" },
- { ns: "http://www.w3.org/1999/xhtml", tag: "span" },
- { ns: "http://www.w3.org/1999/xhtml", tag: "sPaN" },
- { ns: "http://www.w3.org/1999/xhtml", tag: "Span" },
- { ns: "http://www.w3.org/1999/xhtml", tag: "SPAN" },
- { ns: "http://example.com/useless", tag: "span" },
- { ns: "http://example.com/useless", tag: "sPaN" },
- { ns: "http://example.com/useless", tag: "Span" },
- { ns: "http://example.com/useless", tag: "SPAN" },
- ]
- for (var i in data) {
- var ent = data[i];
- var elem;
- if ("ns" in ent) {
- elem = body.ownerDocument.createElementNS(ent.ns, ent.tag);
- } else {
- elem = body.ownerDocument.createElement(ent.tag);
- }
- body.appendChild(elem);
- }
- }
- function bodychildset(indices) {
- return function bodychildset_filter(doc) {
- var body = doc.body;
- var result = [];
- for (var i in indices) {
- result.push(body.childNodes[indices[i]]);
- }
- return result;
- }
- }
- test_selector_in_html("span", setup_cased_spans,
- bodychildset([0, 1, 2, 3, 4, 8]),
- bodychildset([5, 6, 7, 9, 10, 11]));
- test_selector_in_html("sPaN", setup_cased_spans,
- bodychildset([0, 1, 2, 3, 4, 9]),
- bodychildset([5, 6, 7, 8, 10, 11]));
- test_selector_in_html("Span", setup_cased_spans,
- bodychildset([0, 1, 2, 3, 4, 10]),
- bodychildset([5, 6, 7, 8, 9, 11]));
- test_selector_in_html("SPAN", setup_cased_spans,
- bodychildset([0, 1, 2, 3, 4, 11]),
- bodychildset([5, 6, 7, 8, 9, 10]));
- // bug 528096 (tree pseudos)
- test_unbalanced_unparseable(":-moz-tree-column((){} a");
- test_unbalanced_unparseable(":-moz-tree-column(x(){} a");
- test_unbalanced_unparseable(":-moz-tree-column(a b (){} a");
- test_unbalanced_unparseable(":-moz-tree-column(a, b (){} a");
- // Bug 543428 (escaping)
- test_selector_in_html("\\32|a", single_a, set_single, empty_set,
- "@namespace \\32 url(http://www.w3.org/1999/xhtml);");
- test_selector_in_html("-\\32|a", single_a, set_single, empty_set,
- "@namespace -\\32 url(http://www.w3.org/1999/xhtml);");
- test_selector_in_html("\\2|a", single_a, set_single, empty_set,
- "@namespace \\0002 url(http://www.w3.org/1999/xhtml);");
- test_selector_in_html("-\\2|a", single_a, set_single, empty_set,
- "@namespace -\\000002 url(http://www.w3.org/1999/xhtml);");
- var spans = "<span class='2'></span><span class=''></span>" +
- "<span id='2'></span><span id=''></span>"
- test_selector_in_html(".\\32", spans,
- bodychildset([0]), bodychildset([1, 2, 3]));
- test_selector_in_html("[class=\\32]", spans,
- bodychildset([0]), bodychildset([1, 2, 3]));
- test_selector_in_html(".\\2", spans,
- bodychildset([1]), bodychildset([0, 2, 3]));
- test_selector_in_html("[class=\\2]", spans,
- bodychildset([1]), bodychildset([0, 2, 3]));
- test_selector_in_html("#\\32", spans,
- bodychildset([2]), bodychildset([0, 1, 3]));
- test_selector_in_html("[id=\\32]", spans,
- bodychildset([2]), bodychildset([0, 1, 3]));
- test_selector_in_html("#\\2", spans,
- bodychildset([3]), bodychildset([0, 1, 2]));
- test_selector_in_html("[id=\\2]", spans,
- bodychildset([3]), bodychildset([0, 1, 2]));
- test_balanced_unparseable("#2");
- // Bug 553805: :not() containing nothing is forbidden
- test_balanced_unparseable(":not()");
- test_balanced_unparseable(":not( )");
- test_balanced_unparseable(":not( \t\n )");
- test_balanced_unparseable(":not(/*comment*/)");
- test_balanced_unparseable(":not( /*comment*/ /* comment */ )");
- test_balanced_unparseable("p :not()");
- test_balanced_unparseable("p :not( )");
- test_balanced_unparseable("p :not( \t\n )");
- test_balanced_unparseable("p :not(/*comment*/)");
- test_balanced_unparseable("p :not( /*comment*/ /* comment */ )");
- test_balanced_unparseable("p:not()");
- test_balanced_unparseable("p:not( )");
- test_balanced_unparseable("p:not( \t\n )");
- test_balanced_unparseable("p:not(/*comment*/)");
- test_balanced_unparseable("p:not( /*comment*/ /* comment */ )");
- test_balanced_unparseable(":not(:nth-child(2k))");
- test_balanced_unparseable(":not(:nth-child(()))");
- // :-moz-any()
- test_balanced_unparseable(":-moz-any()");
- test_balanced_unparseable(":-moz-any(div p)");
- test_balanced_unparseable(":-moz-any(div ~ p)");
- test_balanced_unparseable(":-moz-any(div~p)");
- test_balanced_unparseable(":-moz-any(div + p)");
- test_balanced_unparseable(":-moz-any(div+p)");
- test_balanced_unparseable(":-moz-any(div > p)");
- test_balanced_unparseable(":-moz-any(div>p)");
- test_parseable(":-moz-any(div, p)");
- test_parseable(":-moz-any( div , p )");
- test_parseable(":-moz-any(div,p)");
- test_parseable(":-moz-any(div)");
- test_parseable(":-moz-any(div,p,:link,span:focus)");
- test_parseable(":-moz-any(:active,:focus)");
- test_parseable(":-moz-any(:active,:link:focus)");
- test_balanced_unparseable(":-moz-any(div,:nonexistentpseudo)");
- var any_elts = "<input type='text'><a href='http://www.example.com/'></a><div></div><a name='foo'>";
- test_selector_in_html(":-moz-any(a,input)", any_elts,
- bodychildset([0, 1, 3]), bodychildset([2]));
- test_selector_in_html(":-moz-any(:link,:not(a))", any_elts,
- bodychildset([0, 1, 2]), bodychildset([3]));
- test_selector_in_html(":-moz-any([href],input[type],input[name])", any_elts,
- bodychildset([0, 1]), bodychildset([2, 3]));
- test_selector_in_html(":-moz-any(div,a):-moz-any([type],[href],[name])",
- any_elts,
- bodychildset([1, 3]), bodychildset([0, 2]));
- test_selector_in_html(":-moz-table-border-nonzero",
- "<p></p>" +
- "<p border='2'></p>" +
- "<table border='2'></table>" +
- "<table border></table>" +
- "<table></table>" +
- "<table frame='border'></table>" +
- "<table border='0'></table>" +
- "<table border='0pt'></table>" +
- "<table border='3pt'></table>",
- bodychildset([2, 3, 8]),
- bodychildset([0, 1, 4, 5, 6, 7]));
- // Test that we don't tokenize an empty HASH.
- test_balanced_unparseable("#");
- test_balanced_unparseable("# ");
- test_balanced_unparseable("#, p");
- test_balanced_unparseable("# , p");
- test_balanced_unparseable("p #");
- test_balanced_unparseable("p # ");
- test_balanced_unparseable("p #, p");
- test_balanced_unparseable("p # , p");
- // Test that a backslash alone at EOF outside of a string is treated
- // as U+FFFD.
- test_parseable_via_api("#a\\");
- test_parseable_via_api("#\\");
- test_parseable_via_api("\\");
- // Test that newline escapes are only supported in strings.
- test_balanced_unparseable("di\\\nv");
- test_balanced_unparseable("div \\\n p");
- test_balanced_unparseable("div\\\n p");
- test_balanced_unparseable("div \\\np");
- test_balanced_unparseable("div\\\np");
- // Test that :-moz-placeholder is parsable.
- test_parseable(":-moz-placeholder");
- // Test that things other than user-action pseudo-classes are
- // rejected after pseudo-elements. Some of these tests rely on
- // using a pseudo-element that supports a user-action pseudo-class
- // after it, so we need to use the prefixed ::-moz-color-swatch,
- // which is one of the ones with
- // CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE (none of which are
- // unprefixed).
- test_parseable("::-moz-color-swatch:hover");
- test_balanced_unparseable("::-moz-color-swatch:not(.foo)");
- test_balanced_unparseable("::-moz-color-swatch:first-child");
- test_balanced_unparseable("::-moz-color-swatch:hover#foo");
- test_balanced_unparseable(".foo::after:not(.bar) ~ h3");
- run_deferred_tests();
- }
- var deferred_tests = [];
- function defer_clonedoc_tests(docurl, onloadfunc)
- {
- deferred_tests.push( { docurl: docurl, onloadfunc: onloadfunc } );
- }
- function run_deferred_tests()
- {
- if (deferred_tests.length == 0) {
- SimpleTest.finish();
- return;
- }
- cloneiframe.onload = deferred_tests_onload;
- cloneiframe.src = deferred_tests[0].docurl;
- }
- function deferred_tests_onload(event)
- {
- if (event.target != cloneiframe)
- return;
- deferred_tests[0].onloadfunc();
- deferred_tests.shift();
- run_deferred_tests();
- }
- </script>
- </pre>
- </body>
- </html>
|