| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title>CSS Selector Invalidation: :has() with pseudo-classes</title> |
| <link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> |
| <style> |
| main:has(input) div { color: grey } |
| main:has(#checkbox:checked) > #subject { color: red } |
| main:has(#option:checked) > #subject { color: red } |
| main:has(#checkbox:disabled) > #subject { color: green } |
| main:has(#option:disabled) > :is(#subject, #subject2) { color: green } |
| main:has(#optgroup:disabled) > #subject { color: blue } |
| main:not(:has(#checkbox:enabled)) > #subject3 { color: green } |
| main:not(:has(#option:enabled)) :is(#subject3, #subject4) { color: green } |
| main:not(:has(#optgroup:enabled)) > #subject3 { color: blue } |
| main:has(#text_input:valid) > #subject { color: yellow } |
| main:not(:has(#text_input:invalid)) > #subject2 { color: yellow } |
| main:has(#form:valid) > #subject3 { color: yellow } |
| main:not(:has(#form:invalid)) > #subject4 { color: yellow } |
| </style> |
| |
| <main id=main> |
| <form id=form> |
| <input type=checkbox id=checkbox></input> |
| <select id=select><optgroup id=optgroup><option>a</option><option id=option>b</option></optgroup></select> |
| <input id=text_input type=text required></input> |
| </form> |
| <div id=subject></div> |
| <div id=subject2></div> |
| <div id=subject3></div> |
| <div id=subject4></div> |
| </main> |
| |
| <script> |
| const grey = 'rgb(128, 128, 128)'; |
| const red = 'rgb(255, 0, 0)'; |
| const green = 'rgb(0, 128, 0)'; |
| const blue = 'rgb(0, 0, 255)'; |
| const yellow = 'rgb(255, 255, 0)'; |
| const purple = 'rgb(128, 0, 128)'; |
| const pink = 'rgb(255, 192, 203)'; |
| |
| function testColor(test_name, subject_element, color) { |
| test(function() { |
| assert_equals(getComputedStyle(subject_element).color, color); |
| }, test_name); |
| } |
| |
| function testPseudoClassChange(element, property, subject_element, expectedColor) |
| { |
| testColor(`Before set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey); |
| |
| element[property] = true; |
| testColor(`Set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, expectedColor); |
| |
| element[property] = false; |
| testColor(`Unset ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey); |
| } |
| |
| function testSelectedChange(option, subject_element, expectedColor) |
| { |
| const oldOption = select.selectedOptions[0]; |
| option.selected = true; |
| testColor(`Set select on ${option.id}`, subject_element, expectedColor); |
| oldOption.selected = true; |
| testColor(`Reset select`, subject, grey); |
| } |
| |
| function testValueChange(input, subject_element, expectedColor) |
| { |
| testColor(`Before setting value of ${input.id}, testing ${subject_element.id}`, subject_element, grey); |
| |
| input.value = "value"; |
| testColor(`Set value of ${input.id}, testing ${subject_element.id}`, subject_element, expectedColor); |
| |
| input.value = ""; |
| testColor(`Clear value of ${input.id}, testing ${subject_element.id}`, subject_element, grey); |
| } |
| |
| testPseudoClassChange(checkbox, "checked", subject, red); |
| testSelectedChange(option, subject, red); |
| |
| testPseudoClassChange(checkbox, "disabled", subject, green); |
| testPseudoClassChange(checkbox, "disabled", subject3, green); |
| testPseudoClassChange(option, "disabled", subject, green); |
| testPseudoClassChange(option, "disabled", subject3, green); |
| |
| testPseudoClassChange(optgroup, "disabled", subject, blue); |
| testPseudoClassChange(optgroup, "disabled", subject2, green); |
| testPseudoClassChange(optgroup, "disabled", subject3, blue); |
| testPseudoClassChange(optgroup, "disabled", subject4, green); |
| |
| testValueChange(text_input, subject, yellow); |
| testValueChange(text_input, subject2, yellow); |
| testValueChange(text_input, subject3, yellow); |
| testValueChange(text_input, subject4, yellow); |
| </script> |