<script>
// Call testEach(cases[i]) on console when debugging
/**
* @type {TestCase[]}
*
* @typedef {object} TestCase
* @property {string} title
* @property {string} text Text on which the test runs.
* The newlines and spaces will be auto-converted if needed.
* @property {boolean} [reverse] Test in both forward and backward directions
* @property {boolean} [backward] Move backward by cmd_wordPrevious
* @property {ElementSpecific} [div] Can be omitted when there is a bug
* @property {ElementSpecific} textarea
*
* @typedef {object} ElementSpecific
* @property {number} expectedOffset Expected offset after a caret move
* @property {number} [expectedNodeIndex] The index of child node with focus after a caret move.
* -1 means the parent node.
* @property {number} [initialOffset=0] initialOffset offset before a caret move
* @property {number} [initialNodeIndex]
*/
const kFirstWordLength = "Supercalifragilisticexpialidocious".length; // 34
const kParentNodeIndex = -1; // special value
const cases = [
{ title: "Eats inline whitespaces after word",
text: "Supercalifragilisticexpialidocious foo bar fussball",
reverse: true, div: {
expectedOffset: kFirstWordLength + 1
}, textarea: {
expectedOffset: kFirstWordLength + 1
}
},
{ title: "Eats inline whitespaces across a wrapped line after word",
text: "Supercalifragilisticexpialidocious foo bar fussball",
reverse: true, div: {
expectedOffset: kFirstWordLength + 7
}, textarea: {
expectedOffset: kFirstWordLength + 7
}
},
{ title: "Eats inline whitespaces across multiple wrapped lines after word",
text: `Supercalifragilisticexpialidocious foo bar fussball`,
reverse: true, div: {
expectedOffset: kFirstWordLength + 65
}, textarea: {
expectedOffset: kFirstWordLength + 65
}
},
{ title: "Eats inline whitespaces after a whole word and stop before a newline",
text: "Supercalifragilisticexpialidocious \nfoo bar fussball",
reverse: true, div: {
expectedOffset: 1,
expectedNodeIndex: kParentNodeIndex
}, textarea: {
expectedOffset: kFirstWordLength + 1
}
},
{ title: "Eats inline whitespaces after a partial word and stop before a newline",
text: "Supercalifragilisticexpialidocious \nfoo bar fussball", div: {
initialOffset: 5,
expectedOffset: 1,
expectedNodeIndex: kParentNodeIndex
}, textarea: {
initialOffset: 5,
expectedOffset: kFirstWordLength + 1
}
},
{ title: "Eats inline whitespaces without a word and stop before a newline",
text: "Supercalifragilisticexpialidocious \n foo bar fussball",
// TODO(krosylight): Currently ClusterIterator internally skips trailing whitespace
// div: {
// initialOffset: kFirstWordLength,
// expectedOffset: 1,
// expectedNodeIndex: kParentNodeIndex
// }, textarea: {
initialOffset: kFirstWordLength,
expectedOffset: kFirstWordLength + 1
}
},
{ title: "Jumps to the next line and eats inline whitespaces",
text: "Supercalifragilisticexpialidocious \n foo bar fussball",
reverse: true, div: {
initialOffset: kFirstWordLength + 1,
expectedOffset: 6,
expectedNodeIndex: 2
}, textarea: {
initialOffset: kFirstWordLength + 1,
expectedOffset: kFirstWordLength + 8
}
},
{ title: "Stops on whitespaces after word",
text: "Supercalifragilisticexpialidocious \n foo bar fussball",
backward: true, div: {
initialOffset: 8,
initialNodeIndex: 2,
expectedOffset: 6,
expectedNodeIndex: 2
}, textarea: {
initialOffset: 44, // middle of "foo"
expectedOffset: 42
}
},
// TODO(krosylight): Currently no way to tell a word break is from line wrapping
// {
// title: "Ignore a word break introduced by line wrapping",
// text: "Supercalifragilisticexpialidociouspostfix",
// className: "narrow break-word",
// div: {
// expectedOffset: kFirstWordLength + 7
// },
// textarea: {
// expectedOffset: kFirstWordLength + 7
// }
// }
{ title: "Jump only one line at an empty line end",
text: "Supercalifragilisticexpialidocious \n\nfoo bar fussball",
reverse: true, div: {
initialOffset: 2,
initialNodeIndex: kParentNodeIndex,
expectedOffset: 0,
expectedNodeIndex: 3
}, textarea: {
initialOffset: kFirstWordLength + 2,
expectedOffset: kFirstWordLength + 3
}
},
{ title: "Jump only one line at a non-empty line end",
text: "Supercalifragilisticexpialidocious \n\nfoo bar fussball",
reverse: true, div: {
initialOffset: kFirstWordLength + 1,
expectedOffset: 2,
expectedNodeIndex: -1
}, textarea: {
initialOffset: kFirstWordLength + 1,
expectedOffset: kFirstWordLength + 2
}
},
];
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async () => {
await SpecialPowers.pushPrefEnv({
set: [["layout.word_select.eat_space_to_next_word", true]]
});
// Test on div first to prevent Bug 1623413
for (const testCase of cases) {
if (testCase.div) {
testOnDiv(testCase);
}
}
for (const testCase of cases) {
testOnTextarea(testCase);
}
SimpleTest.finish();
});
/** @param {TestCase} testCase */
function testOnDiv(testCase) {
const { title,
backward = false,
reverse = false,
} = testCase;
const {
initialOffset = 0,
expectedOffset,
} = testCase.div;
if (expectedOffset === undefined) {
throw new Error("`expectedOffset` must be defined.")
}
is(selection.focusNode, expectedNode, `focusNode in "${title}"`);
is(selection.focusOffset, expectedOffset, `focusOffset in "${title}"`);
if (reverse) {
selection.collapse(expectedNode, expectedOffset);
moveByWord(!backward);
is(selection.focusNode, initialNode, `focusNode with reversed selection in "${title}"`);
is(selection.focusOffset, initialOffset, `focusOffset with reversed selection in "${title}"`);
}
}
function testOnTextarea(testCase) {
const { title,
backward = false,
reverse = false,
} = testCase;
const {
initialOffset = 0,
expectedOffset,
} = testCase.textarea;
if (expectedOffset === undefined) {
throw new Error("`expectedOffset` must be defined.")
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.