is-pseudo-containing-complex-in-has.html (27650B)
1 <!DOCTYPE html> 2 <meta charset="utf-8" /> 3 <title>CSS Selectors Invalidation: :is() in :has() argument</title> 4 <link rel="author" title="Byungwoo Lee" href="blee@igalia.com"> 5 <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <style> 9 div { color: grey } 10 .red:has(#descendant:is(.a_has_scope .b)) { color: red } 11 .orangered:has(#descendant:is(.a_descendant .b)) #descendant { color: orangered } 12 .darkred:has(#descendant:is(.a_indirect_next .b)) ~ #indirect_next { color: darkred } 13 .pink:has(#descendant:is(.a_indirect_next_child .b)) ~ #indirect_next #indirect_next_child { color: pink } 14 .green:has(#descendant:is(.p + .c_has_scope ~ .d .e)) { color: green } 15 .lightgreen:has(#descendant:is(.p + .c_descendant ~ .d .e)) #descendant { color: lightgreen } 16 .darkgreen:has(#descendant:is(.p + .c_indirect_next ~ .d .e)) ~ #indirect_next { color: darkgreen } 17 .yellowgreen:has(#descendant:is(.p + .c_indirect_next_child ~ .d .e)) ~ #indirect_next #indirect_next_child { color: yellowgreen } 18 .blue:has(~ #indirect_next:is(.p + .f_has_scope ~ .g)) { color: blue } 19 .skyblue:has(~ #indirect_next:is(.p + .f_descendant ~ .g)) #descendant { color: skyblue } 20 .lightblue:has(~ #indirect_next:is(.p + .f_indirect_next ~ .g)) ~ #indirect_next { color: lightblue } 21 .darkblue:has(~ #indirect_next:is(.p + .f_indirect_next_child ~ .g)) ~ #indirect_next #indirect_next_child { color: darkblue } 22 .yellow:has(~ #indirect_next:is(.h_has_scope .i)) { color: yellow } 23 .ivory:has(~ #indirect_next:is(.h_descendant .i)) #descendant { color: ivory } 24 .greenyellow:has(~ #indirect_next:is(.h_indirect_next .i)) ~ #indirect_next { color: greenyellow } 25 .khaki:has(~ #indirect_next:is(.h_indirect_next_child .i)) ~ #indirect_next #indirect_next_child { color: khaki } 26 .purple:has(~ #indirect_next:is(.p + .j_has_scope ~ .k .l)) { color: purple } 27 .violet:has(~ #indirect_next:is(.p + .j_descendant ~ .k .l)) #descendant { color: violet } 28 .orchid:has(~ #indirect_next:is(.p + .j_indirect_next ~ .k .l)) ~ #indirect_next { color: orchid } 29 .plum:has(~ #indirect_next:is(.p + .j_indirect_next_child ~ .k .l)) ~ #indirect_next #indirect_next_child { color: plum } 30 .orange:has(#descendant:is(:is(.m, .n) .o)) { color: orange } 31 </style> 32 <div> 33 <div class="p"></div> 34 <div id="parent_previous"></div> 35 <div id="parent" class="d k"> 36 <div class="p"></div> 37 <div id="previous"></div> 38 <div class="p"></div> 39 <div id="has_scope" class="d"> 40 <div class="p"></div> 41 <div id="child_previous"></div> 42 <div id="child" class="d"> 43 <div id="descendant" class="b e o"></div> 44 </div> 45 </div> 46 <div class="p"></div> 47 <div id="direct_next"></div> 48 <div id="indirect_next" class="g i l"> 49 <div id="indirect_next_child"></div> 50 </div> 51 </div> 52 </div> 53 <script> 54 const grey = "rgb(128, 128, 128)"; 55 const red = "rgb(255, 0, 0)"; 56 const orangered = "rgb(255, 69, 0)"; 57 const darkred = "rgb(139, 0, 0)"; 58 const pink = "rgb(255, 192, 203)"; 59 const green = "rgb(0, 128, 0)"; 60 const lightgreen = "rgb(144, 238, 144)"; 61 const darkgreen = "rgb(0, 100, 0)"; 62 const yellowgreen = "rgb(154, 205, 50)"; 63 const blue = "rgb(0, 0, 255)"; 64 const skyblue = "rgb(135, 206, 235)"; 65 const lightblue = "rgb(173, 216, 230)"; 66 const darkblue = "rgb(0, 0, 139)"; 67 const yellow = "rgb(255, 255, 0)"; 68 const ivory = "rgb(255, 255, 240)"; 69 const greenyellow = "rgb(173, 255, 47)"; 70 const khaki = "rgb(240, 230, 140)"; 71 const purple = "rgb(128, 0, 128)"; 72 const violet = "rgb(238, 130, 238)"; 73 const orchid = "rgb(218, 112, 214)"; 74 const plum = "rgb(221, 160, 221)"; 75 const orange = "rgb(255, 165, 0)"; 76 77 function addClass(element, class_name) { 78 element.classList.add(class_name); 79 } 80 81 function removeClass(element, class_name) { 82 element.classList.remove(class_name); 83 } 84 85 function testClassChange(operation, class_name, element_id, 86 selector, matches_result, 87 subject_id, subject_color) { 88 let element = document.getElementById(element_id); 89 assert_equals(element ? element.id : "", element_id); 90 let subject = document.getElementById(subject_id); 91 assert_equals(subject ? subject.id : "", subject_id); 92 let message_prefix = [ 93 "[", selector, "]", 94 ["#", element.id, ".classList.", 95 (operation == addClass ? "add" : "remove"), 96 "('", class_name, "')"].join(""), 97 ": "].join(" "); 98 operation(element, class_name); 99 test(function() { 100 assert_equals(subject.matches(selector), matches_result); 101 }, message_prefix + "check matches (" + matches_result + ")"); 102 test(function() { 103 assert_equals(getComputedStyle(subject).color, subject_color); 104 }, message_prefix + "check #" + subject_id + " color"); 105 } 106 107 function testSiblingInsertionRemoval(class_name, insert_before_id, selector, 108 subject_id, 109 insertion_matches_result, 110 insertion_subject_color, 111 removal_matches_result, 112 removal_subject_color) { 113 let insert_before = document.getElementById(insert_before_id); 114 assert_equals(insert_before ? insert_before.id : "", insert_before_id); 115 let parent = insert_before.parentElement; 116 let subject = document.getElementById(subject_id); 117 assert_equals(subject ? subject.id : "", subject_id); 118 let message_prefix = [ 119 "[", selector, "]", 120 ["insert/remove .", 121 class_name, " before #", insert_before.id, ")"].join(""), 122 ": "].join(" "); 123 124 let div = document.createElement("div"); 125 div.classList.add(class_name); 126 127 parent.insertBefore(div, insert_before); 128 test(function() { 129 assert_equals(subject.matches(selector), insertion_matches_result); 130 }, message_prefix + "(insertion) check matches (" + 131 insertion_matches_result + ")"); 132 test(function() { 133 assert_equals(getComputedStyle(subject).color, insertion_subject_color); 134 }, message_prefix + "(insertion) check #" + subject_id + " color"); 135 136 div.remove(); 137 test(function() { 138 assert_equals(subject.matches(selector), removal_matches_result); 139 }, message_prefix + "(removal) check matches (" + 140 removal_matches_result + ")"); 141 test(function() { 142 assert_equals(getComputedStyle(subject).color, removal_subject_color); 143 }, message_prefix + "(removal) check #" + subject_id + " color"); 144 } 145 146 assert_equals(getComputedStyle(has_scope).color, grey); 147 148 let selector = ".red:has(#descendant:is(.a_has_scope .b))"; 149 testClassChange(addClass, "red", "has_scope", selector, false, "has_scope", grey); 150 testClassChange(addClass, "a_has_scope", "parent", selector, true, "has_scope", red); 151 testClassChange(removeClass, "a_has_scope", "parent", selector, false, "has_scope", grey); 152 testClassChange(addClass, "a_has_scope", "has_scope", selector, true, "has_scope", red); 153 testClassChange(removeClass, "a_has_scope", "has_scope", selector, false, "has_scope", grey); 154 testClassChange(addClass, "a_has_scope", "child", selector, true, "has_scope", red); 155 testClassChange(removeClass, "a_has_scope", "child", selector, false, "has_scope", grey); 156 testClassChange(removeClass, "red", "has_scope", selector, false, "has_scope", grey); 157 158 selector = ".orangered:has(#descendant:is(.a_descendant .b)) #descendant"; 159 testClassChange(addClass, "orangered", "has_scope", selector, false, "descendant", grey); 160 testClassChange(addClass, "a_descendant", "parent", selector, true, "descendant", orangered); 161 testClassChange(removeClass, "a_descendant", "parent", selector, false, "descendant", grey); 162 testClassChange(addClass, "a_descendant", "has_scope", selector, true, "descendant", orangered); 163 testClassChange(removeClass, "a_descendant", "has_scope", selector, false, "descendant", grey); 164 testClassChange(addClass, "a_descendant", "child", selector, true, "descendant", orangered); 165 testClassChange(removeClass, "a_descendant", "child", selector, false, "descendant", grey); 166 testClassChange(removeClass, "orangered", "has_scope", selector, false, "descendant", grey); 167 168 selector = ".darkred:has(#descendant:is(.a_indirect_next .b)) ~ #indirect_next"; 169 testClassChange(addClass, "darkred", "has_scope", selector, false, "indirect_next", grey); 170 testClassChange(addClass, "a_indirect_next", "parent", selector, true, "indirect_next", darkred); 171 testClassChange(removeClass, "a_indirect_next", "parent", selector, false, "indirect_next", grey); 172 testClassChange(addClass, "a_indirect_next", "has_scope", selector, true, "indirect_next", darkred); 173 testClassChange(removeClass, "a_indirect_next", "has_scope", selector, false, "indirect_next", grey); 174 testClassChange(addClass, "a_indirect_next", "child", selector, true, "indirect_next", darkred); 175 testClassChange(removeClass, "a_indirect_next", "child", selector, false, "indirect_next", grey); 176 testClassChange(removeClass, "darkred", "has_scope", selector, false, "indirect_next", grey); 177 178 selector = ".pink:has(#descendant:is(.a_indirect_next_child .b)) ~ #indirect_next #indirect_next_child"; 179 testClassChange(addClass, "pink", "has_scope", selector, false, "indirect_next_child", grey); 180 testClassChange(addClass, "a_indirect_next_child", "parent", selector, true, "indirect_next_child", pink); 181 testClassChange(removeClass, "a_indirect_next_child", "parent", selector, false, "indirect_next_child", grey); 182 testClassChange(addClass, "a_indirect_next_child", "has_scope", selector, true, "indirect_next_child", pink); 183 testClassChange(removeClass, "a_indirect_next_child", "has_scope", selector, false, "indirect_next_child", grey); 184 testClassChange(addClass, "a_indirect_next_child", "child", selector, true, "indirect_next_child", pink); 185 testClassChange(removeClass, "a_indirect_next_child", "child", selector, false, "indirect_next_child", grey); 186 testClassChange(removeClass, "pink", "has_scope", selector, false, "indirect_next_child", grey); 187 188 selector = ".green:has(#descendant:is(.p + .c_has_scope ~ .d .e))"; 189 testClassChange(addClass, "green", "has_scope", selector, false, "has_scope", grey); 190 testClassChange(addClass, "c_has_scope", "parent_previous", selector, true, "has_scope", green); 191 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "has_scope", false, grey, true, green); 192 testClassChange(removeClass, "c_has_scope", "parent_previous", selector, false, "has_scope", grey); 193 testSiblingInsertionRemoval("c_has_scope", "parent_previous", selector, "has_scope", true, green, false, grey); 194 testClassChange(addClass, "c_has_scope", "previous", selector, true, "has_scope", green); 195 testSiblingInsertionRemoval("invalid", "previous", selector, "has_scope", false, grey, true, green); 196 testClassChange(removeClass, "c_has_scope", "previous", selector, false, "has_scope", grey); 197 testSiblingInsertionRemoval("c_has_scope", "previous", selector, "has_scope", true, green, false, grey); 198 testClassChange(addClass, "c_has_scope", "child_previous", selector, true, "has_scope", green); 199 testSiblingInsertionRemoval("invalid", "child_previous", selector, "has_scope", false, grey, true, green); 200 testClassChange(removeClass, "c_has_scope", "child_previous", selector, false, "has_scope", grey); 201 testSiblingInsertionRemoval("c_has_scope", "child_previous", selector, "has_scope", true, green, false, grey); 202 testClassChange(removeClass, "green", "has_scope", selector, false, "has_scope", grey); 203 204 selector = ".lightgreen:has(#descendant:is(.p + .c_descendant ~ .d .e)) #descendant"; 205 testClassChange(addClass, "lightgreen", "has_scope", selector, false, "descendant", grey); 206 testClassChange(addClass, "c_descendant", "parent_previous", selector, true, "descendant", lightgreen); 207 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "descendant", false, grey, true, lightgreen); 208 testClassChange(removeClass, "c_descendant", "parent_previous", selector, false, "descendant", grey); 209 testSiblingInsertionRemoval("c_descendant", "parent_previous", selector, "descendant", true, lightgreen, false, grey); 210 testClassChange(addClass, "c_descendant", "previous", selector, true, "descendant", lightgreen); 211 testSiblingInsertionRemoval("invalid", "previous", selector, "descendant", false, grey, true, lightgreen); 212 testClassChange(removeClass, "c_descendant", "previous", selector, false, "descendant", grey); 213 testSiblingInsertionRemoval("c_descendant", "previous", selector, "descendant", true, lightgreen, false, grey); 214 testClassChange(addClass, "c_descendant", "child_previous", selector, true, "descendant", lightgreen); 215 testSiblingInsertionRemoval("invalid", "child_previous", selector, "descendant", false, grey, true, lightgreen); 216 testClassChange(removeClass, "c_descendant", "child_previous", selector, false, "descendant", grey); 217 testSiblingInsertionRemoval("c_descendant", "child_previous", selector, "descendant", true, lightgreen, false, grey); 218 testClassChange(removeClass, "lightgreen", "has_scope", selector, false, "descendant", grey); 219 220 selector = ".darkgreen:has(#descendant:is(.p + .c_indirect_next ~ .d .e)) ~ #indirect_next"; 221 testClassChange(addClass, "darkgreen", "has_scope", selector, false, "indirect_next", grey); 222 testClassChange(addClass, "c_indirect_next", "parent_previous", selector, true, "indirect_next", darkgreen); 223 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "indirect_next", false, grey, true, darkgreen); 224 testClassChange(removeClass, "c_indirect_next", "parent_previous", selector, false, "indirect_next", grey); 225 testSiblingInsertionRemoval("c_indirect_next", "parent_previous", selector, "indirect_next", true, darkgreen, false, grey); 226 testClassChange(addClass, "c_indirect_next", "previous", selector, true, "indirect_next", darkgreen); 227 testSiblingInsertionRemoval("invalid", "previous", selector, "indirect_next", false, grey, true, darkgreen); 228 testClassChange(removeClass, "c_indirect_next", "previous", selector, false, "indirect_next", grey); 229 testSiblingInsertionRemoval("c_indirect_next", "previous", selector, "indirect_next", true, darkgreen, false, grey); 230 testClassChange(addClass, "c_indirect_next", "child_previous", selector, true, "indirect_next", darkgreen); 231 testSiblingInsertionRemoval("invalid", "child_previous", selector, "indirect_next", false, grey, true, darkgreen); 232 testClassChange(removeClass, "c_indirect_next", "child_previous", selector, false, "indirect_next", grey); 233 testSiblingInsertionRemoval("c_indirect_next", "child_previous", selector, "indirect_next", true, darkgreen, false, grey); 234 testClassChange(removeClass, "darkgreen", "has_scope", selector, false, "indirect_next", grey); 235 236 selector = ".yellowgreen:has(#descendant:is(.p + .c_indirect_next_child ~ .d .e)) ~ #indirect_next #indirect_next_child"; 237 testClassChange(addClass, "yellowgreen", "has_scope", selector, false, "indirect_next_child", grey); 238 testClassChange(addClass, "c_indirect_next_child", "parent_previous", selector, true, "indirect_next_child", yellowgreen); 239 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "indirect_next_child", false, grey, true, yellowgreen); 240 testClassChange(removeClass, "c_indirect_next_child", "parent_previous", selector, false, "indirect_next_child", grey); 241 testSiblingInsertionRemoval("c_indirect_next_child", "parent_previous", selector, "indirect_next_child", true, yellowgreen, false, grey); 242 testClassChange(addClass, "c_indirect_next_child", "previous", selector, true, "indirect_next_child", yellowgreen); 243 testSiblingInsertionRemoval("invalid", "previous", selector, "indirect_next_child", false, grey, true, yellowgreen); 244 testClassChange(removeClass, "c_indirect_next_child", "previous", selector, false, "indirect_next_child", grey); 245 testSiblingInsertionRemoval("c_indirect_next_child", "previous", selector, "indirect_next_child", true, yellowgreen, false, grey); 246 testClassChange(addClass, "c_indirect_next_child", "child_previous", selector, true, "indirect_next_child", yellowgreen); 247 testSiblingInsertionRemoval("invalid", "child_previous", selector, "indirect_next_child", false, grey, true, yellowgreen); 248 testClassChange(removeClass, "c_indirect_next_child", "child_previous", selector, false, "indirect_next_child", grey); 249 testSiblingInsertionRemoval("c_indirect_next_child", "child_previous", selector, "indirect_next_child", true, yellowgreen, false, grey); 250 testClassChange(removeClass, "yellowgreen", "has_scope", selector, false, "indirect_next_child", grey); 251 252 selector = ".blue:has(~ #indirect_next:is(.p + .f_has_scope ~ .g))"; 253 testClassChange(addClass, "blue", "has_scope", selector, false, "has_scope", grey); 254 testClassChange(addClass, "f_has_scope", "previous", selector, true, "has_scope", blue); 255 testSiblingInsertionRemoval("invalid", "previous", selector, "has_scope", false, grey, true, blue); 256 testClassChange(removeClass, "f_has_scope", "previous", selector, false, "has_scope", grey); 257 testSiblingInsertionRemoval("f_has_scope", "previous", selector, "has_scope", true, blue, false, grey); 258 testClassChange(addClass, "f_has_scope", "has_scope", selector, true, "has_scope", blue); 259 testClassChange(removeClass, "f_has_scope", "has_scope", selector, false, "has_scope", grey); 260 testClassChange(addClass, "f_has_scope", "direct_next", selector, true, "has_scope", blue); 261 testSiblingInsertionRemoval("invalid", "direct_next", selector, "has_scope", false, grey, true, blue); 262 testClassChange(removeClass, "f_has_scope", "direct_next", selector, false, "has_scope", grey); 263 testSiblingInsertionRemoval("f_has_scope", "direct_next", selector, "has_scope", true, blue, false, grey); 264 testClassChange(removeClass, "blue", "has_scope", selector, false, "has_scope", grey); 265 266 selector = ".skyblue:has(~ #indirect_next:is(.p + .f_descendant ~ .g)) #descendant"; 267 testClassChange(addClass, "skyblue", "has_scope", selector, false, "descendant", grey); 268 testClassChange(addClass, "f_descendant", "previous", selector, true, "descendant", skyblue); 269 testSiblingInsertionRemoval("invalid", "previous", selector, "descendant", false, grey, true, skyblue); 270 testClassChange(removeClass, "f_descendant", "previous", selector, false, "descendant", grey); 271 testSiblingInsertionRemoval("f_descendant", "previous", selector, "descendant", true, skyblue, false, grey); 272 testClassChange(addClass, "f_descendant", "has_scope", selector, true, "descendant", skyblue); 273 testClassChange(removeClass, "f_descendant", "has_scope", selector, false, "descendant", grey); 274 testClassChange(addClass, "f_descendant", "direct_next", selector, true, "descendant", skyblue); 275 testSiblingInsertionRemoval("invalid", "direct_next", selector, "descendant", false, grey, true, skyblue); 276 testClassChange(removeClass, "f_descendant", "direct_next", selector, false, "descendant", grey); 277 testSiblingInsertionRemoval("f_descendant", "direct_next", selector, "descendant", true, skyblue, false, grey); 278 testClassChange(removeClass, "skyblue", "has_scope", selector, false, "descendant", grey); 279 280 selector = ".lightblue:has(~ #indirect_next:is(.p + .f_indirect_next ~ .g)) ~ #indirect_next"; 281 testClassChange(addClass, "lightblue", "has_scope", selector, false, "indirect_next", grey); 282 testClassChange(addClass, "f_indirect_next", "previous", selector, true, "indirect_next", lightblue); 283 testSiblingInsertionRemoval("invalid", "previous", selector, "indirect_next", false, grey, true, lightblue); 284 testClassChange(removeClass, "f_indirect_next", "previous", selector, false, "indirect_next", grey); 285 testSiblingInsertionRemoval("f_indirect_next", "previous", selector, "indirect_next", true, lightblue, false, grey); 286 testClassChange(addClass, "f_indirect_next", "has_scope", selector, true, "indirect_next", lightblue); 287 testClassChange(removeClass, "f_indirect_next", "has_scope", selector, false, "indirect_next", grey); 288 testClassChange(addClass, "f_indirect_next", "direct_next", selector, true, "indirect_next", lightblue); 289 testSiblingInsertionRemoval("invalid", "direct_next", selector, "indirect_next", false, grey, true, lightblue); 290 testClassChange(removeClass, "f_indirect_next", "direct_next", selector, false, "indirect_next", grey); 291 testSiblingInsertionRemoval("f_indirect_next", "direct_next", selector, "indirect_next", true, lightblue, false, grey); 292 testClassChange(removeClass, "lightblue", "has_scope", selector, false, "indirect_next", grey); 293 294 selector = ".darkblue:has(~ #indirect_next:is(.p + .f_indirect_next_child ~ .g)) ~ #indirect_next #indirect_next_child"; 295 testClassChange(addClass, "darkblue", "has_scope", selector, false, "indirect_next_child", grey); 296 testClassChange(addClass, "f_indirect_next_child", "previous", selector, true, "indirect_next_child", darkblue); 297 testSiblingInsertionRemoval("invalid", "previous", selector, "indirect_next_child", false, grey, true, darkblue); 298 testClassChange(removeClass, "f_indirect_next_child", "previous", selector, false, "indirect_next_child", grey); 299 testSiblingInsertionRemoval("f_indirect_next_child", "previous", selector, "indirect_next_child", true, darkblue, false, grey); 300 testClassChange(addClass, "f_indirect_next_child", "has_scope", selector, true, "indirect_next_child", darkblue); 301 testClassChange(removeClass, "f_indirect_next_child", "has_scope", selector, false, "indirect_next_child", grey); 302 testClassChange(addClass, "f_indirect_next_child", "direct_next", selector, true, "indirect_next_child", darkblue); 303 testSiblingInsertionRemoval("invalid", "direct_next", selector, "indirect_next_child", false, grey, true, darkblue); 304 testClassChange(removeClass, "f_indirect_next_child", "direct_next", selector, false, "indirect_next_child", grey); 305 testSiblingInsertionRemoval("f_indirect_next_child", "direct_next", selector, "indirect_next_child", true, darkblue, false, grey); 306 testClassChange(removeClass, "darkblue", "has_scope", selector, false, "indirect_next_child", grey); 307 308 selector = ".yellow:has(~ #indirect_next:is(.h_has_scope .i))" 309 testClassChange(addClass, "yellow", "has_scope", selector, false, "has_scope", grey); 310 testClassChange(addClass, "h_has_scope", "parent", selector, true, "has_scope", yellow); 311 testClassChange(removeClass, "h_has_scope", "parent", selector, false, "has_scope", grey); 312 testClassChange(removeClass, "yellow", "has_scope", selector, false, "has_scope", grey); 313 314 selector = ".ivory:has(~ #indirect_next:is(.h_descendant .i)) #descendant"; 315 testClassChange(addClass, "ivory", "has_scope", selector, false, "descendant", grey); 316 testClassChange(addClass, "h_descendant", "parent", selector, true, "descendant", ivory); 317 testClassChange(removeClass, "h_descendant", "parent", selector, false, "descendant", grey); 318 testClassChange(removeClass, "ivory", "has_scope", selector, false, "descendant", grey); 319 320 selector = ".greenyellow:has(~ #indirect_next:is(.h_indirect_next .i)) ~ #indirect_next"; 321 testClassChange(addClass, "greenyellow", "has_scope", selector, false, "indirect_next", grey); 322 testClassChange(addClass, "h_indirect_next", "parent", selector, true, "indirect_next", greenyellow); 323 testClassChange(removeClass, "h_indirect_next", "parent", selector, false, "indirect_next", grey); 324 testClassChange(removeClass, "greenyellow", "has_scope", selector, false, "indirect_next", grey); 325 326 selector = ".khaki:has(~ #indirect_next:is(.h_indirect_next_child .i)) ~ #indirect_next #indirect_next_child"; 327 testClassChange(addClass, "khaki", "has_scope", selector, false, "indirect_next_child", grey); 328 testClassChange(addClass, "h_indirect_next_child", "parent", selector, true, "indirect_next_child", khaki); 329 testClassChange(removeClass, "h_indirect_next_child", "parent", selector, false, "indirect_next_child", grey); 330 testClassChange(removeClass, "khaki", "has_scope", selector, false, "indirect_next_child", grey); 331 332 selector = ".purple:has(~ #indirect_next:is(.p + .j_has_scope ~ .k .l))" 333 testClassChange(addClass, "purple", "has_scope", selector, false, "has_scope", grey); 334 testClassChange(addClass, "j_has_scope", "parent_previous", selector, true, "has_scope", purple); 335 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "has_scope", false, grey, true, purple); 336 testClassChange(removeClass, "j_has_scope", "parent_previous", selector, false, "has_scope", grey); 337 testSiblingInsertionRemoval("j_has_scope", "parent_previous", selector, "has_scope", true, purple, false, grey); 338 testClassChange(removeClass, "purple", "has_scope", selector, false, "has_scope", grey); 339 340 selector = ".violet:has(~ #indirect_next:is(.p + .j_descendant ~ .k .l)) #descendant"; 341 testClassChange(addClass, "violet", "has_scope", selector, false, "descendant", grey); 342 testClassChange(addClass, "j_descendant", "parent_previous", selector, true, "descendant", violet); 343 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "descendant", false, grey, true, violet); 344 testClassChange(removeClass, "j_descendant", "parent_previous", selector, false, "descendant", grey); 345 testSiblingInsertionRemoval("j_descendant", "parent_previous", selector, "descendant", true, violet, false, grey); 346 testClassChange(removeClass, "violet", "has_scope", selector, false, "descendant", grey); 347 348 selector = ".orchid:has(~ #indirect_next:is(.p + .j_indirect_next ~ .k .l)) ~ #indirect_next"; 349 testClassChange(addClass, "orchid", "has_scope", selector, false, "indirect_next", grey); 350 testClassChange(addClass, "j_indirect_next", "parent_previous", selector, true, "indirect_next", orchid); 351 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "indirect_next", false, grey, true, orchid); 352 testClassChange(removeClass, "j_indirect_next", "parent_previous", selector, false, "indirect_next", grey); 353 testSiblingInsertionRemoval("j_indirect_next", "parent_previous", selector, "indirect_next", true, orchid, false, grey); 354 testClassChange(removeClass, "orchid", "has_scope", selector, false, "indirect_next", grey); 355 356 selector = ".plum:has(~ #indirect_next:is(.p + .j_indirect_next_child ~ .k .l)) ~ #indirect_next #indirect_next_child"; 357 testClassChange(addClass, "plum", "has_scope", selector, false, "indirect_next_child", grey); 358 testClassChange(addClass, "j_indirect_next_child", "parent_previous", selector, true, "indirect_next_child", plum); 359 testSiblingInsertionRemoval("invalid", "parent_previous", selector, "indirect_next_child", false, grey, true, plum); 360 testClassChange(removeClass, "j_indirect_next_child", "parent_previous", selector, false, "indirect_next_child", grey); 361 testSiblingInsertionRemoval("j_indirect_next_child", "parent_previous", selector, "indirect_next_child", true, plum, false, grey); 362 testClassChange(removeClass, "plum", "has_scope", selector, false, "indirect_next_child", grey); 363 364 selector = ".orange:has(#descendant:is(:is(.m, .n) .o))"; 365 testClassChange(addClass, "orange", "has_scope", selector, false, "has_scope", grey); 366 testClassChange(addClass, "m", "parent", selector, true, "has_scope", orange); 367 testClassChange(removeClass, "m", "parent", selector, false, "has_scope", grey); 368 testClassChange(addClass, "n", "parent", selector, true, "has_scope", orange); 369 testClassChange(removeClass, "n", "parent", selector, false, "has_scope", grey); 370 testClassChange(addClass, "m", "has_scope", selector, true, "has_scope", orange); 371 testClassChange(removeClass, "m", "has_scope", selector, false, "has_scope", grey); 372 testClassChange(addClass, "n", "has_scope", selector, true, "has_scope", orange); 373 testClassChange(removeClass, "n", "has_scope", selector, false, "has_scope", grey); 374 testClassChange(addClass, "m", "child", selector, true, "has_scope", orange); 375 testClassChange(removeClass, "m", "child", selector, false, "has_scope", grey); 376 testClassChange(addClass, "n", "child", selector, true, "has_scope", orange); 377 testClassChange(removeClass, "n", "child", selector, false, "has_scope", grey); 378 testClassChange(removeClass, "orange", "has_scope", selector, false, "has_scope", grey); 379 </script>