Commit 6ff998ed authored by Anupam Snigdha's avatar Anupam Snigdha Committed by Commit Bot

Added punctuation breaks during word movement

Ctrl+Break on Windows was busted. The algorithm
in |NextWordPositionInternal| never considered
punctuation as a word break character.
According to the Unicode spec for word break boundaries,
punctuation should be considered as word breaking characters.
Added this additional condition in both previous
and next word movement.
Also changed many spellchecking tests to match this behavior.
Insert a space after the misspelled word so it is spellchecked properly.
This is done to trigger spellchecking as the punctuation after the
misspelled word doesn't trigger spellchecking until the user has pressed
space bar or changed the selection.
This is how it should be done in real sites anyways so inserting the
space after misspelled word to trigger spellcheck  makes sense.

Test: third_party\blink\renderer\core\editing\visible_units_word_test.cc

Bug: 122304, 1004414

Change-Id: I88694d3cd2e275f06e3939e7e42181de0bd1b9c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1880602
Commit-Queue: Anupam Snigdha <snianu@microsoft.com>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710243}
parent aa28a093
......@@ -95,12 +95,21 @@ PositionInFlatTree NextWordPositionInternal(
TextBreakIterator* it = WordBreakIterator(text.Span16());
for (int runner = it->following(offset); runner != kTextBreakDone;
runner = it->following(runner)) {
// Accumulate punctuation runs
if (static_cast<unsigned>(runner) < text.length() &&
WTF::unicode::IsPunct(text[runner])) {
if (WTF::unicode::IsAlphanumeric(text[runner - 1]))
return Position::Before(runner);
continue;
}
// We stop searching when the character preceding the break is
// alphanumeric or underscore.
// alphanumeric or punctuations or underscore.
if (static_cast<unsigned>(runner) < text.length() &&
(WTF::unicode::IsAlphanumeric(text[runner - 1]) ||
text[runner - 1] == kLowLineCharacter))
(WTF::unicode::IsPunct(text[runner - 1])) ||
text[runner - 1] == kLowLineCharacter)) {
return Position::After(runner - 1);
}
}
if (text[text.length() - 1] != kNewlineCharacter)
return Position::After(text.length() - 1);
......@@ -121,10 +130,22 @@ PositionInFlatTree PreviousWordPositionInternal(
if (!offset || text.length() == 0)
return Position();
TextBreakIterator* it = WordBreakIterator(text.Span16());
int punct_runner = -1;
for (int runner = it->preceding(offset); runner != kTextBreakDone;
runner = it->preceding(runner)) {
// Accumulate punctuation runs
if (static_cast<unsigned>(runner) < text.length() &&
WTF::unicode::IsPunct(text[runner])) {
if (WTF::unicode::IsAlphanumeric(text[runner - 1]))
return Position::Before(runner);
punct_runner = runner;
continue;
}
if (punct_runner >= 0)
return Position::Before(punct_runner);
// We stop searching when the character following the break is
// alphanumeric or underscore.
// alphanumeric or punctuations or underscore.
if (runner && (WTF::unicode::IsAlphanumeric(text[runner]) ||
text[runner] == kLowLineCharacter))
return Position::Before(runner);
......
......@@ -481,10 +481,10 @@ TEST_P(ParameterizedVisibleUnitsWordTest,
}
TEST_P(ParameterizedVisibleUnitsWordTest, NextWordBasic) {
EXPECT_EQ("<p> (1|) abc def</p>", DoNextWord("<p>| (1) abc def</p>"));
EXPECT_EQ("<p> (1|) abc def</p>", DoNextWord("<p> |(1) abc def</p>"));
EXPECT_EQ("<p> (|1) abc def</p>", DoNextWord("<p>| (1) abc def</p>"));
EXPECT_EQ("<p> (|1) abc def</p>", DoNextWord("<p> |(1) abc def</p>"));
EXPECT_EQ("<p> (1|) abc def</p>", DoNextWord("<p> (|1) abc def</p>"));
EXPECT_EQ("<p> (1) abc| def</p>", DoNextWord("<p> (1|) abc def</p>"));
EXPECT_EQ("<p> (1)| abc def</p>", DoNextWord("<p> (1|) abc def</p>"));
EXPECT_EQ("<p> (1) abc| def</p>", DoNextWord("<p> (1)| abc def</p>"));
EXPECT_EQ("<p> (1) abc| def</p>", DoNextWord("<p> (1) |abc def</p>"));
EXPECT_EQ("<p> (1) abc| def</p>", DoNextWord("<p> (1) a|bc def</p>"));
......@@ -535,16 +535,21 @@ TEST_P(ParameterizedVisibleUnitsWordTest, NextWordPunctuation) {
EXPECT_EQ("abc|.def", DoNextWord("|abc.def"));
EXPECT_EQ("abc|.def", DoNextWord("a|bc.def"));
EXPECT_EQ("abc|.def", DoNextWord("ab|c.def"));
EXPECT_EQ("abc.def|", DoNextWord("abc|.def"));
EXPECT_EQ("abc.|def", DoNextWord("abc|.def"));
EXPECT_EQ("abc.def|", DoNextWord("abc.|def"));
EXPECT_EQ("abc|...def", DoNextWord("|abc...def"));
EXPECT_EQ("abc|...def", DoNextWord("a|bc...def"));
EXPECT_EQ("abc|...def", DoNextWord("ab|c...def"));
EXPECT_EQ("abc...def|", DoNextWord("abc|...def"));
EXPECT_EQ("abc...def|", DoNextWord("abc.|..def"));
EXPECT_EQ("abc...def|", DoNextWord("abc..|.def"));
EXPECT_EQ("abc...|def", DoNextWord("abc|...def"));
EXPECT_EQ("abc...|def", DoNextWord("abc.|..def"));
EXPECT_EQ("abc...|def", DoNextWord("abc..|.def"));
EXPECT_EQ("abc...def|", DoNextWord("abc...|def"));
EXPECT_EQ("abc| ((())) def", DoNextWord("|abc ((())) def"));
EXPECT_EQ("abc ((()))| def", DoNextWord("abc |((())) def"));
EXPECT_EQ("abc| 32.3 def", DoNextWord("|abc 32.3 def"));
EXPECT_EQ("abc 32.3| def", DoNextWord("abc |32.3 def"));
}
TEST_P(ParameterizedVisibleUnitsWordTest, NextWordSkipTab) {
......@@ -559,7 +564,7 @@ TEST_P(ParameterizedVisibleUnitsWordTest, NextWordSkipTextControl) {
DoNextWord("f|oo<input value=\"bla\">bar"));
EXPECT_EQ("foo|<input value=\"bla\">bar",
DoNextWord("fo|o<input value=\"bla\">bar"));
EXPECT_EQ("foo<input value=\"bla\">bar|",
EXPECT_EQ("foo<input value=\"bla\">|bar",
DoNextWord("foo|<input value=\"bla\">bar"));
EXPECT_EQ("foo<input value=\"bla\">bar|",
DoNextWord("foo<input value=\"bla\">|bar"));
......@@ -578,8 +583,8 @@ TEST_P(ParameterizedVisibleUnitsWordTest, PreviousWordBasic) {
EXPECT_EQ("<p> |(1) abc def</p>", DoPreviousWord("<p> |(1) abc def</p>"));
EXPECT_EQ("<p> |(1) abc def</p>", DoPreviousWord("<p> (|1) abc def</p>"));
EXPECT_EQ("<p> (|1) abc def</p>", DoPreviousWord("<p> (1|) abc def</p>"));
EXPECT_EQ("<p> (|1) abc def</p>", DoPreviousWord("<p> (1)| abc def</p>"));
EXPECT_EQ("<p> (|1) abc def</p>", DoPreviousWord("<p> (1) |abc def</p>"));
EXPECT_EQ("<p> (1|) abc def</p>", DoPreviousWord("<p> (1)| abc def</p>"));
EXPECT_EQ("<p> (1|) abc def</p>", DoPreviousWord("<p> (1) |abc def</p>"));
EXPECT_EQ("<p> (1) |abc def</p>", DoPreviousWord("<p> (1) a|bc def</p>"));
EXPECT_EQ("<p> (1) |abc def</p>", DoPreviousWord("<p> (1) ab|c def</p>"));
EXPECT_EQ("<p> (1) |abc def</p>", DoPreviousWord("<p> (1) abc| def</p>"));
......@@ -588,6 +593,12 @@ TEST_P(ParameterizedVisibleUnitsWordTest, PreviousWordBasic) {
EXPECT_EQ("<p> (1) abc |def</p>", DoPreviousWord("<p> (1) abc de|f</p>"));
EXPECT_EQ("<p> (1) abc |def</p>", DoPreviousWord("<p> (1) abc def|</p>"));
EXPECT_EQ("<p> (1) abc |def</p>", DoPreviousWord("<p> (1) abc def</p>|"));
EXPECT_EQ("<p> |abc ((())) def</p>",
DoPreviousWord("<p> abc |((())) def</p>"));
EXPECT_EQ("<p> abc |((())) def</p>",
DoPreviousWord("<p> abc ((())) |def</p>"));
EXPECT_EQ("<p> |abc 32.3 def</p>", DoPreviousWord("<p> abc |32.3 def</p>"));
EXPECT_EQ("<p> abc |32.3 def</p>", DoPreviousWord("<p> abc 32.3 |def</p>"));
}
TEST_P(ParameterizedVisibleUnitsWordTest, PreviousWordSkipTextControl) {
......@@ -599,7 +610,7 @@ TEST_P(ParameterizedVisibleUnitsWordTest, PreviousWordSkipTextControl) {
DoPreviousWord("fo|o<input value=\"bla\">bar"));
EXPECT_EQ("|foo<input value=\"bla\">bar",
DoPreviousWord("foo|<input value=\"bla\">bar"));
EXPECT_EQ("|foo<input value=\"bla\">bar",
EXPECT_EQ("foo|<input value=\"bla\">bar",
DoPreviousWord("foo<input value=\"bla\">|bar"));
EXPECT_EQ("foo<input value=\"bla\">|bar",
DoPreviousWord("foo<input value=\"bla\">b|ar"));
......
......@@ -30,7 +30,7 @@ function editingTest()
var elem = document.getElementById("test2");
var selection = window.getSelection();
selection.collapse(elem, 0);
for (var i = 0; i < 4; ++i)
for (var i = 0; i < 5; ++i) // One additional extend needed to account for punctuation
execExtendSelectionForwardByWordCommand();
execCopyCommand();
......
......@@ -92,7 +92,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2.|\u202C</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2.^\u202C</div>',
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.^\u202C</div>',
`${behavior} 17-13 ltr backward word`);
selection_test(
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.\u202C</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2^.\u202C</div>',
`${behavior} 17-14 ltr backward word`);
}
</script>
......@@ -92,7 +92,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2.|\u202C</div>',
selection => selection.modify('extend', 'left', 'word'),
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2.^\u202C</div>',
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.^\u202C</div>',
`${behavior} 17-13 ltr left word`);
selection_test(
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.\u202C</div>',
selection => selection.modify('extend', 'left', 'word'),
'<div contenteditable dir="ltr">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2^.\u202C</div>',
`${behavior} 17-14 ltr left word`);
}
</script>
......@@ -92,7 +92,13 @@ selection_test(
selection_test(
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2.|\u202C</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2.^\u202C</div>',
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.^\u202C</div>',
`${behavior} 17-13 rtl backward word`);
selection_test(
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.\u202C</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2^.\u202C</div>',
`${behavior} 17-14 rtl backward word`);
}
</script>
......@@ -92,7 +92,13 @@ selection_test(
selection_test(
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2.|\u202C</div>',
selection => selection.modify('extend', 'right', 'word'),
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2.^\u202C</div>',
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.^\u202C</div>',
`${behavior} 17-13 rtl right word`);
selection_test(
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2|.\u202C</div>',
selection => selection.modify('extend', 'right', 'word'),
'<div contenteditable dir="rtl">\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2^.\u202C</div>',
`${behavior} 17-14 rtl right word`);
}
</script>
......@@ -80,13 +80,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">they said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="ltr">they |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="ltr">they said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-11 ltr backward word`);
selection_test(
'<div contenteditable dir="ltr">they said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="ltr">they |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="ltr">they said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-12 ltr backward word`);
selection_test(
......@@ -164,7 +164,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C.|"</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C.^"</div>',
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|.^"</div>',
`${behavior} 18-25 ltr backward word`);
selection_test(
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|."</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C^."</div>',
`${behavior} 18-26 ltr backward word`);
}
</script>
......@@ -80,13 +80,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">they said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'left', 'word'),
'<div contenteditable dir="ltr">they |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="ltr">they said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-11 ltr left word`);
selection_test(
'<div contenteditable dir="ltr">they said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'left', 'word'),
'<div contenteditable dir="ltr">they |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="ltr">they said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-12 ltr left word`);
selection_test(
......@@ -164,7 +164,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C.|"</div>',
selection => selection.modify('extend', 'left', 'word'),
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C.^"</div>',
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|.^"</div>',
`${behavior} 18-25 ltr left word`);
selection_test(
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|."</div>',
selection => selection.modify('extend', 'left', 'word'),
'<div contenteditable dir="ltr">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C^."</div>',
`${behavior} 18-26 ltr left word`);
}
</script>
......@@ -80,13 +80,13 @@ selection_test(
selection_test(
'<div contenteditable dir="rtl">they said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="rtl">they |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="rtl">they said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-11 rtl backward word`);
selection_test(
'<div contenteditable dir="rtl">they said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="rtl">they |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="rtl">they said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-12 rtl backward word`);
selection_test(
......@@ -164,7 +164,13 @@ selection_test(
selection_test(
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C.|"</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C.^"</div>',
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|.^"</div>',
`${behavior} 18-25 rtl backward word`);
selection_test(
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|."</div>',
selection => selection.modify('extend', 'backward', 'word'),
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C^."</div>',
`${behavior} 18-26 rtl backward word`);
}
</script>
......@@ -80,13 +80,13 @@ selection_test(
selection_test(
'<div contenteditable dir="rtl">they said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'right', 'word'),
'<div contenteditable dir="rtl">they |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="rtl">they said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-11 rtl right word`);
selection_test(
'<div contenteditable dir="rtl">they said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
selection => selection.modify('extend', 'right', 'word'),
'<div contenteditable dir="rtl">they |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
'<div contenteditable dir="rtl">they said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C."</div>',
`${behavior} 18-12 rtl right word`);
selection_test(
......@@ -164,7 +164,13 @@ selection_test(
selection_test(
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C.|"</div>',
selection => selection.modify('extend', 'right', 'word'),
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C.^"</div>',
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|.^"</div>',
`${behavior} 18-25 rtl right word`);
selection_test(
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|."</div>',
selection => selection.modify('extend', 'right', 'word'),
'<div contenteditable dir="rtl">they said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C^."</div>',
`${behavior} 18-26 rtl right word`);
}
</script>
......@@ -94,13 +94,13 @@ selection_test(
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'|\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-13 ltr backward word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202A|they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-14 ltr backward word`);
selection_test(
......@@ -166,13 +166,13 @@ selection_test(
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-25 ltr backward word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-26 ltr backward word`);
selection_test(
......@@ -250,19 +250,19 @@ selection_test(
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"|\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"^\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"^\u202C\'?</div>`,
`${behavior} 19-39 ltr backward word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C|\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C^\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C^\'?</div>`,
`${behavior} 19-40 ltr backward word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'|?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C\'^?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C\'^?</div>`,
`${behavior} 19-41 ltr backward word`);
}
</script>
......@@ -94,13 +94,13 @@ selection_test(
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'|\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-13 ltr left word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202A|they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-14 ltr left word`);
selection_test(
......@@ -166,13 +166,13 @@ selection_test(
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-25 ltr left word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-26 ltr left word`);
selection_test(
......@@ -250,19 +250,19 @@ selection_test(
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"|\u202C\'?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"^\u202C\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"^\u202C\'?</div>`,
`${behavior} 19-39 ltr left word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C|\'?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C^\'?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C^\'?</div>`,
`${behavior} 19-40 ltr left word`);
selection_test(
`<div contenteditable dir="ltr" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'|?</div>`,
selection => selection.modify('extend', 'left', 'word'),
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C\'^?</div>`,
`<div contenteditable dir="ltr" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C\'^?</div>`,
`${behavior} 19-41 ltr left word`);
}
</script>
......@@ -94,13 +94,13 @@ selection_test(
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'|\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-13 rtl backward word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202A|they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-14 rtl backward word`);
selection_test(
......@@ -166,13 +166,13 @@ selection_test(
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-25 rtl backward word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-26 rtl backward word`);
selection_test(
......@@ -250,19 +250,19 @@ selection_test(
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"|\u202C\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"^\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"^\u202C\'?</div>`,
`${behavior} 19-39 rtl backward word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C|\'?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C^\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C^\'?</div>`,
`${behavior} 19-40 rtl backward word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'|?</div>`,
selection => selection.modify('extend', 'backward', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C\'^?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C\'^?</div>`,
`${behavior} 19-41 rtl backward word`);
}
</script>
......@@ -94,13 +94,13 @@ selection_test(
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'|\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'^\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-13 rtl right word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202A|they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 |\u1500\u1501\u1502 \'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 |\'\u202A^they said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-14 rtl right word`);
selection_test(
......@@ -166,13 +166,13 @@ selection_test(
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "|\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"^\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-25 rtl right word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202B|car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey |said "\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said |"\u202B^car \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'?</div>`,
`${behavior} 19-26 rtl right word`);
selection_test(
......@@ -250,19 +250,19 @@ selection_test(
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"|\u202C\'?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"^\u202C\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"^\u202C\'?</div>`,
`${behavior} 19-39 rtl right word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C|\'?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C^\'?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C^\'?</div>`,
`${behavior} 19-40 rtl right word`);
selection_test(
`<div contenteditable dir="rtl" style="${kStyle}">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C"\u202C\'|?</div>`,
selection => selection.modify('extend', 'right', 'word'),
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 |\u05D0\u05D1\u05D2\u202C"\u202C\'^?</div>`,
`<div contenteditable dir="rtl" style="width: 600px; font: 20px monospace">\u05D6\u05D7\u05D8 \u1497\u1498\u1499 \u1500\u1501\u1502 \'\u202Athey said "\u202Bcar \u05D3\u05D4\u05D5 \u05D0\u05D1\u05D2\u202C|"\u202C\'^?</div>`,
`${behavior} 19-41 rtl right word`);
}
</script>
......@@ -19,7 +19,7 @@ test(() => assert_selection(
'</ul>'
].join(''),
selection => {
for (let i = 0; i < 6; ++i)
for (let i = 0; i < 11; ++i)
selection.modify('extend', 'forward', 'word');
},
[
......
......@@ -57,8 +57,8 @@ test(() => assert_selection(
[
'<div contenteditable>',
isMac
? 'foo<img src="../../resources/abe.png">bar| baz'
: 'foo<img src="../../resources/abe.png">bar |baz',
? 'foo<img src="../../resources/abe.png">|bar baz'
: 'foo<img src="../../resources/abe.png">|bar baz',
'</div>',
].join('')),
'Move forward word 2');
......@@ -102,7 +102,7 @@ test(() => assert_selection(
selection => selection.modify('move', 'backward', 'word'),
[
'<div contenteditable>',
'foo |bar<img src="../../resources/abe.png">baz',
'foo bar|<img src="../../resources/abe.png">baz',
'</div>',
].join('')),
'Move backward word 2');
......
......@@ -87,13 +87,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">abc def hij <img src="../../../accessibility/resources/cake.png">| opq rst </div>',
selection => selection.modify('move', 'left', 'word'),
'<div contenteditable dir="ltr">abc def |hij <img src="../../../accessibility/resources/cake.png"> opq rst </div>',
'<div contenteditable dir="ltr">abc def hij |<img src="../../../accessibility/resources/cake.png"> opq rst </div>',
'18-13 left word');
selection_test(
'<div contenteditable dir="ltr">abc def hij <img src="../../../accessibility/resources/cake.png"> |opq rst </div>',
selection => selection.modify('move', 'left', 'word'),
'<div contenteditable dir="ltr">abc def |hij <img src="../../../accessibility/resources/cake.png"> opq rst </div>',
'<div contenteditable dir="ltr">abc def hij |<img src="../../../accessibility/resources/cake.png"> opq rst </div>',
'18-14 left word');
selection_test(
......
......@@ -75,13 +75,13 @@ selection_test(
selection_test(
'<div contenteditable dir="ltr">abc def hij| <img src="../../../accessibility/resources/cake.png"> opq rst </div>',
selection => selection.modify('move', 'right', 'word'),
'<div contenteditable dir="ltr">abc def hij <img src="../../../accessibility/resources/cake.png"> opq |rst </div>',
'<div contenteditable dir="ltr">abc def hij <img src="../../../accessibility/resources/cake.png"> |opq rst </div>',
'18-11 right word');
selection_test(
'<div contenteditable dir="ltr">abc def hij |<img src="../../../accessibility/resources/cake.png"> opq rst </div>',
selection => selection.modify('move', 'right', 'word'),
'<div contenteditable dir="ltr">abc def hij <img src="../../../accessibility/resources/cake.png"> opq |rst </div>',
'<div contenteditable dir="ltr">abc def hij <img src="../../../accessibility/resources/cake.png"> |opq rst </div>',
'18-12 right word');
selection_test(
......
......@@ -20,11 +20,11 @@ steps.push(
textarea.focus();
document.execCommand('insertText', false, 'zz.');
input.focus();
document.execCommand('insertText', false, 'zz.');
document.execCommand('insertText', false, 'zz. ');
},
[
'<textarea id="textarea">#zz#.</textarea>',
'<input value="#zz#.">',
'<input value="#zz#. ">',
'<textarea id="aux"></textarea>'
].join(''),
{
......@@ -38,7 +38,7 @@ steps.push(
document => document.getElementById('aux').focus(),
[
'<textarea id="textarea">#zz#.</textarea>',
'<input value="zz.">',
'<input value="zz. ">',
'<textarea id="aux"></textarea>'
].join(''),
{
......@@ -52,7 +52,7 @@ steps.push(
document => document.querySelector('input').focus(),
[
'<textarea id="textarea">#zz#.</textarea>',
'<input value="#zz#.">',
'<input value="#zz#. ">',
'<textarea id="aux"></textarea>'
].join(''),
'Focusing INPUT preserves markers in TEXTAREA.'));
......
......@@ -59,17 +59,17 @@ spellcheck_test(
const textarea1 = document.getElementById('textarea1');
const textarea2 = document.getElementById('textarea2');
textarea1.focus();
document.execCommand('insertText', false, 'foo.');
document.execCommand('insertText', false, 'foo. ');
runIdleTimeSpellCheckerIfNeeded(document);
textarea2.focus();
document.execCommand('insertText', false, 'baz.');
document.execCommand('insertText', false, 'baz. ');
runIdleTimeSpellCheckerIfNeeded(document);
textarea1.focus();
document.execCommand('insertText', false, 'zz.');
document.execCommand('insertText', false, 'zz. ');
},
[
'<textarea id="textarea1">#foo#.#zz#.</textarea>',
'<textarea id="textarea2">#baz#.</textarea>'
'<textarea id="textarea1">#foo#. #zz#. </textarea>',
'<textarea id="textarea2">#baz#. </textarea>'
].join(''),
'Spellchecker invokes requests in sequence order.');
</script>
......@@ -9,45 +9,45 @@
spellcheck_test(
'<div contenteditable>|</div>',
'insertText zz.',
'<div contenteditable>#zz#.</div>',
'insertText zz. ',
'<div contenteditable>#zz#.\u00A0</div>',
'Mark misspellings after typing.');
spellcheck_test(
'<div contenteditable>|</div>',
'insertText You has the right.',
'<div contenteditable>You ~has~ the right.</div>',
'insertText You has the right. ',
'<div contenteditable>You ~has~ the right.\u00A0</div>',
'Mark ungrammatical phrases after typing.');
spellcheck_test(
'<div contenteditable>|</div>',
'insertText orange,zz,apple.',
'insertText orange,zz,apple. ',
// Grammar marker under the whole sentence, and spelling marker under 'zz'.
'<div contenteditable>~orange,#zz#,apple.~</div>',
'<div contenteditable>~orange,#zz#,apple.~\u00A0</div>',
'Mark overlapping grammar and spelling errors.');
spellcheck_test(
'<textarea>|</textarea>',
document => {
document.querySelector('textarea').focus();
document.execCommand('insertText', false, 'zz.');
document.execCommand('insertText', false, 'zz. ');
},
'<textarea>#zz#.</textarea>',
'<textarea>#zz#. </textarea>',
'Mark misspellings in <textarea>.');
spellcheck_test(
'<input type="text">|',
document => {
document.querySelector('input').focus();
document.execCommand('insertText', false, 'asd.');
document.execCommand('insertText', false, 'asd. ');
},
'<input type="text" value="#asd#.">',
'<input type="text" value="#asd#. ">',
'Mark misspellings in <input>.');
spellcheck_test(
'<div contenteditable spellcheck="false">zz.|</div>',
'<div contenteditable spellcheck="false">zz. |</div>',
'',
'<div contenteditable spellcheck="false">zz.</div>',
'<div contenteditable spellcheck="false">zz. </div>',
{
title: 'No marker on misspelled word when spellcheck=false.',
callback: sample => spellcheck_test(
......@@ -58,7 +58,7 @@ spellcheck_test(
// Trigger spellchecker by selection change.
document.getSelection().collapse(div, 0);
},
'<div contenteditable spellcheck="true">#zz#.</div>',
'<div contenteditable spellcheck="true">#zz#. </div>',
'Marker appears after setting spellcheck=true.'
)
});
......
......@@ -7,61 +7,61 @@
<script>
spellcheck_test(
'<div contenteditable><span>[|]</span></div>',
'insertText zz.',
'<div contenteditable><span>[#zz#.]</span></div>',
'insertText zz. ',
'<div contenteditable><span>[#zz#. ]</span></div>',
'Typing in child without spellcheck attribute whose parent node does not have spellcheck attribute.');
spellcheck_test(
'<div contenteditable><span spellcheck="true">[|]</span></div>',
'insertText zz.',
'<div contenteditable><span spellcheck="true">[#zz#.]</span></div>',
'insertText zz. ',
'<div contenteditable><span spellcheck="true">[#zz#. ]</span></div>',
'Typing in child with spellcheck=true whose parent node does not have spellcheck attribute.');
spellcheck_test(
'<div contenteditable><span spellcheck="false">[|]</span></div>',
'insertText zz.',
'<div contenteditable><span spellcheck="false">[zz.]</span></div>',
'insertText zz. ',
'<div contenteditable><span spellcheck="false">[zz. ]</span></div>',
'Typing in child with spellcheck=false whose parent node does not have spellcheck attribute.');
spellcheck_test(
'<div contenteditable spellcheck="true"><span>[|]</span></div>',
'insertText zz.',
'<div contenteditable spellcheck="true"><span>[#zz#.]</span></div>',
'insertText zz. ',
'<div contenteditable spellcheck="true"><span>[#zz#. ]</span></div>',
'Typing in child without spellcheck attribute whose parent node has spellcheck=true.');
spellcheck_test(
'<div contenteditable spellcheck="true"><span spellcheck="true">[|]</span></div>',
'insertText zz.',
'<div contenteditable spellcheck="true"><span spellcheck="true">[#zz#.]</span></div>',
'insertText zz. ',
'<div contenteditable spellcheck="true"><span spellcheck="true">[#zz#. ]</span></div>',
'Typing in child with spellcheck=true whose parent node has spellcheck=true.');
spellcheck_test(
'<div contenteditable spellcheck="true"><span spellcheck="false">[|]</span></div>',
'insertText zz.',
'<div contenteditable spellcheck="true"><span spellcheck="false">[zz.]</span></div>',
'insertText zz. ',
'<div contenteditable spellcheck="true"><span spellcheck="false">[zz. ]</span></div>',
'Typing in child with spellcheck=false whose parent node has spellcheck=true.');
spellcheck_test(
'<div contenteditable spellcheck="false"><span>[|]</span></div>',
'insertText zz.',
'<div contenteditable spellcheck="false"><span>[zz.]</span></div>',
'insertText zz. ',
'<div contenteditable spellcheck="false"><span>[zz. ]</span></div>',
'Typing in child without spellcheck attribute whose parent node has spellcheck=false.');
spellcheck_test(
'<div contenteditable spellcheck="false"><span spellcheck="true">[|]</span></div>',
'insertText zz.',
'<div contenteditable spellcheck="false"><span spellcheck="true">[#zz#.]</span></div>',
'insertText zz. ',
'<div contenteditable spellcheck="false"><span spellcheck="true">[#zz#. ]</span></div>',
'Typing in child with spellcheck=true whose parent node has spellcheck=false.');
spellcheck_test(
'<div contenteditable spellcheck="false"><span spellcheck="false">[|]</span></div>',
'insertText zz.',
'<div contenteditable spellcheck="false"><span spellcheck="false">[zz.]</span></div>',
'insertText zz. ',
'<div contenteditable spellcheck="false"><span spellcheck="false">[zz. ]</span></div>',
'Typing in child with spellcheck=false whose parent node has spellcheck=false.');
spellcheck_test(
'<div contenteditable><span spellcheck="false">zz</span>&nbsp;|</div>',
'insertText zz.',
'<div contenteditable><span spellcheck="false">zz</span>\u00A0#zz#.</div>',
'insertText zz. ',
'<div contenteditable><span spellcheck="false">zz</span>\u00A0#zz#.\u00A0</div>',
'Typing in spellchecked parent should not check child with spellcheck=false.');
</script>
......@@ -7,8 +7,8 @@
<script>
spellcheck_test(
'<div contenteditable>|</div>',
'insertText This sentence ends with a misspelled word asd.',
'<div contenteditable>This sentence ends with a misspelled word #asd#.</div>',
'insertText This sentence ends with a misspelled word asd. ',
'<div contenteditable>This sentence ends with a misspelled word #asd#.\u00A0</div>',
{
title: 'Mark misspelled word "asd" after typing.',
callback: sample => spellcheck_test(
......@@ -21,7 +21,7 @@ spellcheck_test(
selection.modify('move', 'backward', 'character');
selection.modify('move', 'backward', 'character');
},
'<div contenteditable>This sentence ends with a misspelled word #asd#.</div>',
'<div contenteditable>This sentence ends with a misspelled word #asd#.\u00A0</div>',
'Misspelled word should still be marked when caret is no longer adjacent with it.')
});
</script>
......@@ -6,27 +6,37 @@
<script>
spellcheck_test(
'<div contenteditable>|</div>',
'insertText Spell wellcome. Is it broken?',
'<div contenteditable>Spell #wellcome#. Is it broken?</div>',
// Insert a space after the misspelled word so it is spellchecked properly.
// This is done to trigger spellchecking as the punctuation after the misspelled word
// doesn't trigger spellchecking until the user has pressed space bar or changed the selection.
// This is how it should be done in real sites anyways so inserting the space after spellcheck
// makes sense.
'insertText Spell wellcome. ',
'<div contenteditable>Spell #wellcome#.\u00A0</div>',
{
title: '1 Setup a content editable div with spelling marker',
callback: sample => spellcheck_test(
sample,
document => {
assert_not_equals(window.eventSender, undefined, 'This test requires eventSender.');
assert_not_equals(window.eventSender, undefined, 'This test requires eventSender. ');
const destination = document.querySelector('div');
const textNode = destination.firstChild;
// Select the text "Is it broken?".
const deleteRange = document.createRange();
deleteRange.setStart(textNode, 15);
deleteRange.setEnd(textNode, 29);
deleteRange.setStart(textNode, 16);
deleteRange.setEnd(textNode, 16);
document.getSelection().removeAllRanges();
document.getSelection().addRange(deleteRange);
document.execCommand('insertText', false, 'Is it broken?');
const textNode1 = destination.firstChild;
// Select the text "Is it broken?".
deleteRange.setStart(textNode1, 16);
deleteRange.setEnd(textNode1, 29);
document.getSelection().removeAllRanges();
document.getSelection().addRange(deleteRange);
// Del key to delete the text "Is it broken?".
eventSender.keyDown("Delete", null);
// Delete the text "Is it broken?".
textNode1.deleteData(16, 29);
// Context click to show the context menu.
var x = destination.offsetParent.offsetLeft + destination.offsetLeft + 50;
......@@ -37,7 +47,7 @@ spellcheck_test(
// Esc key to hide the context menu.
eventSender.keyDown("Escape", null);
},
'<div contenteditable>Spell #wellcome#.</div>',
'<div contenteditable>Spell #wellcome#. </div>',
'1 Spellcheck should not crash after the text has changed.')
});
......
......@@ -7,8 +7,8 @@
<script>
spellcheck_test(
'<div contenteditable>|</div>',
'insertText wellcome.',
'<div contenteditable>#wellcome#.</div>',
'insertText wellcome. ',
'<div contenteditable>#wellcome#.\u00A0</div>',
{
title: 'Mark misspelled word "wellcome".',
callback: sample => test(() => {
......
......@@ -16,6 +16,8 @@ window.getSelection().modify("extend", "backward", "paragraphBoundary");
document.execCommand("ForeColor", false, "blue");
window.getSelection().modify("move", "forward", "character");
window.getSelection().modify("move", "backward", "word");
// Have to move again to account for punctuation
window.getSelection().modify("move", "backward", "word");
document.execCommand("ForeColor", false, "green");
document.execCommand("InsertText", false, "a combination of green and blue, not ");
</script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment