tor-browser

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

move-around-contenteditable-false.html (6265B)


      1 <!doctype html>
      2 <html>
      3 <head>
      4 <meta charset="utf-8">
      5 <title>Don't move caret to non-editable node from a editable node</title>
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="/resources/testdriver.js"></script>
      9 <script src="/resources/testdriver-vendor.js"></script>
     10 <script src="/resources/testdriver-actions.js"></script>
     11 <script>
     12 "use strict";
     13 
     14 function getRangeDescription(range) {
     15  function getNodeDescription(node) {
     16    if (!node) {
     17      return "null";
     18    }
     19    switch (node.nodeType) {
     20      case Node.TEXT_NODE:
     21        return `${node.nodeName} "${node.data}"`;
     22      case Node.ELEMENT_NODE:
     23        return `<${node.nodeName.toLowerCase()}>`;
     24      default:
     25        return `${node.nodeName}`;
     26    }
     27  }
     28  if (range === null) {
     29    return "null";
     30  }
     31  if (range === undefined) {
     32    return "undefined";
     33  }
     34  return range.startContainer == range.endContainer &&
     35    range.startOffset == range.endOffset
     36    ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})`
     37    : `(${getNodeDescription(range.startContainer)}, ${
     38        range.startOffset
     39      }) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`;
     40 }
     41 
     42 function sendArrowRightKey() {
     43  const kArrowRight = "\uE014";
     44  return new test_driver.Actions()
     45    .keyDown(kArrowRight)
     46    .keyUp(kArrowRight)
     47    .send();
     48 }
     49 
     50 function sendArrowLeftKey() {
     51  const kArrowLeft = "\uE012";
     52  return new test_driver.Actions()
     53    .keyDown(kArrowLeft)
     54    .keyUp(kArrowLeft)
     55    .send();
     56 }
     57 
     58 promise_test(async () => {
     59  await new Promise(resolve => {
     60    addEventListener("load", resolve, {once: true});
     61  });
     62 }, "Initializing tests");
     63 
     64 promise_test(async t => {
     65  const editingHost = document.querySelector("div[contenteditable]");
     66  editingHost.focus();
     67  const p = editingHost.querySelector("p");
     68  getSelection().collapse(p.firstChild, "abc".length);
     69  await sendArrowRightKey();
     70  test(() => {
     71    assert_equals(
     72      getRangeDescription(getSelection().getRangeAt(0)),
     73      getRangeDescription({
     74        startContainer: p.nextSibling,
     75        startOffset: 0,
     76        endContainer: p.nextSibling,
     77        endOffset: 0,
     78      }),
     79    );
     80  }, `${t.name}: first arrow-right should move caret before non-editable text`);
     81  await sendArrowRightKey();
     82  test(() => {
     83    assert_equals(
     84      getRangeDescription(getSelection().getRangeAt(0)),
     85      getRangeDescription({
     86        startContainer: p.nextSibling,
     87        startOffset: 1,
     88        endContainer: p.nextSibling,
     89        endOffset: 1,
     90      }),
     91    );
     92  }, `${t.name}: second arrow-right should move caret after non-editable text`);
     93 }, "Move caret from end of editable text node to <br> following non-editable text in next paragraph");
     94 
     95 promise_test(async t => {
     96  const editingHost = document.querySelector("div[contenteditable]");
     97  editingHost.focus();
     98  const p = editingHost.querySelector("p");
     99  getSelection().collapse(p.nextSibling, 1);
    100  await sendArrowLeftKey();
    101  assert_false(
    102    editingHost.querySelector("[contenteditable=false]").contains(getSelection().focusNode),
    103    "focus node should not be the non-editable nodes"
    104  );
    105  assert_false(
    106    editingHost.querySelector("[contenteditable=false]").contains(getSelection().anchorNode),
    107    "anchor node should not be the non-editable nodes"
    108  );
    109  test(() => {
    110    assert_equals(
    111      getRangeDescription(getSelection().getRangeAt(0)),
    112      getRangeDescription({
    113        startContainer: p.nextSibling,
    114        startOffset: 0,
    115        endContainer: p.nextSibling,
    116        endOffset: 0,
    117      }),
    118    );
    119  }, `${t.name}: first arrow-left should move caret before non-editable text`);
    120 }, "Move caret from <br> following non-editable text to end of preceding editable text in next paragraph");
    121 
    122 promise_test(async t => {
    123  const editingHost = document.querySelector("div[contenteditable] + div[contenteditable]");
    124  editingHost.focus();
    125  const p = editingHost.querySelector("p");
    126  getSelection().collapse(p.firstChild, 0);
    127  await sendArrowRightKey();
    128  test(() => {
    129    assert_equals(
    130      getRangeDescription(getSelection().getRangeAt(0)),
    131      getRangeDescription({
    132        startContainer: p.nextSibling,
    133        startOffset: 0,
    134        endContainer: p.nextSibling,
    135        endOffset: 0,
    136      }),
    137    );
    138  }, `${t.name}: first arrow-right should move caret before non-editable text`);
    139  await sendArrowRightKey();
    140  test(() => {
    141    assert_equals(
    142      getRangeDescription(getSelection().getRangeAt(0)),
    143      getRangeDescription({
    144        startContainer: editingHost.querySelector("[contenteditable=false]").nextSibling,
    145        startOffset: 0,
    146        endContainer: editingHost.querySelector("[contenteditable=false]").nextSibling,
    147        endOffset: 0,
    148      }),
    149    );
    150  }, `${t.name}: second arrow-right should move caret after non-editable text`);
    151 }, "Move caret from empty editable paragraph to editable text following non-editable text in next paragraph");
    152 
    153 promise_test(async t => {
    154  const editingHost = document.querySelector("div[contenteditable] + div[contenteditable]");
    155  editingHost.focus();
    156  const p = editingHost.querySelector("p");
    157  getSelection().collapse(editingHost.querySelector("[contenteditable=false]").nextSibling, 0);
    158  await sendArrowLeftKey();
    159  assert_false(
    160    editingHost.querySelector("[contenteditable=false]").contains(getSelection().focusNode),
    161    "focus node should not be the non-editable nodes"
    162  );
    163  assert_false(
    164    editingHost.querySelector("[contenteditable=false]").contains(getSelection().anchorNode),
    165    "anchor node should not be the non-editable nodes"
    166  );
    167  test(() => {
    168    assert_equals(
    169      getRangeDescription(getSelection().getRangeAt(0)),
    170      getRangeDescription({
    171        startContainer: p.nextSibling,
    172        startOffset: 0,
    173        endContainer: p.nextSibling,
    174        endOffset: 0,
    175      }),
    176    );
    177  }, `${t.name}: first arrow-left should move caret before non-editable text`);
    178 }, "Move caret from start of text following non-editable text to empty preceding editable paragraph");
    179 </script>
    180 </head>
    181 <body>
    182 <div contenteditable>
    183 <p>abc</p><p><span contenteditable="false">def</span><br></p>
    184 </div>
    185 <div contenteditable>
    186 <p><br></p><p><span contenteditable="false">abc</span>def</p>
    187 </div>
    188 </body>
    189 </html>