tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

has-in-adjacent-position.html (11780B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <title>CSS Selector Invalidation: :has() in adjacent position</title>
      4 <link rel="author" title="Antti Koivisto" href="mailto:antti@apple.com">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <link rel="help" href="https://drafts.csswg.org/selectors/#relational">
      8 <style>
      9 div, main { color: grey }
     10 div:has(.test) + #subject { color: red }
     11 div:has([test_attr]) + #subject { color: orangered }
     12 div:has(> .test) + #subject { color: green }
     13 div:has(> [test_attr]) + #subject { color: lightgreen }
     14 div:has(~ .test) + #subject { color: yellow }
     15 div:has(~ [test_attr]) + #subject { color: ivory }
     16 div:has(+ .test) + #subject { color: blue }
     17 div:has(+ [test_attr]) + #subject { color: skyblue }
     18 div:has(~ div .test) + #subject { color: purple }
     19 div:has(~ div [test_attr]) + #subject { color: violet }
     20 div:has(+ div .test) + #subject { color: pink }
     21 div:has(+ div [test_attr]) + #subject { color: lightpink }
     22 </style>
     23 
     24 <main id=main>
     25    <div id=previous_sibling>
     26        <div id=previous_sibling_child>
     27            <div id=previous_sibling_descendant></div>
     28        </div>
     29    </div>
     30    <div id=subject></div>
     31    <div id=next_sibling>
     32        <div id=next_sibling_child>
     33            <div id=next_sibling_descendant></div>
     34        </div>
     35    </div>
     36 </main>
     37 
     38 <script>
     39 const grey = 'rgb(128, 128, 128)';
     40 const red = 'rgb(255, 0, 0)';
     41 const orangered = 'rgb(255, 69, 0)';
     42 const green = 'rgb(0, 128, 0)';
     43 const lightgreen = 'rgb(144, 238, 144)';
     44 const blue = 'rgb(0, 0, 255)';
     45 const skyblue = 'rgb(135, 206, 235)';
     46 const yellow = 'rgb(255, 255, 0)';
     47 const ivory = 'rgb(255, 255, 240)';
     48 const purple = 'rgb(128, 0, 128)';
     49 const violet = 'rgb(238, 130, 238)';
     50 const pink = 'rgb(255, 192, 203)';
     51 const lightpink = 'rgb(255, 182, 193)';
     52 const colors = {
     53  grey: {
     54    classTest: grey,
     55    attributeTest: grey,
     56  },
     57  red: {
     58    classTest: red,
     59    attributeTest: orangered,
     60  },
     61  green: {
     62    classTest: green,
     63    attributeTest: lightgreen,
     64  },
     65  blue: {
     66    classTest: blue,
     67    attributeTest: skyblue,
     68  },
     69  yellow: {
     70    classTest: yellow,
     71    attributeTest: ivory,
     72  },
     73  purple: {
     74    classTest: purple,
     75    attributeTest: violet,
     76  },
     77  pink: {
     78    classTest: pink,
     79    attributeTest: lightpink,
     80  },
     81 };
     82 
     83 function testColor(test_name, color) {
     84    test(function() {
     85        assert_equals(getComputedStyle(subject).color, color);
     86    }, test_name);
     87 }
     88 
     89 function testClassChange(element, expectedColorName)
     90 {
     91    const expectedColorForClassTest = colors[expectedColorName].classTest;
     92    element.classList.add('test');
     93    testColor(`add .test to ${element.id}`, expectedColorForClassTest);
     94    element.classList.remove('test');
     95    testColor(`remove .test from ${element.id}`, grey);
     96 }
     97 
     98 function testElementInsertionBefore(beforeElement, expectedColorName)
     99 {
    100    const expectedColorForClassTest = colors[expectedColorName].classTest;
    101    const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
    102    const newElement = document.createElement('div');
    103    newElement.classList.add('test')
    104 
    105    beforeElement.before(newElement);
    106    testColor(`insert element div.test before ${beforeElement.id}`, expectedColorForClassTest);
    107 
    108    newElement.classList.remove('test');
    109    testColor(`remove the class 'test' from the element inserted before ${beforeElement.id}`, grey);
    110 
    111    newElement.classList.add('test');
    112    testColor(`add the class 'test' again to the element inserted before ${beforeElement.id}`, expectedColorForClassTest);
    113 
    114    newElement.remove();
    115    testColor(`remove element div.test before ${beforeElement.id}`, grey);
    116 
    117    newElement.classList.remove('test');
    118 
    119    beforeElement.before(newElement);
    120    testColor(`insert element div before ${beforeElement.id}`, grey);
    121 
    122    newElement.classList.add('test');
    123    testColor(`add the class 'test' to the element inserted again before ${beforeElement.id}`, expectedColorForClassTest);
    124 
    125    newElement.classList.remove('test');
    126    testColor(`remove the class 'test' from the element inserted again before ${beforeElement.id}`, grey);
    127 
    128    newElement.remove();
    129    testColor(`remove element div before ${beforeElement.id}`, grey);
    130 
    131    newElement.setAttribute('test_attr', '');
    132 
    133    beforeElement.before(newElement);
    134    testColor(`insert element div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
    135 
    136    newElement.remove();
    137    testColor(`remove element div[test_attr] before ${beforeElement.id}`, grey);
    138 }
    139 
    140 function testElementInsertionAfter(afterElement, expectedColorName)
    141 {
    142    const expectedColorForClassTest = colors[expectedColorName].classTest;
    143    const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
    144    const newElement = document.createElement('div');
    145    newElement.classList.add('test')
    146 
    147    afterElement.after(newElement);
    148    testColor(`insert element div.test after ${afterElement.id}`, expectedColorForClassTest);
    149 
    150    newElement.classList.remove('test');
    151    testColor(`remove the class 'test' from the element inserted after ${afterElement.id}`, grey);
    152 
    153    newElement.classList.add('test');
    154    testColor(`add the class 'test' again to the element inserted after ${afterElement.id}`, expectedColorForClassTest);
    155 
    156    newElement.remove();
    157    testColor(`remove element div.test after ${afterElement.id}`, grey);
    158 
    159    newElement.classList.remove('test');
    160 
    161    afterElement.after(newElement);
    162    testColor(`insert element div after ${afterElement.id}`, grey);
    163 
    164    newElement.classList.add('test');
    165    testColor(`add the class 'test' to the element inserted again after ${afterElement.id}`, expectedColorForClassTest);
    166 
    167    newElement.classList.remove('test');
    168    testColor(`remove the class 'test' from the element inserted again after ${afterElement.id}`, grey);
    169 
    170    newElement.remove();
    171    testColor(`remove element div after ${afterElement.id}`, grey);
    172 
    173    newElement.setAttribute('test_attr', '');
    174 
    175    afterElement.after(newElement);
    176    testColor(`insert element div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
    177 
    178    newElement.remove();
    179    testColor(`remove element div[test_attr] after ${afterElement.id}`, grey);
    180 }
    181 
    182 function testTreeInsertionBefore(beforeElement, expectedColorName)
    183 {
    184    const expectedColorForClassTest = colors[expectedColorName].classTest;
    185    const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
    186    const newElement = document.createElement('div');
    187    const newChild = document.createElement('div');
    188    newChild.classList.add('test');
    189    newElement.appendChild(newChild);
    190 
    191    beforeElement.before(newElement);
    192    testColor(`insert tree div>div.test before ${beforeElement.id}`, expectedColorForClassTest);
    193 
    194    newChild.classList.remove('test');
    195    testColor(`remove the class 'test' from the element in the tree inserted before ${beforeElement.id}`, grey);
    196 
    197    newChild.classList.add('test');
    198    testColor(`add the class 'test' again to the element in the tree inserted before ${beforeElement.id}`, expectedColorForClassTest);
    199 
    200    newElement.remove();
    201    testColor(`remove tree div>div.test before ${beforeElement.id}`, grey);
    202 
    203    newChild.classList.remove('test');
    204 
    205    beforeElement.before(newElement);
    206    testColor(`insert tree div>div before ${beforeElement.id}`, grey);
    207 
    208    newChild.classList.add('test');
    209    testColor(`add the class 'test' to the element in the tree inserted again before ${beforeElement.id}`, expectedColorForClassTest);
    210 
    211    newChild.classList.remove('test');
    212    testColor(`remove the class 'test' from the element in the tree inserted again before ${beforeElement.id}`, grey);
    213 
    214    newElement.remove();
    215    testColor(`remove tree div>div before ${beforeElement.id}`, grey);
    216 
    217    newChild.setAttribute('test_attr', '');
    218 
    219    beforeElement.before(newElement);
    220    testColor(`insert element div>div[test_attr] before ${beforeElement.id}`, expectedColorForAttributeTest);
    221 
    222    newElement.remove();
    223    testColor(`remove element div>div[test_attr] before ${beforeElement.id}`, grey);
    224 }
    225 
    226 function testTreeInsertionAfter(afterElement, expectedColorName)
    227 {
    228    const expectedColorForClassTest = colors[expectedColorName].classTest;
    229    const expectedColorForAttributeTest = colors[expectedColorName].attributeTest;
    230    const newElement = document.createElement('div');
    231    const newChild = document.createElement('div');
    232    newChild.classList.add('test');
    233    newElement.appendChild(newChild);
    234 
    235    afterElement.after(newElement);
    236    testColor(`insert tree div>div.test after ${afterElement.id}`, expectedColorForClassTest);
    237 
    238    newChild.classList.remove('test');
    239    testColor(`remove the class 'test' from the element in the tree inserted after ${afterElement.id}`, grey);
    240 
    241    newChild.classList.add('test');
    242    testColor(`add the class 'test' again to the element in the tree inserted after ${afterElement.id}`, expectedColorForClassTest);
    243 
    244    newElement.remove();
    245    testColor(`remove tree div>div.test after ${afterElement.id}`, grey);
    246 
    247    newChild.classList.remove('test');
    248 
    249    afterElement.after(newElement);
    250    testColor(`insert tree div>div after ${afterElement.id}`, grey);
    251 
    252    newChild.classList.add('test');
    253    testColor(`add the class 'test' to the element in the tree inserted again after ${afterElement.id}`, expectedColorForClassTest);
    254 
    255    newChild.classList.remove('test');
    256    testColor(`remove the class 'test' from the element in the tree inserted again after ${afterElement.id}`, grey);
    257 
    258    newElement.remove();
    259    testColor(`remove tree div>div after ${afterElement.id}`, grey);
    260 
    261    newChild.setAttribute('test_attr', '');
    262 
    263    afterElement.after(newElement);
    264    testColor(`insert element div>div[test_attr] after ${afterElement.id}`, expectedColorForAttributeTest);
    265 
    266    newElement.remove();
    267    testColor(`remove element div>div[test_attr] after ${afterElement.id}`, grey);
    268 }
    269 
    270 testColor('Initial color', grey);
    271 
    272 testClassChange(previous_sibling, "grey");
    273 testClassChange(previous_sibling_child, "green");
    274 testClassChange(previous_sibling_descendant, "red");
    275 testClassChange(subject, "blue");
    276 testClassChange(next_sibling, "yellow");
    277 testClassChange(next_sibling_child, "purple");
    278 testClassChange(next_sibling_descendant, "purple");
    279 
    280 testElementInsertionBefore(previous_sibling, "grey");
    281 testElementInsertionBefore(previous_sibling_child, "green");
    282 testElementInsertionBefore(previous_sibling_descendant, "red");
    283 testElementInsertionBefore(subject, "grey");
    284 testElementInsertionBefore(next_sibling, "yellow");
    285 testElementInsertionBefore(next_sibling_child, "purple");
    286 testElementInsertionBefore(next_sibling_descendant, "purple");
    287 
    288 testElementInsertionAfter(previous_sibling, "grey");
    289 testElementInsertionAfter(previous_sibling_child, "green");
    290 testElementInsertionAfter(previous_sibling_descendant, "red");
    291 testElementInsertionAfter(subject, "yellow");
    292 testElementInsertionAfter(next_sibling, "yellow");
    293 testElementInsertionAfter(next_sibling_child, "purple");
    294 testElementInsertionAfter(next_sibling_descendant, "purple");
    295 
    296 testTreeInsertionBefore(previous_sibling, "grey");
    297 testTreeInsertionBefore(previous_sibling_child, "red");
    298 testTreeInsertionBefore(previous_sibling_descendant, "red");
    299 testTreeInsertionBefore(subject, "green");
    300 testTreeInsertionBefore(next_sibling, "purple");
    301 testTreeInsertionBefore(next_sibling_child, "purple");
    302 testTreeInsertionBefore(next_sibling_descendant, "purple");
    303 
    304 testTreeInsertionAfter(previous_sibling, "green");
    305 testTreeInsertionAfter(previous_sibling_child, "red");
    306 testTreeInsertionAfter(previous_sibling_descendant, "red");
    307 testTreeInsertionAfter(subject, "purple");
    308 testTreeInsertionAfter(next_sibling, "purple");
    309 testTreeInsertionAfter(next_sibling_child, "purple");
    310 testTreeInsertionAfter(next_sibling_descendant, "purple");
    311 
    312 </script>