tor-browser

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

selection-preserve.html (6080B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <script src='/resources/testharness.js'></script>
      5 <script src='/resources/testharnessreport.js'></script>
      6 <script src="/resources/testdriver.js"></script>
      7 <script src="/resources/testdriver-actions.js"></script>
      8 <script src="/resources/testdriver-vendor.js"></script>
      9 </head>
     10 
     11 <body>
     12 </body>
     13 
     14 <script>
     15 'use strict';
     16 
     17 async function select_range(t, anchorNode, focusNode) {
     18  await new test_driver.Actions()
     19      .pointerMove(0, 0, {origin: anchorNode})
     20      .pointerDown()
     21      .pointerMove(focusNode.clientWidth, focusNode.clientHeight, {origin: focusNode})
     22      .pointerUp()
     23      .send();
     24 }
     25 
     26 promise_test(async t => {
     27  document.body.innerHTML = `
     28    <div id=old_parent>
     29      <span id=notMove>This text does not move</span>
     30      <span id=text>Text</span>
     31    </div>
     32    <div id=new_parent></div>`;
     33  getSelection().removeAllRanges();
     34 
     35  await select_range(t, text, text);
     36 
     37  // XXX This test seems to rely on Chromium internal behavior!
     38  // Don't first verify that `getSelection().anchorNode` is the expected
     39  // `<span id=text>` node that was selected above. If we did that, then at
     40  // least in Chromium browsers, this would generate a new Range capturing the
     41  // visual selection, which would be cached to the internal `DOMSelection`
     42  // object. Then the move would have two effects:
     43  //
     44  // 1. The internal visual selection would change as a result of
     45  //    `moveBefore()`
     46  // 2. But the Range representing the visual selection would remain
     47  //    unchanged, since it was cached to the `DOMSelection` object and not
     48  //    updated during `moveBefore()`. This means if (a) the visual selection,
     49  //    and (b) the "API-returned" selection Range are out of sync after
     50  //    `moveBefore()`, it would be impossible to detect the discrepancy
     51  //    without a reftest.
     52  //
     53  // So instead, we will just dive right into `moveBefore()`, and then compute
     54  // the selection range *after*, which will accurately represent the internal
     55  // visual selection that the user sees, and we can run our assertions on it.
     56  new_parent.moveBefore(text, null);
     57  assert_equals(getSelection().anchorNode, notMove.firstChild);
     58  assert_equals(getSelection().focusNode, notMove.firstChild);
     59 }, "moveBefore should not reset selection with preceding text");
     60 
     61 const kHTML = `
     62  <div id=grandparentDiv>
     63    <span id=grandparentParagraph>Grandparent paragraph</span>
     64    <div id=parentDiv>
     65      <span id=parentParagraph>Parent paragraph</span>
     66      <div id=childDiv>
     67        <span id=childParagraph1>Child paragraph one</span>
     68        <span id=childParagraph2>Paragraph two</span>
     69      </div>
     70    </div>
     71  </div>
     72 `;
     73 
     74 // Selection spans parent->child.
     75 promise_test(async t => {
     76  document.body.innerHTML = kHTML;
     77  getSelection().removeAllRanges();
     78  await select_range(t, parentParagraph, childParagraph1);
     79 
     80  grandparentDiv.moveBefore(parentDiv, grandparentParagraph);
     81  assert_equals(getSelection().anchorNode, grandparentParagraph.firstChild);
     82  assert_equals(getSelection().focusNode, grandparentParagraph.firstChild);
     83 }, "moveBefore resets selection that enters a subtree, when the whole " +
     84   "selection is moved");
     85 
     86 // Selection anchor node is moved upwards in the DOM, to suddenly intersect more
     87 // nodes.
     88 promise_test(async t => {
     89  document.body.innerHTML = kHTML;
     90  getSelection().removeAllRanges();
     91  await select_range(t, parentParagraph, childParagraph1);
     92 
     93  grandparentDiv.moveBefore(parentParagraph, grandparentParagraph);
     94  assert_equals(getSelection().anchorNode, childParagraph1.firstChild);
     95  assert_equals(getSelection().focusNode, childParagraph1.firstChild);
     96  assert_false(getSelection().getRangeAt(0).intersectsNode(grandparentParagraph));
     97 }, "moveBefore anchor node moved up to expand selection and absorb nodes");
     98 
     99 // Intersecting nodes are moved *out* of the selection.
    100 promise_test(async t => {
    101  document.body.innerHTML = kHTML;
    102  getSelection().removeAllRanges();
    103  await select_range(t, grandparentParagraph, childParagraph2);
    104 
    105  grandparentDiv.moveBefore(childParagraph1, grandparentParagraph);
    106  assert_equals(getSelection().anchorNode, grandparentParagraph.firstChild);
    107  assert_equals(getSelection().focusNode, childParagraph2.firstChild);
    108  assert_false(getSelection().getRangeAt(0).intersectsNode(childParagraph1));
    109 }, "moveBefore move intersecting nodes out of a selection");
    110 
    111 // Selection focus node is moved upwards in the DOM, shrinking the selection and
    112 // excluding once-intersecting nodes.
    113 promise_test(async t => {
    114  document.body.innerHTML = kHTML;
    115  getSelection().removeAllRanges();
    116  await select_range(t, grandparentParagraph, childParagraph2);
    117 
    118  parentDiv.moveBefore(childDiv, parentParagraph);
    119  assert_equals(getSelection().anchorNode, grandparentParagraph.firstChild);
    120  assert_equals(getSelection().focusNode, parentParagraph.firstChild);
    121  assert_true(getSelection().getRangeAt(0).intersectsNode(parentParagraph));
    122 }, "moveBefore focus node moved up to shrink selection and exclude nodes; " +
    123   "focus node gets reset");
    124 
    125 // Selection focus node is moved upwards in the DOM, shrinking the selection and
    126 // excluding once-intersecting nodes.
    127 promise_test(async t => {
    128  document.body.innerHTML = `
    129    <ul id=list>
    130      <li id=i1>One</li>
    131      <li id=i2>Two</li>
    132      <li id=i3>Three</li>
    133      <li id=i4>Four</li>
    134    </ul>
    135  `;
    136  getSelection().removeAllRanges();
    137  await select_range(t, i3, i4);
    138 
    139  // Move the last list item (the selection focus node) to the position before
    140  // the first. This resets the range to be collapsed at `i3`.
    141  list.moveBefore(i4, i1);
    142  assert_equals(getSelection().focusNode, i3.firstChild);
    143  assert_equals(getSelection().anchorNode, i3.firstChild);
    144  assert_true(getSelection().getRangeAt(0).collapsed, "Range is collased at `i3`");
    145  assert_false(getSelection().getRangeAt(0).intersectsNode(i2),
    146      "Range does not intersect node that comes before anchor");
    147  assert_true(getSelection().getRangeAt(0).intersectsNode(i3));
    148 }, "moveBefore selection is not preserved, especially when underlying range " +
    149   "gets inverted");
    150 </script>
    151 </html>