tor-browser

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

has-in-parent-position.html (11049B)


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