tor-browser

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

test_movement_by_words.html (29040B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Test Word Movement (including nsTextFrame::PeekOffsetWord)</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <script src="/tests/SimpleTest/EventUtils.js"></script>
      7  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      8 </head>
      9 <body>
     10 <p id="display"></p>
     11 <div id="content" style="display: block">
     12 <div contentEditable id="editor"></div>
     13 </div>
     14 <p id="catch">Catch-all
     15 <pre id="test"><script class="testbody" type="text/javascript">
     16 
     17 /** Tests for bugs 384147, 981281, 1066756, 1820290 */
     18 
     19 const kIsMac = navigator.platform.includes("Mac");
     20 
     21 SimpleTest.waitForExplicitFinish();
     22 
     23 SimpleTest.waitForFocus(async () => {
     24  const editor = document.getElementById("editor");
     25  const waitForFocusEditor = new Promise(resolve =>
     26    editor.addEventListener("focus", resolve, {once: true})
     27  );
     28  editor.focus();
     29  // This seems to be necessary because the selection is not set up properly otherwise
     30  await waitForFocusEditor;
     31 
     32  await test1();
     33  await test2();
     34  await test3();
     35  await test4();
     36 
     37  SimpleTest.finish();
     38 });
     39 
     40 var eatSpace;
     41 var stopAtPunctuation;
     42 var sel = window.getSelection();
     43 var editor = document.getElementById("editor");
     44 
     45 function setPrefs(eat_space, stop_at_punctuation) {
     46  eatSpace = eat_space;
     47  stopAtPunctuation = stop_at_punctuation;
     48  return SpecialPowers.pushPrefEnv({
     49    "set": [["layout.word_select.eat_space_to_next_word", eat_space],
     50     ["layout.word_select.stop_at_punctuation", stop_at_punctuation],
     51     ["intl.icu4x.segmenter.enabled", true]]
     52  });
     53 }
     54 
     55 function currentStateDescription() {
     56  return `eatSpace=${eatSpace}, stopAtPunctuation=${stopAtPunctuation}, testing="${editor.outerHTML}"`;
     57 }
     58 
     59 function getNodeDescription(aNode) {
     60  if (aNode === undefined) {
     61    return "undefined";
     62  }
     63  if (aNode === null) {
     64    return "null";
     65  }
     66  switch (aNode.nodeType) {
     67    case Node.TEXT_NODE:
     68      return `"${
     69        aNode.data.replace(/\n/g, "\\n")
     70      }" in ${getNodeDescription(aNode.parentNode)}`;
     71    case Node.ELEMENT_NODE:
     72      return `<${aNode.tagName.toLowerCase()}${
     73        aNode.getAttribute("id") !== null
     74          ? ` id="${aNode.getAttribute("id")}"`
     75          : ""
     76      }${
     77        aNode.getAttribute("dir") !== null
     78          ? ` dir="${aNode.getAttribute("dir")}"`
     79          : ""
     80      }>`;
     81  }
     82  return aNode.nodeName;
     83 }
     84 
     85 function testRight(node, offset, knownFailure) {
     86  if (!kIsMac) {
     87    synthesizeKey("KEY_ArrowRight", { ctrlKey: true });
     88  } else {
     89    // macOS does not have default shortcut key to move caret per word.
     90    SpecialPowers.doCommand(window, "cmd_wordNext");
     91  }
     92  (knownFailure ? todo_is : is)(
     93    `{${getNodeDescription(sel.anchorNode)} - ${sel.anchorOffset}}`,
     94    `{${getNodeDescription(node)} - ${offset}}`,
     95    `testRight(${currentStateDescription()})`
     96  );
     97  if (knownFailure) {
     98    getSelection().collapse(node, offset);
     99  }
    100 }
    101 
    102 function testLeft(node, offset, knownFailure) {
    103  if (!kIsMac) {
    104    synthesizeKey("KEY_ArrowLeft", { ctrlKey: true });
    105  } else {
    106    // macOS does not have default shortcut key to move caret per word.
    107    SpecialPowers.doCommand(window, "cmd_wordPrevious");
    108  }
    109  (knownFailure ? todo_is : is)(
    110    `{${getNodeDescription(sel.anchorNode)} - ${sel.anchorOffset}}`,
    111    `{${getNodeDescription(node)} - ${offset}}`,
    112    `testLeft(${currentStateDescription()})`
    113  );
    114  if (knownFailure) {
    115    getSelection().collapse(node, offset);
    116  }
    117 }
    118 
    119 const afterEditorNode = document.getElementById("catch").firstChild;
    120 
    121 const ChineseChars = "&#x6F22;&#x5B57;";
    122 const HiraganaChars = "&#x3072;&#x3089;&#x304C;&#x306A;";
    123 const KatakanaChars = "&#x30AB;&#x30BF;&#x30AB;&#x30CA;";
    124 const JapaneseFullStop = "&#x3002;";
    125 const JapaneseComma = "&#x3001;";
    126 const ModifierColon = "&#xA789;";
    127 const Symbol = "&#x26C5;"; // "sun behind cloud" (weather symbol)
    128 const Emoji = "&#x1f400;"; // rat emoji
    129 const DeseretChars = "&#x10440;&#x10441;";
    130 const ChineseCharsPlane2 = "&#x2000B;&#x2003F;";
    131 const ArabicOne = "\u0648\u0627\u062D\u062F";
    132 const ArabicTwo = "\u0627\u062B\u0646\u064A\u0646";
    133 const ArabicThree = "\u062B\u0644\u0627\u062B\u0629";
    134 
    135 async function test1() {
    136  await setPrefs(false, true);
    137 
    138  editor.innerHTML = "Hello Kitty";
    139  sel.collapse(editor.firstChild, 0);
    140  testRight(editor.firstChild, 5);
    141  testRight(editor.firstChild, 11);
    142  testLeft(editor.firstChild, 6);
    143  testLeft(editor.firstChild, 0);
    144 
    145  editor.innerHTML = "<b>Hello</b> Kitty";
    146  sel.collapse(editor.firstChild.firstChild, 0);
    147  testRight(editor.firstChild.nextSibling, 0);
    148  testRight(editor.firstChild.nextSibling, 6);
    149  testLeft(editor.firstChild.nextSibling, 1);
    150  testLeft(editor.firstChild.firstChild, 0);
    151 
    152  editor.innerHTML = "<b>Hello </b>Kitty";
    153  sel.collapse(editor.firstChild.firstChild, 0);
    154  testRight(editor.firstChild.firstChild, 5);
    155  testRight(editor.firstChild.nextSibling, 5);
    156  testLeft(editor.firstChild.firstChild, 6);
    157  testLeft(editor.firstChild.firstChild, 0);
    158 
    159  editor.innerHTML = "<b>Log out</b>  roc";
    160  sel.collapse(editor.firstChild.firstChild, 0);
    161  testRight(editor.firstChild.firstChild, 3);
    162  testRight(editor.firstChild.nextSibling, 0);
    163  testRight(editor.firstChild.nextSibling, 5);
    164  // In the next test, we expect to be at the end of the
    165  // space that is not collapsed away
    166  testLeft(editor.firstChild.nextSibling, 1);
    167  testLeft(editor.firstChild.firstChild, 4);
    168  testLeft(editor.firstChild.firstChild, 0);
    169 
    170  editor.innerHTML = "http://www.mozilla.org";
    171  sel.collapse(editor.firstChild, 0);
    172  testRight(editor.firstChild, 7);
    173  testRight(editor.firstChild, 11);
    174  testRight(editor.firstChild, 19);
    175  testLeft(editor.firstChild, 11);
    176  testLeft(editor.firstChild, 7);
    177  testLeft(editor.firstChild, 0);
    178 
    179  editor.innerHTML = "Set .rc to <b>'</b>quiz'";
    180  sel.collapse(editor.firstChild, 0);
    181  testRight(editor.firstChild, 3);
    182  testRight(editor.firstChild, 7);
    183  testRight(editor.firstChild, 10);
    184  testRight(editor.firstChild.nextSibling.nextSibling, 5);
    185  testLeft(editor.firstChild.nextSibling.firstChild, 1);
    186  testLeft(editor.firstChild, 8);
    187  testLeft(editor.firstChild, 5);
    188  testLeft(editor.firstChild, 0);
    189 
    190  editor.innerHTML = "layout.word_select.stop_at_punctuation";
    191  sel.collapse(editor.firstChild, 0);
    192  testRight(editor.firstChild, 7);
    193  testRight(editor.firstChild, 19);
    194  testRight(editor.firstChild, 38);
    195  testLeft(editor.firstChild, 19);
    196  testLeft(editor.firstChild, 7);
    197  testLeft(editor.firstChild, 0);
    198 
    199  editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
    200  sel.collapse(editor.firstChild, 0);
    201  testRight(editor.firstChild, 2);
    202  testRight(editor.firstChild, 5);
    203  testRight(editor.firstChild, 6);
    204  testRight(editor.firstChild, 8);
    205  testLeft(editor.firstChild, 6);
    206  testLeft(editor.firstChild, 5);
    207  testLeft(editor.firstChild, 2);
    208  testLeft(editor.firstChild, 0);
    209 
    210  editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
    211  sel.collapse(editor.firstChild, 0);
    212  testRight(editor.firstChild, 2);
    213  testRight(editor.firstChild, 6);
    214  testRight(editor.firstChild, 8);
    215  testLeft(editor.firstChild, 6);
    216  testLeft(editor.firstChild, 2);
    217  testLeft(editor.firstChild, 0);
    218 
    219  editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
    220  sel.collapse(editor.firstChild, 0);
    221  testRight(editor.firstChild, 4);
    222  testRight(editor.firstChild, 7);
    223  testRight(editor.firstChild, 8);
    224  testRight(editor.firstChild, 12);
    225  testLeft(editor.firstChild, 8);
    226  testLeft(editor.firstChild, 7);
    227  testLeft(editor.firstChild, 4);
    228  testLeft(editor.firstChild, 0);
    229 
    230  editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
    231  sel.collapse(editor.firstChild, 0);
    232  testRight(editor.firstChild, 3);
    233  testRight(editor.firstChild, 5);
    234  testRight(editor.firstChild, 8);
    235  testRight(editor.firstChild, 10);
    236  testRight(editor.firstChild, 13);
    237  testRight(editor.firstChild, 14);
    238  testLeft(editor.firstChild, 13);
    239  testLeft(editor.firstChild, 10);
    240  testLeft(editor.firstChild, 8);
    241  testLeft(editor.firstChild, 5);
    242  testLeft(editor.firstChild, 3);
    243  testLeft(editor.firstChild, 0);
    244 
    245  editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
    246  sel.collapse(editor.firstChild, 0);
    247  testRight(editor.firstChild, 5);
    248  testRight(editor.firstChild, 10);
    249  testRight(editor.firstChild, 14);
    250  testLeft(editor.firstChild, 10);
    251  testLeft(editor.firstChild, 5);
    252  testLeft(editor.firstChild, 0);
    253 
    254  editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
    255  sel.collapse(editor.firstChild, 0);
    256  testRight(editor.firstChild, 3);
    257  testRight(editor.firstChild, 6);
    258  testRight(editor.firstChild, 8);
    259  testLeft(editor.firstChild, 6);
    260  testLeft(editor.firstChild, 3);
    261  testLeft(editor.firstChild, 0);
    262 
    263  // test for bug 1066756
    264  editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
    265  sel.collapse(editor.firstChild, 0);
    266  testRight(editor.firstChild, 6);
    267  testRight(editor.firstChild, 13);
    268  testLeft(editor.firstChild, 7);
    269  testLeft(editor.firstChild, 0);
    270 
    271  // test word selection in Deseret (alphabet in Plane 1)
    272  editor.innerHTML = DeseretChars + " " + DeseretChars;
    273  sel.collapse(editor.firstChild, 0);
    274  testRight(editor.firstChild, 4);
    275  testRight(editor.firstChild, 9);
    276  testLeft(editor.firstChild, 5);
    277  testLeft(editor.firstChild, 0);
    278 
    279  // Latin words separated by a pictographic symbol
    280  editor.innerHTML = "hello" + Symbol + "world";
    281  sel.collapse(editor.firstChild, 0);
    282  testRight(editor.firstChild, 6);
    283  testRight(editor.firstChild, 11);
    284  testLeft(editor.firstChild, 6);
    285  testLeft(editor.firstChild, 0);
    286 
    287  // Latin words separated by an emoji symbol
    288  editor.innerHTML = "hello" + Emoji + "world";
    289  sel.collapse(editor.firstChild, 0);
    290  testRight(editor.firstChild, 5);
    291  testRight(editor.firstChild, 7);
    292  testRight(editor.firstChild, 12);
    293  testLeft(editor.firstChild, 7);
    294  testLeft(editor.firstChild, 5);
    295  testLeft(editor.firstChild, 0);
    296 
    297  // Emoji and Chinese
    298  editor.innerHTML = Emoji + ChineseChars;
    299  sel.collapse(editor.firstChild, 0);
    300  testRight(editor.firstChild, 2);
    301  testRight(editor.firstChild, 4);
    302  testLeft(editor.firstChild, 2);
    303  testLeft(editor.firstChild, 0);
    304 
    305  // test that word selection stops at Latin/Chinese boundary
    306  editor.innerHTML = "hello" + ChineseChars + "world";
    307  sel.collapse(editor.firstChild, 0);
    308  testRight(editor.firstChild, 5);
    309  testRight(editor.firstChild, 7);
    310  testRight(editor.firstChild, 12);
    311  testLeft(editor.firstChild, 7);
    312  testLeft(editor.firstChild, 5);
    313  testLeft(editor.firstChild, 0);
    314 
    315  // similar, but with Deseret (alphabet in Plane 1) in place of Latin
    316  editor.innerHTML = DeseretChars + ChineseChars + DeseretChars;
    317  sel.collapse(editor.firstChild, 0);
    318  testRight(editor.firstChild, 4);
    319  testRight(editor.firstChild, 6);
    320  testRight(editor.firstChild, 10);
    321  testLeft(editor.firstChild, 6);
    322  testLeft(editor.firstChild, 4);
    323  testLeft(editor.firstChild, 0);
    324 
    325  // with Plane 2 Chinese characters
    326  editor.innerHTML = "hello" + ChineseCharsPlane2 + "world";
    327  sel.collapse(editor.firstChild, 0);
    328  testRight(editor.firstChild, 5);
    329  testRight(editor.firstChild, 9);
    330  testRight(editor.firstChild, 14);
    331  testLeft(editor.firstChild, 9);
    332  testLeft(editor.firstChild, 5);
    333  testLeft(editor.firstChild, 0);
    334 
    335  // Plane 1 Deseret and Plane 2 Chinese characters
    336  editor.innerHTML = DeseretChars + ChineseCharsPlane2 + DeseretChars;
    337  sel.collapse(editor.firstChild, 0);
    338  testRight(editor.firstChild, 4);
    339  testRight(editor.firstChild, 8);
    340  testRight(editor.firstChild, 12);
    341  testLeft(editor.firstChild, 8);
    342  testLeft(editor.firstChild, 4);
    343  testLeft(editor.firstChild, 0);
    344 
    345  // Out-of-flow frames around line edges should be treated as independent lines.
    346  for (const floatValue of ["left", "right"]) {
    347    editor.innerHTML = `<b>One</b> <i>Two</i><span style=float:${floatValue}>Three</span>`;
    348    sel.collapse(editor.querySelector("i").firstChild, 0);
    349    testRight(editor.querySelector("i").firstChild, "Two".length);
    350    testRight(editor.querySelector("span").firstChild, "Three".length);
    351    testLeft(editor.querySelector("span").firstChild, 0);
    352    testLeft(editor.querySelector("i").previousSibling, " ".length); // FIXME: Should stop at start of "Two"
    353    editor.innerHTML = `<span style=float:${floatValue}>One</span><b>Two</b> <i>Three</i>`;
    354    sel.collapse(editor.querySelector("b").firstChild, "Two".length);
    355    testLeft(editor.querySelector("b").firstChild, 0);
    356    testLeft(editor.querySelector("span").firstChild, 0);
    357    testRight(editor.querySelector("span").firstChild, "One".length);
    358    testRight(editor.querySelector("b").nextSibling, 0); // FIXME: Should stop at end of "Two"
    359  }
    360 
    361  // And also visually connected words which are split by an out-of-flow content
    362  // shouldn't be treated as a word.
    363  editor.innerHTML = 'One<span style=float:right>Two</span>Three';
    364  sel.collapse(editor.firstChild, 0);
    365  testRight(editor.firstChild, "One".length);
    366  testRight(editor.querySelector("span").firstChild, "Two".length);
    367  testRight(editor.lastChild, "Three".length);
    368  testLeft(editor.lastChild, 0);
    369  testLeft(editor.querySelector("span").firstChild, 0);
    370  testLeft(editor.firstChild, 0);
    371 
    372  // Simple RTL cases of above.
    373  editor.setAttribute("dir", "rtl");
    374  for (const floatValue of ["left", "right"]) {
    375    editor.innerHTML = `<b>${ArabicOne}</b> <i>${ArabicTwo}</i><span style=float:${floatValue}>${ArabicThree}</span>`;
    376    sel.collapse(editor.querySelector("i").firstChild, 0);
    377    testLeft(editor.querySelector("i").firstChild, ArabicTwo.length);
    378    testLeft(editor.querySelector("span").firstChild, ArabicThree.length);
    379    testRight(editor.querySelector("span").firstChild, 0);
    380    testRight(editor.querySelector("i").previousSibling, " ".length); // FIXME: Should stop at start of ArabicTwo.
    381    editor.innerHTML = `<span style=float:${floatValue}>${ArabicOne}</span><b>${ArabicTwo}</b> <i>${ArabicThree}</i>`;
    382    sel.collapse(editor.querySelector("b").firstChild, ArabicTwo.length);
    383    testRight(editor.querySelector("b").firstChild, 0);
    384    testRight(editor.querySelector("span").firstChild, 0);
    385    testLeft(editor.querySelector("span").firstChild, ArabicOne.length);
    386    testLeft(editor.querySelector("b").nextSibling, 0); // FIXME: Should stop at end of ArabicTwo.
    387  }
    388 
    389  // And also the bidi cases which LRT frames are at line edge if ignoring the
    390  // out-of-flow things.
    391  // XXX Although these tests are behave as expected if I test them manually.
    392  //     I don't know the reason why the behavior changes in this test file.
    393  for (const floatValue of ["left", "right"]) {
    394    editor.innerHTML = `<div><b>${ArabicOne}</b> <i dir="ltr">Two</i><span style=float:${floatValue}>${ArabicThree}</span></div>`;
    395    sel.collapse(editor.querySelector("i").firstChild, "Two".length);
    396    testLeft(editor.querySelector("i").firstChild, 0, true);
    397    testLeft(editor.querySelector("span").firstChild, 0, true);
    398    testLeft(editor.querySelector("span").firstChild, ArabicThree.length);
    399    testRight(editor.querySelector("span").firstChild, 0);
    400    testRight(editor.querySelector("i").previousSibling, " ".length); // FIXME: Should stop at end of "Two"
    401    editor.innerHTML = `<div><span style=float:${floatValue}>${ArabicOne}</span><b dir="ltr">Two</b> <i>${ArabicThree}</i></div>`;
    402    sel.collapse(editor.querySelector("b").firstChild, 0);
    403    testRight(editor.querySelector("b").firstChild, "Two".length, true);
    404    testRight(editor.querySelector("span").firstChild, ArabicOne.length, true);
    405    testRight(editor.querySelector("span").firstChild, 0);
    406    testLeft(editor.querySelector("span").firstChild, ArabicOne.length);
    407    testLeft(editor.querySelector("b").nextSibling, 0); // FIXME: Should stop at start of "Two".
    408  }
    409 
    410  editor.removeAttribute("dir");
    411 }
    412 
    413 async function test2() {
    414  // test basic word movement with eat_space_next_to_word true.
    415  await setPrefs(true, true);
    416 
    417  editor.innerHTML = "Hello Kitty";
    418  sel.collapse(editor.firstChild, 0);
    419  testRight(editor.firstChild, 6);
    420  testRight(editor.firstChild, 11);
    421  testLeft(editor.firstChild, 6);
    422  testLeft(editor.firstChild, 0);
    423 
    424  editor.innerHTML = "<b>Hello</b> Kitty";
    425  sel.collapse(editor.firstChild.firstChild, 0);
    426  testRight(editor.firstChild.nextSibling, 1);
    427  testRight(editor.firstChild.nextSibling, 6);
    428  testLeft(editor.firstChild.nextSibling, 1);
    429  testLeft(editor.firstChild.firstChild, 0);
    430 
    431  editor.innerHTML = "<b>Hello </b>Kitty";
    432  sel.collapse(editor.firstChild.firstChild, 0);
    433  testRight(editor.firstChild.nextSibling, 0);
    434  testRight(editor.firstChild.nextSibling, 5);
    435  testLeft(editor.firstChild.firstChild, 6);
    436  testLeft(editor.firstChild.firstChild, 0);
    437 
    438  editor.innerHTML = "<b>Log out</b>  roc";
    439  sel.collapse(editor.firstChild.firstChild, 0);
    440  testRight(editor.firstChild.firstChild, 4);
    441  testRight(editor.firstChild.nextSibling, 2);
    442  testRight(editor.firstChild.nextSibling, 5);
    443  testLeft(editor.firstChild.nextSibling, 1);
    444  testLeft(editor.firstChild.firstChild, 4);
    445  testLeft(editor.firstChild.firstChild, 0);
    446 
    447  editor.innerHTML = "http://www.mozilla.org";
    448  sel.collapse(editor.firstChild, 0);
    449  testRight(editor.firstChild, 7);
    450  testRight(editor.firstChild, 11);
    451  testRight(editor.firstChild, 19);
    452  testLeft(editor.firstChild, 11);
    453  testLeft(editor.firstChild, 7);
    454  testLeft(editor.firstChild, 0);
    455 
    456  editor.innerHTML = "Set .rc to <b>'</b>quiz'";
    457  sel.collapse(editor.firstChild, 0);
    458  testRight(editor.firstChild, 4);
    459  testRight(editor.firstChild, 8);
    460  testRight(editor.firstChild.nextSibling.firstChild, 0);
    461  testRight(editor.firstChild.nextSibling.nextSibling, 5);
    462  testLeft(editor.firstChild.nextSibling.firstChild, 1);
    463  testLeft(editor.firstChild, 8);
    464  testLeft(editor.firstChild, 5);
    465  testLeft(editor.firstChild, 0);
    466 
    467  editor.innerHTML = "layout.word_select.stop_at_punctuation";
    468  sel.collapse(editor.firstChild, 0);
    469  testRight(editor.firstChild, 7);
    470  testRight(editor.firstChild, 19);
    471  testRight(editor.firstChild, 38);
    472  testLeft(editor.firstChild, 19);
    473  testLeft(editor.firstChild, 7);
    474  testLeft(editor.firstChild, 0);
    475 
    476  editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
    477  sel.collapse(editor.firstChild, 0);
    478  testRight(editor.firstChild, 2);
    479  testRight(editor.firstChild, 5);
    480  testRight(editor.firstChild, 6);
    481  testRight(editor.firstChild, 8);
    482  testLeft(editor.firstChild, 6);
    483  testLeft(editor.firstChild, 5);
    484  testLeft(editor.firstChild, 2);
    485  testLeft(editor.firstChild, 0);
    486 
    487  editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
    488  sel.collapse(editor.firstChild, 0);
    489  testRight(editor.firstChild, 2);
    490  testRight(editor.firstChild, 6);
    491  testRight(editor.firstChild, 8);
    492  testLeft(editor.firstChild, 6);
    493  testLeft(editor.firstChild, 2);
    494  testLeft(editor.firstChild, 0);
    495 
    496  editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
    497  sel.collapse(editor.firstChild, 0);
    498  testRight(editor.firstChild, 4);
    499  testRight(editor.firstChild, 7);
    500  testRight(editor.firstChild, 8);
    501  testRight(editor.firstChild, 12);
    502  testLeft(editor.firstChild, 8);
    503  testLeft(editor.firstChild, 7);
    504  testLeft(editor.firstChild, 4);
    505  testLeft(editor.firstChild, 0);
    506 
    507  editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
    508  sel.collapse(editor.firstChild, 0);
    509  testRight(editor.firstChild, 3);
    510  testRight(editor.firstChild, 5);
    511  testRight(editor.firstChild, 8);
    512  testRight(editor.firstChild, 10);
    513  testRight(editor.firstChild, 13);
    514  testRight(editor.firstChild, 14);
    515  testLeft(editor.firstChild, 13);
    516  testLeft(editor.firstChild, 10);
    517  testLeft(editor.firstChild, 8);
    518  testLeft(editor.firstChild, 5);
    519  testLeft(editor.firstChild, 3);
    520  testLeft(editor.firstChild, 0);
    521 
    522  editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
    523  sel.collapse(editor.firstChild, 0);
    524  testRight(editor.firstChild, 5);
    525  testRight(editor.firstChild, 10);
    526  testRight(editor.firstChild, 14);
    527  testLeft(editor.firstChild, 10);
    528  testLeft(editor.firstChild, 5);
    529  testLeft(editor.firstChild, 0);
    530 
    531  editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
    532  sel.collapse(editor.firstChild, 0);
    533  testRight(editor.firstChild, 3);
    534  testRight(editor.firstChild, 6);
    535  testRight(editor.firstChild, 8);
    536  testLeft(editor.firstChild, 6);
    537  testLeft(editor.firstChild, 3);
    538  testLeft(editor.firstChild, 0);
    539 
    540  editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
    541  sel.collapse(editor.firstChild, 0);
    542  testRight(editor.firstChild, 7);
    543  testRight(editor.firstChild, 13);
    544  testLeft(editor.firstChild, 7);
    545  testLeft(editor.firstChild, 0);
    546 }
    547 
    548 async function test3() {
    549  // Test basic word movement with stop_at_punctuation false (bug 981281).
    550  await setPrefs(false, false);
    551 
    552  editor.innerHTML = "Hello Kitty";
    553  sel.collapse(editor.firstChild, 0);
    554  testRight(editor.firstChild, 5);
    555  testRight(editor.firstChild, 11);
    556  testLeft(editor.firstChild, 6);
    557  testLeft(editor.firstChild, 0);
    558 
    559  editor.innerHTML = "<b>Hello</b> Kitty";
    560  sel.collapse(editor.firstChild.firstChild, 0);
    561  testRight(editor.firstChild.nextSibling, 0);
    562  testRight(editor.firstChild.nextSibling, 6);
    563  testLeft(editor.firstChild.nextSibling, 1);
    564  testLeft(editor.firstChild.firstChild, 0);
    565 
    566  editor.innerHTML = "<b>Hello </b>Kitty";
    567  sel.collapse(editor.firstChild.firstChild, 0);
    568  testRight(editor.firstChild.firstChild, 5);
    569  testRight(editor.firstChild.nextSibling, 5);
    570  testLeft(editor.firstChild.firstChild, 6);
    571  testLeft(editor.firstChild.firstChild, 0);
    572 
    573  editor.innerHTML = "<b>Log out</b>  roc";
    574  sel.collapse(editor.firstChild.firstChild, 0);
    575  testRight(editor.firstChild.firstChild, 3);
    576  testRight(editor.firstChild.nextSibling, 0);
    577  testRight(editor.firstChild.nextSibling, 5);
    578  testLeft(editor.firstChild.nextSibling, 1);
    579  testLeft(editor.firstChild.firstChild, 4);
    580  testLeft(editor.firstChild.firstChild, 0);
    581 
    582  editor.innerHTML = "http://www.mozilla.org";
    583  sel.collapse(editor.firstChild, 0);
    584  testRight(editor.firstChild, 22);
    585  testLeft(editor.firstChild, 0);
    586 
    587  editor.innerHTML = "Set .rc to <b>'</b>quiz'";
    588  sel.collapse(editor.firstChild, 0);
    589  testRight(editor.firstChild, 3);
    590  testRight(editor.firstChild, 7);
    591  testRight(editor.firstChild, 10);
    592  testRight(editor.firstChild.nextSibling.nextSibling, 5);
    593  testLeft(editor.firstChild, 11);
    594  testLeft(editor.firstChild, 8);
    595  testLeft(editor.firstChild, 4);
    596  testLeft(editor.firstChild, 0);
    597 
    598  editor.innerHTML = "layout.word_select.stop_at_punctuation";
    599  sel.collapse(editor.firstChild, 0);
    600  testRight(editor.firstChild, 38);
    601  testLeft(editor.firstChild, 0);
    602 
    603  editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
    604  sel.collapse(editor.firstChild, 0);
    605  testRight(editor.firstChild, 2);
    606  testRight(editor.firstChild, 5);
    607  testRight(editor.firstChild, 6);
    608  testRight(editor.firstChild, 8);
    609  testLeft(editor.firstChild, 6);
    610  testLeft(editor.firstChild, 5);
    611  testLeft(editor.firstChild, 2);
    612  testLeft(editor.firstChild, 0);
    613 
    614  editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
    615  sel.collapse(editor.firstChild, 0);
    616  testRight(editor.firstChild, 2);
    617  testRight(editor.firstChild, 6);
    618  testRight(editor.firstChild, 8);
    619  testLeft(editor.firstChild, 6);
    620  testLeft(editor.firstChild, 2);
    621  testLeft(editor.firstChild, 0);
    622 
    623  editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
    624  sel.collapse(editor.firstChild, 0);
    625  testRight(editor.firstChild, 4);
    626  testRight(editor.firstChild, 7);
    627  testRight(editor.firstChild, 8);
    628  testRight(editor.firstChild, 12);
    629  testLeft(editor.firstChild, 8);
    630  testLeft(editor.firstChild, 7);
    631  testLeft(editor.firstChild, 4);
    632  testLeft(editor.firstChild, 0);
    633 
    634  editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
    635  sel.collapse(editor.firstChild, 0);
    636  testRight(editor.firstChild, 3);
    637  testRight(editor.firstChild, 8);
    638  testRight(editor.firstChild, 13);
    639  testRight(editor.firstChild, 14);
    640  testLeft(editor.firstChild, 13);
    641  testLeft(editor.firstChild, 8);
    642  testLeft(editor.firstChild, 3);
    643  testLeft(editor.firstChild, 0);
    644 
    645  editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
    646  sel.collapse(editor.firstChild, 0);
    647  testRight(editor.firstChild, 14);
    648  testLeft(editor.firstChild, 0);
    649 
    650  editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
    651  sel.collapse(editor.firstChild, 0);
    652  testRight(editor.firstChild, 8);
    653  testLeft(editor.firstChild, 0);
    654 
    655  editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
    656  sel.collapse(editor.firstChild, 0);
    657  testRight(editor.firstChild, 6);
    658  testRight(editor.firstChild, 13);
    659  testLeft(editor.firstChild, 7);
    660  testLeft(editor.firstChild, 0);
    661 }
    662 
    663 async function test4() {
    664  // And again with eat_space_next_to_word true.
    665  await setPrefs(true, false);
    666 
    667  editor.innerHTML = "Hello Kitty";
    668  sel.collapse(editor.firstChild, 0);
    669  testRight(editor.firstChild, 6);
    670  testRight(editor.firstChild, 11);
    671  testLeft(editor.firstChild, 6);
    672  testLeft(editor.firstChild, 0);
    673 
    674  editor.innerHTML = "<b>Hello</b> Kitty";
    675  sel.collapse(editor.firstChild.firstChild, 0);
    676  testRight(editor.firstChild.nextSibling, 1);
    677  testRight(editor.firstChild.nextSibling, 6);
    678  testLeft(editor.firstChild.nextSibling, 1);
    679  testLeft(editor.firstChild.firstChild, 0);
    680 
    681  editor.innerHTML = "<b>Hello </b>Kitty";
    682  sel.collapse(editor.firstChild.firstChild, 0);
    683  testRight(editor.firstChild.nextSibling, 0);
    684  testRight(editor.firstChild.nextSibling, 5);
    685  testLeft(editor.firstChild.firstChild, 6);
    686  testLeft(editor.firstChild.firstChild, 0);
    687 
    688  editor.innerHTML = "<b>Log out</b>  roc";
    689  sel.collapse(editor.firstChild.firstChild, 0);
    690  testRight(editor.firstChild.firstChild, 4);
    691  testRight(editor.firstChild.nextSibling, 2);
    692  testRight(editor.firstChild.nextSibling, 5);
    693  testLeft(editor.firstChild.nextSibling, 1);
    694  testLeft(editor.firstChild.firstChild, 4);
    695  testLeft(editor.firstChild.firstChild, 0);
    696 
    697  editor.innerHTML = "http://www.mozilla.org";
    698  sel.collapse(editor.firstChild, 0);
    699  testRight(editor.firstChild, 22);
    700  testLeft(editor.firstChild, 0);
    701 
    702  editor.innerHTML = "Set .rc to <b>'</b>quiz'";
    703  sel.collapse(editor.firstChild, 0);
    704  testRight(editor.firstChild, 4);
    705  testRight(editor.firstChild, 8);
    706  testRight(editor.firstChild.nextSibling.firstChild, 0);
    707  testRight(editor.firstChild.nextSibling.nextSibling, 5);
    708  testLeft(editor.firstChild, 11);
    709  testLeft(editor.firstChild, 8);
    710  testLeft(editor.firstChild, 4);
    711  testLeft(editor.firstChild, 0);
    712 
    713  editor.innerHTML = "layout.word_select.stop_at_punctuation";
    714  sel.collapse(editor.firstChild, 0);
    715  testRight(editor.firstChild, 38);
    716  testLeft(editor.firstChild, 0);
    717 
    718  editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
    719  sel.collapse(editor.firstChild, 0);
    720  testRight(editor.firstChild, 2);
    721  testRight(editor.firstChild, 5);
    722  testRight(editor.firstChild, 6);
    723  testRight(editor.firstChild, 8);
    724  testLeft(editor.firstChild, 6);
    725  testLeft(editor.firstChild, 5);
    726  testLeft(editor.firstChild, 2);
    727  testLeft(editor.firstChild, 0);
    728 
    729  editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
    730  sel.collapse(editor.firstChild, 0);
    731  testRight(editor.firstChild, 2);
    732  testRight(editor.firstChild, 6);
    733  testRight(editor.firstChild, 8);
    734  testLeft(editor.firstChild, 6);
    735  testLeft(editor.firstChild, 2);
    736  testLeft(editor.firstChild, 0);
    737 
    738  editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
    739  sel.collapse(editor.firstChild, 0);
    740  testRight(editor.firstChild, 4);
    741  testRight(editor.firstChild, 7);
    742  testRight(editor.firstChild, 8);
    743  testRight(editor.firstChild, 12);
    744  testLeft(editor.firstChild, 8);
    745  testLeft(editor.firstChild, 7);
    746  testLeft(editor.firstChild, 4);
    747  testLeft(editor.firstChild, 0);
    748 
    749  editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
    750  sel.collapse(editor.firstChild, 0);
    751  testRight(editor.firstChild, 3);
    752  testRight(editor.firstChild, 8);
    753  testRight(editor.firstChild, 13);
    754  testRight(editor.firstChild, 14);
    755  testLeft(editor.firstChild, 13);
    756  testLeft(editor.firstChild, 8);
    757  testLeft(editor.firstChild, 3);
    758  testLeft(editor.firstChild, 0);
    759 
    760  editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
    761  sel.collapse(editor.firstChild, 0);
    762  testRight(editor.firstChild, 14);
    763  testLeft(editor.firstChild, 0);
    764 
    765  editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
    766  sel.collapse(editor.firstChild, 0);
    767  testRight(editor.firstChild, 8);
    768  testLeft(editor.firstChild, 0);
    769 
    770  editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
    771  sel.collapse(editor.firstChild, 0);
    772  testRight(editor.firstChild, 7);
    773  testRight(editor.firstChild, 13);
    774  testLeft(editor.firstChild, 7);
    775  testLeft(editor.firstChild, 0);
    776 }
    777 
    778 
    779 </script></pre>
    780 </body>
    781 </html>