semantics.html (13655B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>Selectors: semantics of case-sensitivity attribute selector</title> 4 <link rel="help" href="https://drafts.csswg.org/selectors/#attribute-case"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <style></style> 8 <div id=log></div> 9 <iframe id="quirks" src="resources/semantics-quirks.html"></iframe> 10 <iframe id="xml" src="resources/semantics-xml.xhtml"></iframe> 11 <script> 12 setup({explicit_done:true}); 13 var match = [ 14 // [selector, attrs...] (each attr is [ns, name, value]) 15 ["[foo='BAR'] /* sanity check (match) */", ["", "foo", "BAR"]], 16 ["[foo='bar'] /* sanity check (match) */", ["", "foo", "bar"]], 17 ["[align='left'] /* sanity check (match) */", ["", "align", "left"]], 18 ["[class~='a'] /* sanity check (match) */", ["", "class", "X a b"]], 19 ["[class~='A'] /* sanity check (match) */", ["", "class", "x A B"]], 20 ["[id^='a'] /* sanity check (match) */", ["", "id", "ab"]], 21 ["[id$='A'] /* sanity check (match) */", ["", "id", "XA"]], 22 ["[lang|='a'] /* sanity check (match) */", ["", "lang", "a-b"]], 23 ["[lang*='A'] /* sanity check (match) */", ["", "lang", "XAB"]], 24 ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A'] /* sanity check (match) */", 25 ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], 26 // Case-insensitive matching. 27 ["[foo='bar' i]", ["", "foo", "BAR"]], 28 ["[foo='' i]", ["", "foo", ""]], 29 ["[foo='a\u0308' i] /* COMBINING in both */", ["", "foo", "A\u0308"]], 30 ["[foo='A\u0308' i] /* COMBINING in both */", ["", "foo", "a\u0308"]], 31 ["[*|foo='bar' i]", ["", "foo", "x"], ["a", "foo", "x"], ["b", "foo", "BAR"], ["c", "foo", "x"]], 32 ["[*|foo='bar' i]", ["", "foo", "BAR"], ["a", "foo", "x"], ["b", "foo", "x"], ["c", "foo", "x"]], 33 ["[align='left' i]", ["", "align", "LEFT"]], 34 ["[align='LEFT' i]", ["", "align", "left"]], 35 ["[class~='a' i]", ["", "class", "X A B"]], 36 ["[class~='A' i]", ["", "class", "x a b"]], 37 ["[id^='a' i]", ["", "id", "AB"]], 38 ["[id$='A' i]", ["", "id", "xa"]], 39 ["[lang|='a' i]", ["", "lang", "A-B"]], 40 ["[lang*='A' i]", ["", "lang", "xab"]], 41 ["[*|lang='a' i]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], 42 ["[*|lang='A' i]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 43 ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A' i]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 44 ["[foo='bar' i][foo='bar' i]", ["", "foo", "BAR"]], 45 ["[foo='BAR'][foo='bar' i]", ["", "foo", "BAR"]], 46 ["[foo='bar' i][foo='BAR']", ["", "foo", "BAR"]], 47 // Case-sensitive matching. 48 ["[foo='bar' s]", ["", "foo", "bar"]], 49 ["[foo='' s]", ["", "foo", ""]], 50 ["[foo='a\u0308' s] /* COMBINING in both */", ["", "foo", "a\u0308"]], 51 ["[*|foo='bar' s]", ["", "foo", "x"], ["a", "foo", "x"], ["b", "foo", "bar"], ["c", "foo", "x"]], 52 ["[*|foo='bar' s]", ["", "foo", "bar"], ["a", "foo", "x"], ["b", "foo", "x"], ["c", "foo", "x"]], 53 ["[align='left' s]", ["", "align", "left"]], 54 ["[align='LEFT' s]", ["", "align", "LEFT"]], 55 ["[class~='a' s]", ["", "class", "x a b"]], 56 ["[class~='A' s]", ["", "class", "X A B"]], 57 ["[id^='a' s]", ["", "id", "ab"]], 58 ["[id$='A' s]", ["", "id", "XA"]], 59 ["[lang|='a' s]", ["", "lang", "a-b"]], 60 ["[lang*='A' s]", ["", "lang", "XAB"]], 61 ["[*|lang='a' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 62 ["[*|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], 63 ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], 64 ["[foo='BAR' s][foo='BAR' s]", ["", "foo", "BAR"]], 65 ]; 66 67 var matchHTMLOnly = [ 68 ["[align='left'] /* sanity check (match HTML) */", ["", "align", "LEFT"]], 69 ["[align='LEFT'] /* sanity check (match HTML) */", ["", "align", "left"]], 70 ["[lang|='a'] /* sanity check (match HTML) */", ["", "lang", "A-B"]], 71 ["[lang*='A'] /* sanity check (match HTML) */", ["", "lang", "xab"]], 72 ]; 73 74 var nomatch = [ 75 ["[missingattr] /* sanity check (no match) */", ["", "foo", "BAR"]], 76 ["[foo='bar'] /* sanity check (no match) */", ["", "foo", "BAR"]], 77 ["[class~='a'] /* sanity check (no match) */", ["", "class", "X A B"]], 78 ["[class~='A'] /* sanity check (no match) */", ["", "class", "x a b"]], 79 ["[id^='a'] /* sanity check (no match) */", ["", "id", "AB"]], 80 ["[id$='A']", ["", "id", "xa"]], 81 ["[*|lang='a'] /* sanity check (no match) */", 82 ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], 83 ["[*|lang='A'] /* sanity check (no match) */", 84 ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 85 ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A'] /* sanity check (no match) */", 86 ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 87 // Case-insensitive matching. 88 ["[foo='' i]", ["", "foo", "BAR"]], 89 ["[foo='\u0000' i] /* \\0 in selector */", ["", "foo", ""]], 90 ["[foo='' i] /* \\0 in attribute */", ["", "foo", "\u0000"]], 91 ["[foo='\u00E4' i]", ["", "foo", "\u00C4"]], 92 ["[foo='\u00C4' i]", ["", "foo", "\u00E4"]], 93 ["[foo='a\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00C4"]], 94 ["[foo~='a\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00E4"]], 95 ["[foo^='A\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00C4"]], 96 ["[foo$='A\u0308' i] /* COMBINING in selector */", ["", "foo", "\u00E4"]], 97 ["[foo*='\u00E4' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 98 ["[foo|='\u00E4' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 99 ["[foo='\u00C4' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 100 ["[foo='\u00C4' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 101 ["[foo='a\u0308' i] /* COMBINING in selector */", ["", "foo", "a"]], 102 ["[foo='a\u0308' i] /* COMBINING in selector */", ["", "foo", "A"]], 103 ["[foo='A\u0308' i] /* COMBINING in selector */", ["", "foo", "a"]], 104 ["[foo='A\u0308' i] /* COMBINING in selector */", ["", "foo", "A"]], 105 ["[foo='a' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 106 ["[foo='A' i] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 107 ["[foo='a' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 108 ["[foo='A' i] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 109 ["[foo='i' i]", ["", "foo", "\u0130"]], 110 ["[foo='i' i]", ["", "foo", "\u0131"]], 111 ["[foo='I' i]", ["", "foo", "\u0130"]], 112 ["[foo='I' i]", ["", "foo", "\u0131"]], 113 ["[foo='\u0130' i]", ["", "foo", "i"]], 114 ["[foo='\u0131' i]", ["", "foo", "i"]], 115 ["[foo='\u0130' i]", ["", "foo", "I"]], 116 ["[foo='\u0131' i]", ["", "foo", "I"]], 117 ["[foo='bar' i]", ["", "foo", "x"], ["a", "foo", "BAR"]], 118 ["[|foo='bar' i]", ["", "foo", "x"], ["a", "foo", "BAR"]], 119 ["[foo='bar' i]", ["", "FOO", "bar"]], 120 ["[foo='\t' i] /* tab in selector */", ["", "foo", " "]], 121 ["[foo=' ' i] /* tab in attribute */", ["", "foo", "\t"]], 122 ["@namespace x 'a'; [x|foo='' i]", ["A", "foo", ""]], 123 ["@namespace x 'A'; [x|foo='' i]", ["a", "foo", ""]], 124 ["[foo='bar' i][foo='bar']", ["", "foo", "BAR"]], 125 ["[foo='bar' i]", ["", "baz", "BAR"]], 126 ["[foo^='é' i]", ["", "foo", "É"]], 127 ["[foo$='é' i]", ["", "foo", "É"]], 128 ["[foo*='é' i]", ["", "foo", "É"]], 129 ["[foo|='é' i]", ["", "foo", "É"]], 130 ["[foo^='É' i]", ["", "foo", "é"]], 131 ["[foo$='É' i]", ["", "foo", "é"]], 132 ["[foo*='É' i]", ["", "foo", "é"]], 133 ["[foo|='É' i]", ["", "foo", "é"]], 134 // Case-sensitive matching 135 ["[foo='' s]", ["", "foo", "BAR"]], 136 ["[foo='\u0000' s] /* \\0 in selector */", ["", "foo", ""]], 137 ["[foo='' s] /* \\0 in attribute */", ["", "foo", "\u0000"]], 138 ["[foo='\u00E4' s]", ["", "foo", "\u00C4"]], 139 ["[foo='\u00C4' s]", ["", "foo", "\u00E4"]], 140 ["[foo='a\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00C4"]], 141 ["[foo~='a\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00E4"]], 142 ["[foo^='A\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00C4"]], 143 ["[foo$='A\u0308' s] /* COMBINING in selector */", ["", "foo", "\u00E4"]], 144 ["[foo*='\u00E4' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 145 ["[foo|='\u00E4' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 146 ["[foo='\u00C4' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 147 ["[foo='\u00C4' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 148 ["[foo='a\u0308' s] /* COMBINING in selector */", ["", "foo", "a"]], 149 ["[foo='a\u0308' s] /* COMBINING in selector */", ["", "foo", "A"]], 150 ["[foo='A\u0308' s] /* COMBINING in selector */", ["", "foo", "a"]], 151 ["[foo='A\u0308' s] /* COMBINING in selector */", ["", "foo", "A"]], 152 ["[foo='a' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 153 ["[foo='A' s] /* COMBINING in attribute */", ["", "foo", "a\u0308"]], 154 ["[foo='a' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 155 ["[foo='A' s] /* COMBINING in attribute */", ["", "foo", "A\u0308"]], 156 ["[foo='i' s]", ["", "foo", "\u0130"]], 157 ["[foo='i' s]", ["", "foo", "\u0131"]], 158 ["[foo='I' s]", ["", "foo", "\u0130"]], 159 ["[foo='I' s]", ["", "foo", "\u0131"]], 160 ["[foo='\u0130' s]", ["", "foo", "i"]], 161 ["[foo='\u0131' s]", ["", "foo", "i"]], 162 ["[foo='\u0130' s]", ["", "foo", "I"]], 163 ["[foo='\u0131' s]", ["", "foo", "I"]], 164 ["[foo='bar' s]", ["", "foo", "x"], ["a", "foo", "BAR"]], 165 ["[|foo='bar' s]", ["", "foo", "x"], ["a", "foo", "BAR"]], 166 ["[foo='bar' s]", ["", "FOO", "bar"]], 167 ["[foo='\t' s] /* tab in selector */", ["", "foo", " "]], 168 ["[foo=' ' s] /* tab in attribute */", ["", "foo", "\t"]], 169 ["@namespace x 'a'; [x|foo='' s]", ["A", "foo", ""]], 170 ["@namespace x 'A'; [x|foo='' s]", ["a", "foo", ""]], 171 ["[foo='bar' s][foo='bar']", ["", "foo", "BAR"]], 172 ["[foo='bar' s]", ["", "baz", "BAR"]], 173 ["[foo='bar' s]", ["", "foo", "BAR"]], 174 ["[foo='a\u0308' s] /* COMBINING in both */", ["", "foo", "A\u0308"]], 175 ["[foo='A\u0308' s] /* COMBINING in both */", ["", "foo", "a\u0308"]], 176 ["[*|foo='bar' s]", ["", "foo", "x"], ["a", "foo", "x"], ["b", "foo", "BAR"], ["c", "foo", "x"]], 177 ["[*|foo='bar' s]", ["", "foo", "BAR"], ["a", "foo", "x"], ["b", "foo", "x"], ["c", "foo", "x"]], 178 ["[align='left' s]", ["", "align", "LEFT"]], 179 ["[align='LEFT' s]", ["", "align", "left"]], 180 ["[class~='a' s]", ["", "class", "X A B"]], 181 ["[class~='A' s]", ["", "class", "x a b"]], 182 ["[id^='a' s]", ["", "id", "AB"]], 183 ["[id$='A' s]", ["", "id", "xa"]], 184 ["[lang|='a' s]", ["", "lang", "A-B"]], 185 ["[lang*='A' s]", ["", "lang", "xab"]], 186 ["[*|lang='a' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "A"]], 187 ["[*|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 188 ["@namespace x 'http://www.w3.org/XML/1998/namespace'; [x|lang='A' s]", ["http://www.w3.org/XML/1998/namespace", "lang", "a"]], 189 ["[foo='bar' s][foo='bar' s]", ["", "foo", "BAR"]], 190 ["[foo='BAR' s][foo='bar']", ["", "foo", "BAR"]], 191 ["[foo='bar'][foo='BAR' s]", ["", "foo", "BAR"]], 192 ["[foo='BAR'][foo='bar' s]", ["", "foo", "BAR"]], 193 ["[foo='bar' s][foo='BAR']", ["", "foo", "bar"]], 194 ]; 195 var mode = "standards mode"; 196 function format_attrs(attrs) { 197 var rv = []; 198 attrs.forEach(function(attr) { 199 var str = ""; 200 var ns = attr[0]; 201 var name = attr[1]; 202 var value = attr[2]; 203 if (ns) 204 str += "{" + ns + "}"; 205 str += name + "=\"" + value + "\""; 206 rv.push(str); 207 }); 208 return rv.join(" "); 209 } 210 onload = function() { 211 var quirks = document.getElementById('quirks').contentWindow; 212 var xml = document.getElementById('xml').contentWindow; 213 [window, quirks, xml].forEach(function(global) { 214 var style = global.document.getElementsByTagName('style')[0]; 215 var elm; 216 function clean_slate() { 217 style.textContent = ''; 218 if (elm) 219 elm.parentNode.removeChild(elm); 220 elm = global.document.createElement('div'); 221 global.document.body.appendChild(elm); 222 } 223 function set_attrs(attrs) { 224 attrs.forEach(function(attr) { 225 elm.setAttributeNS(attr[0], attr[1], attr[2]); 226 }); 227 } 228 var localMatch = match.slice(); 229 if (global != xml) { 230 localMatch.push(...matchHTMLOnly); 231 } 232 localMatch.forEach(function(arr) { 233 var s = arr[0]; 234 var attrs = arr.slice(1); 235 var ns_decl = s.substr(0, "@namespace".length) == "@namespace"; 236 test(function() { 237 clean_slate(); 238 set_attrs(attrs); 239 style.textContent = s + ' { visibility:hidden }'; 240 assert_equals(style.sheet.cssRules.length, (ns_decl ? 2 : 1), 'rule didn\'t parse into CSSOM'); 241 assert_equals(global.getComputedStyle(elm).visibility, 'hidden', 'selector didn\'t match'); 242 }, s + ' <div ' + format_attrs(attrs) + '> in ' + global.mode); 243 if (!ns_decl) { 244 test(function() { 245 assert_equals(global.document.querySelector(s), elm, 'selector didn\'t match'); 246 }, s + ' <div ' + format_attrs(attrs) + '> with querySelector in ' + global.mode); 247 } 248 }); 249 nomatch.forEach(function(arr) { 250 var s = arr[0]; 251 var attrs = arr.slice(1); 252 var ns_decl = s.substr(0, "@namespace".length) == "@namespace"; 253 test(function() { 254 clean_slate(); 255 set_attrs(attrs); 256 style.textContent = s + ' { visibility:hidden }'; 257 assert_equals(style.sheet.cssRules.length, (ns_decl ? 2 : 1), 'rule didn\'t parse into CSSOM'); 258 assert_equals(global.getComputedStyle(elm).visibility, 'visible', 'selector matched'); 259 }, s + ' <div ' + format_attrs(attrs) + '> in ' + global.mode); 260 if (!ns_decl) { 261 test(function() { 262 assert_equals(global.document.querySelector(s), null, 'selector matched'); 263 }, s + ' <div ' + format_attrs(attrs) + '> with querySelector in ' + global.mode); 264 } 265 }); 266 }); 267 done(); 268 }; 269 </script>