tor-browser

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

Selection-getComposedRanges-range-update.html (12100B)


      1 <!DOCTYPE html>
      2 <html>
      3 <body>
      4 <meta name="assert" content="Selection's composed range should be updated when its associated legacy uncomposed range changes">
      5 <link rel="help" href="https://w3c.github.io/selection-api/#dom-selection-getcomposedranges">
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 
      9 <div id="light">Start outside shadow DOM</div>
     10 <div id="outerHost">outerHost
     11 <template shadowrootmode="open">
     12  <slot></slot>
     13  <div id="innerHost">innerHost
     14   <template shadowrootmode="open">
     15     <slot></slot>
     16   </template>
     17  </div>
     18 </template>
     19 </div>
     20 <div id="lightEnd">End outside shadow DOM</div>
     21 
     22 <script>
     23 
     24 const selection = getSelection();
     25 const outerHost = document.getElementById('outerHost')
     26 const outerRoot = outerHost.shadowRoot;
     27 const innerHost = outerRoot.getElementById('innerHost');
     28 const innerRoot = innerHost.shadowRoot;
     29 
     30 test(() => {
     31  // Setting a selction crossing to shadow tree
     32  selection.setBaseAndExtent(light.firstChild, 10, innerHost.firstChild, 5);
     33  assert_throws_dom("INDEX_SIZE_ERR", function () { selection.getRangeAt(0) });
     34 }, 'If selection crosses shadow boundaries, getRangeAt(0) should throw an IndexSizeError because the end is not in the document tree.');
     35 
     36 test(() => {
     37  // Setting a selection within light tree
     38  selection.setBaseAndExtent(light.firstChild, 10, lightEnd.firstChild, 20);
     39  const liveRange = selection.getRangeAt(0);
     40  const newSpan = document.createElement("span");
     41  liveRange.setStart(newSpan, 0);
     42 
     43  assert_true(liveRange.collapsed);
     44  assert_equals(liveRange.startContainer, newSpan);
     45  assert_equals(liveRange.startOffset, 0);
     46 
     47  assert_true(selection.isCollapsed);
     48  assert_equals(selection.anchorNode, null);
     49  assert_equals(selection.anchorOffset, 0);
     50 
     51  assert_throws_dom("INDEX_SIZE_ERR", function () { selection.getRangeAt(0) });
     52  assert_equals(selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] }).length, 0);
     53 
     54 }, 'modify getRangeAt() range: setStart() to disconnected node will collapse and remove the live range from the selection.');
     55 
     56 test(() => {
     57  // Setting a selection within light tree
     58  selection.setBaseAndExtent(light.firstChild, 10, light.firstChild, 20);
     59  const liveRange = selection.getRangeAt(0);
     60  let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
     61 
     62  assert_equals(liveRange.startContainer, light.firstChild);
     63  assert_equals(liveRange.startOffset, 10);
     64  assert_equals(liveRange.endContainer, light.firstChild);
     65  assert_equals(liveRange.endOffset, 20);
     66 
     67  assert_equals(selection.anchorNode, light.firstChild);
     68  assert_equals(selection.anchorOffset, 10);
     69  assert_equals(selection.focusNode, light.firstChild);
     70  assert_equals(selection.focusOffset, 20);
     71 
     72  assert_equals(composedRange.startContainer, light.firstChild);
     73  assert_equals(composedRange.startOffset, 10);
     74  assert_equals(composedRange.endContainer, light.firstChild);
     75  assert_equals(composedRange.endOffset, 20);
     76 
     77  liveRange.setEnd(innerHost.firstChild, 5);
     78  composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
     79 
     80  assert_true(liveRange.collapsed);
     81  assert_equals(liveRange.startContainer, innerHost.firstChild);
     82  assert_equals(liveRange.startOffset, 5);
     83 
     84  assert_true(selection.isCollapsed);
     85  assert_equals(selection.anchorNode, innerHost.firstChild);
     86  assert_equals(selection.anchorOffset, 5);
     87 
     88  assert_equals(composedRange.startContainer, light.firstChild);
     89  assert_equals(composedRange.startOffset, 10);
     90  assert_equals(composedRange.endContainer, innerHost.firstChild);
     91  assert_equals(composedRange.endOffset, 5);
     92 }, 'modify getRangeAt() range: setEnd() crosses shadow boundary into the shadow DOM and after start, which collapses live range. Composed selection range is not collapsed.');
     93 
     94 test(() => {
     95  // Setting a selection within light tree
     96  selection.setBaseAndExtent(lightEnd.firstChild, 10, lightEnd.firstChild, 20);
     97  const liveRange = selection.getRangeAt(0);
     98  let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
     99 
    100  assert_equals(liveRange.startContainer, lightEnd.firstChild);
    101  assert_equals(liveRange.startOffset, 10);
    102  assert_equals(liveRange.endContainer, lightEnd.firstChild);
    103  assert_equals(liveRange.endOffset, 20);
    104 
    105  assert_equals(selection.anchorNode, lightEnd.firstChild);
    106  assert_equals(selection.anchorOffset, 10);
    107  assert_equals(selection.focusNode, lightEnd.firstChild);
    108  assert_equals(selection.focusOffset, 20);
    109 
    110  assert_equals(composedRange.startContainer, lightEnd.firstChild);
    111  assert_equals(composedRange.startOffset, 10);
    112  assert_equals(composedRange.endContainer, lightEnd.firstChild);
    113  assert_equals(composedRange.endOffset, 20);
    114 
    115  liveRange.setStart(innerHost.firstChild, 5);
    116  composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    117 
    118  assert_true(liveRange.collapsed);
    119  assert_equals(liveRange.startContainer, innerHost.firstChild);
    120  assert_equals(liveRange.startOffset, 5);
    121 
    122  assert_true(selection.isCollapsed);
    123  assert_equals(selection.anchorNode, innerHost.firstChild);
    124  assert_equals(selection.anchorOffset, 5);
    125 
    126  assert_equals(composedRange.startContainer, innerHost.firstChild);
    127  assert_equals(composedRange.startOffset, 5);
    128  assert_equals(composedRange.endContainer, lightEnd.firstChild);
    129  assert_equals(composedRange.endOffset, 20);
    130 }, 'modify getRangeAt() range: setStart() crosses shadow boundary into the shadow DOM and before end, which collapses live range. Composed selection range is not collapsed.');
    131 
    132 test(() => {
    133  // Setting a selection within light tree
    134  selection.setBaseAndExtent(light.firstChild, 10, light.firstChild, 20);
    135  const liveRange = selection.getRangeAt(0);
    136  let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    137 
    138  assert_equals(liveRange.startContainer, light.firstChild);
    139  assert_equals(liveRange.startOffset, 10);
    140  assert_equals(liveRange.endContainer, light.firstChild);
    141  assert_equals(liveRange.endOffset, 20);
    142 
    143  assert_equals(selection.anchorNode, light.firstChild);
    144  assert_equals(selection.anchorOffset, 10);
    145  assert_equals(selection.focusNode, light.firstChild);
    146  assert_equals(selection.focusOffset, 20);
    147 
    148  assert_equals(composedRange.startContainer, light.firstChild);
    149  assert_equals(composedRange.startOffset, 10);
    150  assert_equals(composedRange.endContainer, light.firstChild);
    151  assert_equals(composedRange.endOffset, 20);
    152 
    153  liveRange.setStart(innerHost.firstChild, 5);
    154  composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    155 
    156  assert_true(liveRange.collapsed);
    157  assert_equals(liveRange.startContainer, innerHost.firstChild);
    158  assert_equals(liveRange.startOffset, 5);
    159 
    160  assert_true(selection.isCollapsed);
    161  assert_equals(selection.anchorNode, innerHost.firstChild);
    162  assert_equals(selection.anchorOffset, 5);
    163 
    164  assert_true(composedRange.collapsed);
    165  assert_equals(composedRange.startContainer, innerHost.firstChild);
    166  assert_equals(composedRange.startOffset, 5);
    167 }, 'modify getRangeAt() range: setStart() crosses shadow boundary into the shadow DOM and after end, which collapses both live range and composed selection range.');
    168 
    169 test(() => {
    170  // Setting a selection within light tree
    171  selection.setBaseAndExtent(light.firstChild, 10, lightEnd.firstChild, 20);
    172  const liveRange = selection.getRangeAt(0);
    173  liveRange.selectNode(innerHost);
    174  const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    175 
    176  assert_equals(liveRange.startContainer, outerRoot);
    177  assert_equals(liveRange.startOffset, 3);
    178  assert_equals(liveRange.endContainer, outerRoot);
    179  assert_equals(liveRange.endOffset, 4);
    180 
    181  assert_equals(selection.anchorNode, outerRoot);
    182  assert_equals(selection.anchorOffset, 3);
    183  assert_equals(selection.focusNode, outerRoot);
    184  assert_equals(selection.focusOffset, 4);
    185 
    186  assert_equals(composedRange.startContainer, outerRoot);
    187  assert_equals(composedRange.startOffset, 3);
    188  assert_equals(composedRange.endContainer, outerRoot);
    189  assert_equals(composedRange.endOffset, 4);
    190 }, 'modify getRangeAt() range: selectNode() innerHost for all ranges.');
    191 
    192 test(() => {
    193  // Setting a selection within light tree
    194  selection.setBaseAndExtent(light.firstChild, 10, lightEnd.firstChild, 20);
    195  const liveRange = selection.getRangeAt(0);
    196  liveRange.collapse();
    197  const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    198 
    199  assert_true(liveRange.collapsed);
    200  assert_equals(liveRange.startContainer, lightEnd.firstChild);
    201  assert_equals(liveRange.startOffset, 20);
    202 
    203  assert_true(selection.isCollapsed);
    204  assert_equals(selection.anchorNode, lightEnd.firstChild);
    205  assert_equals(selection.anchorOffset, 20);
    206 
    207  assert_true(composedRange.collapsed);
    208  assert_equals(composedRange.startContainer, lightEnd.firstChild);
    209  assert_equals(composedRange.startOffset, 20);
    210 }, 'modify getRangeAt() range: collapse() collapses all ranges.');
    211 
    212 test(() => {
    213  // Step 1: Creating a live range and only setting its end/anchor
    214  selection.removeAllRanges();
    215  const liveRange = document.createRange();
    216  liveRange.setEnd(innerHost.firstChild, 5);
    217  const composedRanges = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] });
    218 
    219  assert_true(liveRange.collapsed);
    220  assert_equals(liveRange.startContainer, innerHost.firstChild);
    221  assert_equals(liveRange.startOffset, 5);
    222 
    223  assert_true(selection.isCollapsed);
    224  assert_equals(selection.anchorNode, null);
    225  assert_equals(selection.anchorOffset, 0);
    226 
    227  assert_equals(composedRanges.length, 0, 'range is not added to selection yet.');
    228 
    229  // Step 2: Add range to selection so range API updates will change selection
    230  selection.addRange(liveRange);
    231  const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    232 
    233  assert_true(liveRange.collapsed);
    234  assert_equals(liveRange.endContainer, innerHost.firstChild);
    235  assert_equals(liveRange.endOffset, 5);
    236 
    237  assert_true(selection.isCollapsed);
    238  assert_equals(selection.anchorNode, innerHost.firstChild);
    239  assert_equals(selection.anchorOffset, 5);
    240 
    241  assert_true(composedRange.collapsed);
    242  assert_equals(composedRange.startContainer, innerHost.firstChild);
    243  assert_equals(composedRange.startOffset, 5);
    244 }, 'modify createRange() range: adding to selection sets the selection');
    245 
    246 test(() => {
    247  // Step 1: Creating a live range and only setting its end/anchor
    248  selection.removeAllRanges();
    249  const liveRange = document.createRange();
    250  // Add range to selection so range API updates will change selection
    251  selection.addRange(liveRange);
    252  liveRange.setEnd(innerHost.firstChild, 5);
    253  let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    254 
    255  assert_true(liveRange.collapsed);
    256  assert_equals(liveRange.startContainer, innerHost.firstChild);
    257  assert_equals(liveRange.startOffset, 5);
    258 
    259  assert_true(selection.isCollapsed);
    260  assert_equals(selection.anchorNode, innerHost.firstChild);
    261  assert_equals(selection.anchorOffset, 5);
    262 
    263  assert_equals(composedRange.startContainer, document);
    264  assert_equals(composedRange.startOffset, 0);
    265  assert_equals(composedRange.endContainer, innerHost.firstChild);
    266  assert_equals(composedRange.endOffset, 5);
    267 
    268  // Step 2: Update the live range by setting its start/focus
    269  liveRange.setStart(light.firstChild, 10);
    270  composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
    271 
    272  assert_true(liveRange.collapsed);
    273  assert_equals(liveRange.startContainer, light.firstChild);
    274  assert_equals(liveRange.startOffset, 10);
    275 
    276  assert_true(selection.isCollapsed);
    277  assert_equals(selection.anchorNode, light.firstChild);
    278  assert_equals(selection.anchorOffset, 10);
    279 
    280  assert_equals(composedRange.startContainer, light.firstChild);
    281  assert_equals(composedRange.startOffset, 10);
    282  assert_equals(composedRange.endContainer, innerHost.firstChild);
    283  assert_equals(composedRange.endOffset, 5);
    284 }, 'modify createRange() range: added to selection before setStart/setEnd calls.');
    285 </script>