| <!doctype html> |
| <meta charset=utf-8> |
| <title>Selectors: semantics of case-sensitivity attribute selector</title> |
| <link rel="help" href="https://drafts.csswg.org/selectors/#attribute-case"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <style></style> |
| <div id=log></div> |
| <iframe id="quirks" src="resources/semantics-quirks.html"></iframe> |
| <iframe id="xml" src="resources/semantics-xml.xhtml"></iframe> |
| <script> |
| setup({explicit_done:true}); |
| var match = [ |
| // [selector, attrs...] (each attr is [ns, name, value]) |
| ["[foo='BAR'] /* sanity check (match) */", ["", "foo", "BAR"]], |
| ["[foo='bar'] /* sanity check (match) */", ["", "foo", "bar"]], |
| ["[align='left'] /* sanity check (match) */", ["", "align", "left"]], |
| ["[class~='a'] /* sanity check (match) */", ["", "class", "X a b"]], |
| ["[class~='A'] /* sanity check (match) */", ["", "class", "x A B"]], |
| ["[id^='a'] /* sanity check (match) */", ["", "id", "ab"]], |
| ["[id$='A'] /* sanity check (match) */", ["", "id", "XA"]], |
| ["[lang|='a'] /* sanity check (match) */", ["", "lang", "a-b"]], |
| ["[lang*='A'] /* sanity check (match) */", ["", "lang", "XAB"]], |
| ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A'] /* sanity check (match) */", |
| ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], |
| // Case-insensitive matching. |
| ["[foo='bar' i]", ["", "foo", "BAR"]], |
| ["[foo='' i]", ["", "foo", ""]], |
| ["[foo='a\u0308' i] /* COMBINING in both */", ["", "foo", "A\u0308"]], |
| ["[foo='A\u0308' i] /* COMBINING in both */", ["", "foo", "a\u0308"]], |
| ["[*|foo='bar' i]", ["", "foo", "x"], ["a", "foo", "x"], ["b", "foo", "BAR"], ["c", "foo", "x"]], |
| ["[*|foo='bar' i]", ["", "foo", "BAR"], ["a", "foo", "x"], ["b", "foo", "x"], ["c", "foo", "x"]], |
| ["[align='left' i]", ["", "align", "LEFT"]], |
| ["[align='LEFT' i]", ["", "align", "left"]], |
| ["[class~='a' i]", ["", "class", "X A B"]], |
| ["[class~='A' i]", ["", "class", "x a b"]], |
| ["[id^='a' i]", ["", "id", "AB"]], |
| ["[id$='A' i]", ["", "id", "xa"]], |
| ["[lang|='a' i]", ["", "lang", "A-B"]], |
| ["[lang*='A' i]", ["", "lang", "xab"]], |
| ["[*|lang='a' i]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], |
| ["[*|lang='A' i]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A' i]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| ["[foo='bar' i][foo='bar' i]", ["", "foo", "BAR"]], |
| ["[foo='BAR'][foo='bar' i]", ["", "foo", "BAR"]], |
| ["[foo='bar' i][foo='BAR']", ["", "foo", "BAR"]], |
| // Case-sensitive matching. |
| ["[foo='bar' s]", ["", "foo", "bar"]], |
| ["[foo='' s]", ["", "foo", ""]], |
| ["[foo='a\u0308' s] /* COMBINING in both */", ["", "foo", "a\u0308"]], |
| ["[*|foo='bar' s]", ["", "foo", "x"], ["a", "foo", "x"], ["b", "foo", "bar"], ["c", "foo", "x"]], |
| ["[*|foo='bar' s]", ["", "foo", "bar"], ["a", "foo", "x"], ["b", "foo", "x"], ["c", "foo", "x"]], |
| ["[align='left' s]", ["", "align", "left"]], |
| ["[align='LEFT' s]", ["", "align", "LEFT"]], |
| ["[class~='a' s]", ["", "class", "x a b"]], |
| ["[class~='A' s]", ["", "class", "X A B"]], |
| ["[id^='a' s]", ["", "id", "ab"]], |
| ["[id$='A' s]", ["", "id", "XA"]], |
| ["[lang|='a' s]", ["", "lang", "a-b"]], |
| ["[lang*='A' s]", ["", "lang", "XAB"]], |
| ["[*|lang='a' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| ["[*|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], |
| ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], |
| ["[foo='BAR' s][foo='BAR' s]", ["", "foo", "BAR"]], |
| ]; |
| |
| var matchHTMLOnly = [ |
| ["[align='left'] /* sanity check (match HTML) */", ["", "align", "LEFT"]], |
| ["[align='LEFT'] /* sanity check (match HTML) */", ["", "align", "left"]], |
| ["[lang|='a'] /* sanity check (match HTML) */", ["", "lang", "A-B"]], |
| ["[lang*='A'] /* sanity check (match HTML) */", ["", "lang", "xab"]], |
| ]; |
| |
| var nomatch = [ |
| ["[missingattr] /* sanity check (no match) */", ["", "foo", "BAR"]], |
| ["[foo='bar'] /* sanity check (no match) */", ["", "foo", "BAR"]], |
| ["[class~='a'] /* sanity check (no match) */", ["", "class", "X A B"]], |
| ["[class~='A'] /* sanity check (no match) */", ["", "class", "x a b"]], |
| ["[id^='a'] /* sanity check (no match) */", ["", "id", "AB"]], |
| ["[id$='A']", ["", "id", "xa"]], |
| ["[*|lang='a'] /* sanity check (no match) */", |
| ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], |
| ["[*|lang='A'] /* sanity check (no match) */", |
| ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A'] /* sanity check (no match) */", |
| ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| // Case-insensitive matching. |
| ["[foo='' i]", ["", "foo", "BAR"]], |
| ["[foo='\u0000' i] /* \\0 in selector */", ["", "foo", ""]], |
| ["[foo='' i] /* \\0 in attribute */", ["", "foo", "\u0000"]], |
| ["[foo='\u00E4' i]", ["", "foo", "\u00C4"]], |
| ["[foo='\u00C4' i]", ["", "foo", "\u00E4"]], |
| ["[foo='a\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00C4"]], |
| ["[foo~='a\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00E4"]], |
| ["[foo^='A\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00C4"]], |
| ["[foo$='A\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00E4"]], |
| ["[foo*='\u00E4' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo|='\u00E4' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='\u00C4' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo='\u00C4' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='a\u0308' i] /* COMBINING in selector */", ["", "foo", "a"]], |
| ["[foo='a\u0308' i] /* COMBINING in selector */", ["", "foo", "A"]], |
| ["[foo='A\u0308' i] /* COMBINING in selector */", ["", "foo", "a"]], |
| ["[foo='A\u0308' i] /* COMBINING in selector */", ["", "foo", "A"]], |
| ["[foo='a' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo='A' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo='a' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='A' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='i' i]", ["", "foo", "\u0130"]], |
| ["[foo='i' i]", ["", "foo", "\u0131"]], |
| ["[foo='I' i]", ["", "foo", "\u0130"]], |
| ["[foo='I' i]", ["", "foo", "\u0131"]], |
| ["[foo='\u0130' i]", ["", "foo", "i"]], |
| ["[foo='\u0131' i]", ["", "foo", "i"]], |
| ["[foo='\u0130' i]", ["", "foo", "I"]], |
| ["[foo='\u0131' i]", ["", "foo", "I"]], |
| ["[foo='bar' i]", ["", "foo", "x"], ["a", "foo", "BAR"]], |
| ["[|foo='bar' i]", ["", "foo", "x"], ["a", "foo", "BAR"]], |
| ["[foo='bar' i]", ["", "FOO", "bar"]], |
| ["[foo='\t' i] /* tab in selector */", ["", "foo", " "]], |
| ["[foo=' ' i] /* tab in attribute */", ["", "foo", "\t"]], |
| ["@namespace x 'a'; [x|foo='' i]", ["A", "foo", ""]], |
| ["@namespace x 'A'; [x|foo='' i]", ["a", "foo", ""]], |
| ["[foo='bar' i][foo='bar']", ["", "foo", "BAR"]], |
| ["[foo='bar' i]", ["", "baz", "BAR"]], |
| ["[foo^='é' i]", ["", "foo", "É"]], |
| ["[foo$='é' i]", ["", "foo", "É"]], |
| ["[foo*='é' i]", ["", "foo", "É"]], |
| ["[foo|='é' i]", ["", "foo", "É"]], |
| ["[foo^='É' i]", ["", "foo", "é"]], |
| ["[foo$='É' i]", ["", "foo", "é"]], |
| ["[foo*='É' i]", ["", "foo", "é"]], |
| ["[foo|='É' i]", ["", "foo", "é"]], |
| // Case-sensitive matching |
| ["[foo='' s]", ["", "foo", "BAR"]], |
| ["[foo='\u0000' s] /* \\0 in selector */", ["", "foo", ""]], |
| ["[foo='' s] /* \\0 in attribute */", ["", "foo", "\u0000"]], |
| ["[foo='\u00E4' s]", ["", "foo", "\u00C4"]], |
| ["[foo='\u00C4' s]", ["", "foo", "\u00E4"]], |
| ["[foo='a\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00C4"]], |
| ["[foo~='a\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00E4"]], |
| ["[foo^='A\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00C4"]], |
| ["[foo$='A\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00E4"]], |
| ["[foo*='\u00E4' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo|='\u00E4' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='\u00C4' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo='\u00C4' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='a\u0308' s] /* COMBINING in selector */", ["", "foo", "a"]], |
| ["[foo='a\u0308' s] /* COMBINING in selector */", ["", "foo", "A"]], |
| ["[foo='A\u0308' s] /* COMBINING in selector */", ["", "foo", "a"]], |
| ["[foo='A\u0308' s] /* COMBINING in selector */", ["", "foo", "A"]], |
| ["[foo='a' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo='A' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], |
| ["[foo='a' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='A' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], |
| ["[foo='i' s]", ["", "foo", "\u0130"]], |
| ["[foo='i' s]", ["", "foo", "\u0131"]], |
| ["[foo='I' s]", ["", "foo", "\u0130"]], |
| ["[foo='I' s]", ["", "foo", "\u0131"]], |
| ["[foo='\u0130' s]", ["", "foo", "i"]], |
| ["[foo='\u0131' s]", ["", "foo", "i"]], |
| ["[foo='\u0130' s]", ["", "foo", "I"]], |
| ["[foo='\u0131' s]", ["", "foo", "I"]], |
| ["[foo='bar' s]", ["", "foo", "x"], ["a", "foo", "BAR"]], |
| ["[|foo='bar' s]", ["", "foo", "x"], ["a", "foo", "BAR"]], |
| ["[foo='bar' s]", ["", "FOO", "bar"]], |
| ["[foo='\t' s] /* tab in selector */", ["", "foo", " "]], |
| ["[foo=' ' s] /* tab in attribute */", ["", "foo", "\t"]], |
| ["@namespace x 'a'; [x|foo='' s]", ["A", "foo", ""]], |
| ["@namespace x 'A'; [x|foo='' s]", ["a", "foo", ""]], |
| ["[foo='bar' s][foo='bar']", ["", "foo", "BAR"]], |
| ["[foo='bar' s]", ["", "baz", "BAR"]], |
| ["[foo='bar' s]", ["", "foo", "BAR"]], |
| ["[foo='a\u0308' s] /* COMBINING in both */", ["", "foo", "A\u0308"]], |
| ["[foo='A\u0308' s] /* COMBINING in both */", ["", "foo", "a\u0308"]], |
| ["[*|foo='bar' s]", ["", "foo", "x"], ["a", "foo", "x"], ["b", "foo", "BAR"], ["c", "foo", "x"]], |
| ["[*|foo='bar' s]", ["", "foo", "BAR"], ["a", "foo", "x"], ["b", "foo", "x"], ["c", "foo", "x"]], |
| ["[align='left' s]", ["", "align", "LEFT"]], |
| ["[align='LEFT' s]", ["", "align", "left"]], |
| ["[class~='a' s]", ["", "class", "X A B"]], |
| ["[class~='A' s]", ["", "class", "x a b"]], |
| ["[id^='a' s]", ["", "id", "AB"]], |
| ["[id$='A' s]", ["", "id", "xa"]], |
| ["[lang|='a' s]", ["", "lang", "A-B"]], |
| ["[lang*='A' s]", ["", "lang", "xab"]], |
| ["[*|lang='a' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], |
| ["[*|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], |
| ["[foo='bar' s][foo='bar' s]", ["", "foo", "BAR"]], |
| ["[foo='BAR' s][foo='bar']", ["", "foo", "BAR"]], |
| ["[foo='bar'][foo='BAR' s]", ["", "foo", "BAR"]], |
| ["[foo='BAR'][foo='bar' s]", ["", "foo", "BAR"]], |
| ["[foo='bar' s][foo='BAR']", ["", "foo", "bar"]], |
| ]; |
| var mode = "standards mode"; |
| function format_attrs(attrs) { |
| var rv = []; |
| attrs.forEach(function(attr) { |
| var str = ""; |
| var ns = attr[0]; |
| var name = attr[1]; |
| var value = attr[2]; |
| if (ns) |
| str += "{" + ns + "}"; |
| str += name + "=\"" + value + "\""; |
| rv.push(str); |
| }); |
| return rv.join(" "); |
| } |
| onload = function() { |
| var quirks = document.getElementById('quirks').contentWindow; |
| var xml = document.getElementById('xml').contentWindow; |
| [window, quirks, xml].forEach(function(global) { |
| var style = global.document.getElementsByTagName('style')[0]; |
| var elm; |
| function clean_slate() { |
| style.textContent = ''; |
| if (elm) |
| elm.parentNode.removeChild(elm); |
| elm = global.document.createElement('div'); |
| global.document.body.appendChild(elm); |
| } |
| function set_attrs(attrs) { |
| attrs.forEach(function(attr) { |
| elm.setAttributeNS(attr[0], attr[1], attr[2]); |
| }); |
| } |
| var localMatch = match.slice(); |
| if (global != xml) { |
| localMatch.push(...matchHTMLOnly); |
| } |
| localMatch.forEach(function(arr) { |
| var s = arr[0]; |
| var attrs = arr.slice(1); |
| var ns_decl = s.substr(0, "@namespace".length) == "@namespace"; |
| test(function() { |
| clean_slate(); |
| set_attrs(attrs); |
| style.textContent = s + ' { visibility:hidden }'; |
| assert_equals(style.sheet.cssRules.length, (ns_decl ? 2 : 1), 'rule didn\'t parse into CSSOM'); |
| assert_equals(global.getComputedStyle(elm).visibility, 'hidden', 'selector didn\'t match'); |
| }, s + ' <div ' + format_attrs(attrs) + '> in ' + global.mode); |
| if (!ns_decl) { |
| test(function() { |
| assert_equals(global.document.querySelector(s), elm, 'selector didn\'t match'); |
| }, s + ' <div ' + format_attrs(attrs) + '> with querySelector in ' + global.mode); |
| } |
| }); |
| nomatch.forEach(function(arr) { |
| var s = arr[0]; |
| var attrs = arr.slice(1); |
| var ns_decl = s.substr(0, "@namespace".length) == "@namespace"; |
| test(function() { |
| clean_slate(); |
| set_attrs(attrs); |
| style.textContent = s + ' { visibility:hidden }'; |
| assert_equals(style.sheet.cssRules.length, (ns_decl ? 2 : 1), 'rule didn\'t parse into CSSOM'); |
| assert_equals(global.getComputedStyle(elm).visibility, 'visible', 'selector matched'); |
| }, s + ' <div ' + format_attrs(attrs) + '> in ' + global.mode); |
| if (!ns_decl) { |
| test(function() { |
| assert_equals(global.document.querySelector(s), null, 'selector matched'); |
| }, s + ' <div ' + format_attrs(attrs) + '> with querySelector in ' + global.mode); |
| } |
| }); |
| }); |
| done(); |
| }; |
| </script> |