Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'linux' && os_version == '18.04'
- Manifest: layout/generic/test/mochitest.toml
<!DOCTYPE HTML>
<html>
<head>
<title>Test Word Movement (including nsTextFrame::PeekOffsetWord)</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: block">
<div contentEditable id="editor"></div>
</div>
<p id="catch">Catch-all
<pre id="test"><script class="testbody" type="text/javascript">
/** Tests for bugs 384147, 981281, 1066756, 1820290 **/
const kIsMac = navigator.platform.includes("Mac");
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async () => {
const editor = document.getElementById("editor");
const waitForFocusEditor = new Promise(resolve =>
editor.addEventListener("focus", resolve, {once: true})
);
editor.focus();
// This seems to be necessary because the selection is not set up properly otherwise
await waitForFocusEditor;
await test1();
await test2();
await test3();
await test4();
SimpleTest.finish();
});
var eatSpace;
var stopAtPunctuation;
var sel = window.getSelection();
var editor = document.getElementById("editor");
function setPrefs(eat_space, stop_at_punctuation) {
eatSpace = eat_space;
stopAtPunctuation = stop_at_punctuation;
return SpecialPowers.pushPrefEnv({
"set": [["layout.word_select.eat_space_to_next_word", eat_space],
["layout.word_select.stop_at_punctuation", stop_at_punctuation],
["intl.icu4x.segmenter.enabled", true]]
});
}
function currentStateDescription() {
return `eatSpace=${eatSpace}, stopAtPunctuation=${stopAtPunctuation}, testing="${editor.outerHTML}"`;
}
function getNodeDescription(aNode) {
if (aNode === undefined) {
return "undefined";
}
if (aNode === null) {
return "null";
}
switch (aNode.nodeType) {
case Node.TEXT_NODE:
return `"${
aNode.data.replace(/\n/g, "\\n")
}" in ${getNodeDescription(aNode.parentNode)}`;
case Node.ELEMENT_NODE:
return `<${aNode.tagName.toLowerCase()}${
aNode.getAttribute("id") !== null
? ` id="${aNode.getAttribute("id")}"`
: ""
}${
aNode.getAttribute("dir") !== null
? ` dir="${aNode.getAttribute("dir")}"`
: ""
}>`;
}
return aNode.nodeName;
}
function testRight(node, offset, knownFailure) {
if (!kIsMac) {
synthesizeKey("KEY_ArrowRight", { ctrlKey: true });
} else {
// macOS does not have default shortcut key to move caret per word.
SpecialPowers.doCommand(window, "cmd_wordNext");
}
(knownFailure ? todo_is : is)(
`{${getNodeDescription(sel.anchorNode)} - ${sel.anchorOffset}}`,
`{${getNodeDescription(node)} - ${offset}}`,
`testRight(${currentStateDescription()})`
);
if (knownFailure) {
getSelection().collapse(node, offset);
}
}
function testLeft(node, offset, knownFailure) {
if (!kIsMac) {
synthesizeKey("KEY_ArrowLeft", { ctrlKey: true });
} else {
// macOS does not have default shortcut key to move caret per word.
SpecialPowers.doCommand(window, "cmd_wordPrevious");
}
(knownFailure ? todo_is : is)(
`{${getNodeDescription(sel.anchorNode)} - ${sel.anchorOffset}}`,
`{${getNodeDescription(node)} - ${offset}}`,
`testLeft(${currentStateDescription()})`
);
if (knownFailure) {
getSelection().collapse(node, offset);
}
}
const afterEditorNode = document.getElementById("catch").firstChild;
const ChineseChars = "漢字";
const HiraganaChars = "ひらがな";
const KatakanaChars = "カタカナ";
const JapaneseFullStop = "。";
const JapaneseComma = "、";
const ModifierColon = "꞉";
const Symbol = "⛅"; // "sun behind cloud" (weather symbol)
const Emoji = "🐀"; // rat emoji
const DeseretChars = "𐑀𐑁";
const ChineseCharsPlane2 = "𠀋𠀿";
const ArabicOne = "\u0648\u0627\u062D\u062F";
const ArabicTwo = "\u0627\u062B\u0646\u064A\u0646";
const ArabicThree = "\u062B\u0644\u0627\u062B\u0629";
async function test1() {
await setPrefs(false, true);
editor.innerHTML = "Hello Kitty";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 11);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 0);
editor.innerHTML = "<b>Hello</b> Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.nextSibling, 0);
testRight(editor.firstChild.nextSibling, 6);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Hello </b>Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 5);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.firstChild, 6);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Log out</b> roc";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 3);
testRight(editor.firstChild.nextSibling, 0);
testRight(editor.firstChild.nextSibling, 5);
// In the next test, we expect to be at the end of the
// space that is not collapsed away
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 4);
testLeft(editor.firstChild.firstChild, 0);
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 11);
testRight(editor.firstChild, 19);
testLeft(editor.firstChild, 11);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
editor.innerHTML = "Set .rc to <b>'</b>quiz'";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 10);
testRight(editor.firstChild.nextSibling.nextSibling, 5);
testLeft(editor.firstChild.nextSibling.firstChild, 1);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
editor.innerHTML = "layout.word_select.stop_at_punctuation";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 19);
testRight(editor.firstChild, 38);
testLeft(editor.firstChild, 19);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 10);
testRight(editor.firstChild, 13);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 13);
testLeft(editor.firstChild, 10);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 3);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 10);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 10);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 3);
testLeft(editor.firstChild, 0);
editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 13);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
// test word selection in Deseret (alphabet in Plane 1)
editor.innerHTML = DeseretChars + " " + DeseretChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 9);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
// Latin words separated by a pictographic symbol
editor.innerHTML = "hello" + Symbol + "world";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 11);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 0);
// Latin words separated by an emoji symbol
editor.innerHTML = "hello" + Emoji + "world";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
// Emoji and Chinese
editor.innerHTML = Emoji + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 4);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
// test that word selection stops at Latin/Chinese boundary
editor.innerHTML = "hello" + ChineseChars + "world";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
// similar, but with Deseret (alphabet in Plane 1) in place of Latin
editor.innerHTML = DeseretChars + ChineseChars + DeseretChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 10);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
// with Plane 2 Chinese characters
editor.innerHTML = "hello" + ChineseCharsPlane2 + "world";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 9);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 9);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
// Plane 1 Deseret and Plane 2 Chinese characters
editor.innerHTML = DeseretChars + ChineseCharsPlane2 + DeseretChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
// Out-of-flow frames around line edges should be treated as independent lines.
for (const floatValue of ["left", "right"]) {
editor.innerHTML = `<b>One</b> <i>Two</i><span style=float:${floatValue}>Three</span>`;
sel.collapse(editor.querySelector("i").firstChild, 0);
testRight(editor.querySelector("i").firstChild, "Two".length);
testRight(editor.querySelector("span").firstChild, "Three".length);
testLeft(editor.querySelector("span").firstChild, 0);
testLeft(editor.querySelector("i").previousSibling, " ".length); // FIXME: Should stop at start of "Two"
editor.innerHTML = `<span style=float:${floatValue}>One</span><b>Two</b> <i>Three</i>`;
sel.collapse(editor.querySelector("b").firstChild, "Two".length);
testLeft(editor.querySelector("b").firstChild, 0);
testLeft(editor.querySelector("span").firstChild, 0);
testRight(editor.querySelector("span").firstChild, "One".length);
testRight(editor.querySelector("b").nextSibling, 0); // FIXME: Should stop at end of "Two"
}
// And also visually connected words which are split by an out-of-flow content
// shouldn't be treated as a word.
editor.innerHTML = 'One<span style=float:right>Two</span>Three';
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, "One".length);
testRight(editor.querySelector("span").firstChild, "Two".length);
testRight(editor.lastChild, "Three".length);
testLeft(editor.lastChild, 0);
testLeft(editor.querySelector("span").firstChild, 0);
testLeft(editor.firstChild, 0);
// Simple RTL cases of above.
editor.setAttribute("dir", "rtl");
for (const floatValue of ["left", "right"]) {
editor.innerHTML = `<b>${ArabicOne}</b> <i>${ArabicTwo}</i><span style=float:${floatValue}>${ArabicThree}</span>`;
sel.collapse(editor.querySelector("i").firstChild, 0);
testLeft(editor.querySelector("i").firstChild, ArabicTwo.length);
testLeft(editor.querySelector("span").firstChild, ArabicThree.length);
testRight(editor.querySelector("span").firstChild, 0);
testRight(editor.querySelector("i").previousSibling, " ".length); // FIXME: Should stop at start of ArabicTwo.
editor.innerHTML = `<span style=float:${floatValue}>${ArabicOne}</span><b>${ArabicTwo}</b> <i>${ArabicThree}</i>`;
sel.collapse(editor.querySelector("b").firstChild, ArabicTwo.length);
testRight(editor.querySelector("b").firstChild, 0);
testRight(editor.querySelector("span").firstChild, 0);
testLeft(editor.querySelector("span").firstChild, ArabicOne.length);
testLeft(editor.querySelector("b").nextSibling, 0); // FIXME: Should stop at end of ArabicTwo.
}
// And also the bidi cases which LRT frames are at line edge if ignoring the
// out-of-flow things.
// XXX Although these tests are behave as expected if I test them manually.
// I don't know the reason why the behavior changes in this test file.
for (const floatValue of ["left", "right"]) {
editor.innerHTML = `<div><b>${ArabicOne}</b> <i dir="ltr">Two</i><span style=float:${floatValue}>${ArabicThree}</span></div>`;
sel.collapse(editor.querySelector("i").firstChild, "Two".length);
testLeft(editor.querySelector("i").firstChild, 0, true);
testLeft(editor.querySelector("span").firstChild, 0, true);
testLeft(editor.querySelector("span").firstChild, ArabicThree.length);
testRight(editor.querySelector("span").firstChild, 0);
testRight(editor.querySelector("i").previousSibling, " ".length); // FIXME: Should stop at end of "Two"
editor.innerHTML = `<div><span style=float:${floatValue}>${ArabicOne}</span><b dir="ltr">Two</b> <i>${ArabicThree}</i></div>`;
sel.collapse(editor.querySelector("b").firstChild, 0);
testRight(editor.querySelector("b").firstChild, "Two".length, true);
testRight(editor.querySelector("span").firstChild, ArabicOne.length, true);
testRight(editor.querySelector("span").firstChild, 0);
testLeft(editor.querySelector("span").firstChild, ArabicOne.length);
testLeft(editor.querySelector("b").nextSibling, 0); // FIXME: Should stop at start of "Two".
}
editor.removeAttribute("dir");
}
async function test2() {
// test basic word movement with eat_space_next_to_word true.
await setPrefs(true, true);
editor.innerHTML = "Hello Kitty";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 11);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 0);
editor.innerHTML = "<b>Hello</b> Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.nextSibling, 1);
testRight(editor.firstChild.nextSibling, 6);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Hello </b>Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.nextSibling, 0);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.firstChild, 6);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Log out</b> roc";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 4);
testRight(editor.firstChild.nextSibling, 2);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 4);
testLeft(editor.firstChild.firstChild, 0);
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 11);
testRight(editor.firstChild, 19);
testLeft(editor.firstChild, 11);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
editor.innerHTML = "Set .rc to <b>'</b>quiz'";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 8);
testRight(editor.firstChild.nextSibling.firstChild, 0);
testRight(editor.firstChild.nextSibling.nextSibling, 5);
testLeft(editor.firstChild.nextSibling.firstChild, 1);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
editor.innerHTML = "layout.word_select.stop_at_punctuation";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 19);
testRight(editor.firstChild, 38);
testLeft(editor.firstChild, 19);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 10);
testRight(editor.firstChild, 13);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 13);
testLeft(editor.firstChild, 10);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 3);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 10);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 10);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 3);
testLeft(editor.firstChild, 0);
editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 13);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
}
async function test3() {
await setPrefs(false, false);
editor.innerHTML = "Hello Kitty";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 11);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 0);
editor.innerHTML = "<b>Hello</b> Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.nextSibling, 0);
testRight(editor.firstChild.nextSibling, 6);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Hello </b>Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 5);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.firstChild, 6);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Log out</b> roc";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 3);
testRight(editor.firstChild.nextSibling, 0);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 4);
testLeft(editor.firstChild.firstChild, 0);
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 22);
testLeft(editor.firstChild, 0);
editor.innerHTML = "Set .rc to <b>'</b>quiz'";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 10);
testRight(editor.firstChild.nextSibling.nextSibling, 5);
testLeft(editor.firstChild, 11);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
editor.innerHTML = "layout.word_select.stop_at_punctuation";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 38);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 13);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 13);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 3);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 0);
editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 13);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
}
async function test4() {
// And again with eat_space_next_to_word true.
await setPrefs(true, false);
editor.innerHTML = "Hello Kitty";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 11);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 0);
editor.innerHTML = "<b>Hello</b> Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.nextSibling, 1);
testRight(editor.firstChild.nextSibling, 6);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Hello </b>Kitty";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.nextSibling, 0);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.firstChild, 6);
testLeft(editor.firstChild.firstChild, 0);
editor.innerHTML = "<b>Log out</b> roc";
sel.collapse(editor.firstChild.firstChild, 0);
testRight(editor.firstChild.firstChild, 4);
testRight(editor.firstChild.nextSibling, 2);
testRight(editor.firstChild.nextSibling, 5);
testLeft(editor.firstChild.nextSibling, 1);
testLeft(editor.firstChild.firstChild, 4);
testLeft(editor.firstChild.firstChild, 0);
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 22);
testLeft(editor.firstChild, 0);
editor.innerHTML = "Set .rc to <b>'</b>quiz'";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 8);
testRight(editor.firstChild.nextSibling.firstChild, 0);
testRight(editor.firstChild.nextSibling.nextSibling, 5);
testLeft(editor.firstChild, 11);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
editor.innerHTML = "layout.word_select.stop_at_punctuation";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 38);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 5);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 5);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 2);
testRight(editor.firstChild, 6);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 6);
testLeft(editor.firstChild, 2);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 4);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 12);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 4);
testLeft(editor.firstChild, 0);
editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 3);
testRight(editor.firstChild, 8);
testRight(editor.firstChild, 13);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 13);
testLeft(editor.firstChild, 8);
testLeft(editor.firstChild, 3);
testLeft(editor.firstChild, 0);
editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 14);
testLeft(editor.firstChild, 0);
editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 8);
testLeft(editor.firstChild, 0);
editor.innerHTML = "hello" + ModifierColon + " wo" + ModifierColon + "rld";
sel.collapse(editor.firstChild, 0);
testRight(editor.firstChild, 7);
testRight(editor.firstChild, 13);
testLeft(editor.firstChild, 7);
testLeft(editor.firstChild, 0);
}
</script></pre>
</body>
</html>