зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1670531 - Only select selectable element if it isn't editable. r=masayuki
When caret is [] in the following html then we use [shift] + [arrow right], Gecko select non-editable text and "C" character. This behaviour is different of Blink and WebKit. They select only non-editable element by this operation. ``` <div contenteditable>A[]<span contenteditable=false><B</span>C</div> ``` Another example is `<img>` element with `contenteditable=false`. If this `<img>` element is editable, [shift] + [arrow right] doesn't select "C" character, but if this `<img>` element isn't editable, [shift] + [arrow right] selects additional "C" character on Gecko. ``` <div contenteditable>A[]<img contenteditable=false src=... />C</div> ``` So I would like to change this behaviour to Blink/Webkit way. `PeekOffsetForCharacter` is looking for selection end. When it is selecting elements, if traversed frame/content has non-select frame/content, we select first character of editable text. But when we already have selected element, it is unnecessary to select editable text. Also, bug1524266-4.html is unfortunately work now and we don't support white space compression for this situation (bug 1670518). Even if inner span is editable, we don't compress white space. So we need a workaround for this test. Differential Revision: https://phabricator.services.mozilla.com/D93300
This commit is contained in:
Родитель
bdc3f86e85
Коммит
dfdccd0200
|
@ -10,10 +10,7 @@
|
|||
</style>
|
||||
<div contenteditable="true" spellcheck="false">
|
||||
xx
|
||||
<span contenteditable="false">
|
||||
NOT EDITABLE
|
||||
</span>
|
||||
xxx
|
||||
<span contenteditable="false">NOT EDITABLE</span>xxx
|
||||
</div>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function() {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<title>Select non-editable content in an editor</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
div:focus {
|
||||
outline: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
<div contenteditable="true" spellcheck="false">
|
||||
xx<span contenteditable="false">NOT EDITABLE</span>xxx
|
||||
</div>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function() {
|
||||
document.querySelector('[contenteditable="true"]').focus();
|
||||
requestAnimationFrame(function() {
|
||||
// Move after the two x
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
}
|
||||
// Select <span>
|
||||
synthesizeKey("KEY_ArrowRight", { shiftKey: true });
|
||||
document.documentElement.removeAttribute("class");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<title>Select non-editable content in an editor</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
div:focus {
|
||||
outline: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
<div contenteditable="true" spellcheck="false">
|
||||
xx<span contenteditable="false">NOT EDITABLE</span>xxx
|
||||
</div>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function() {
|
||||
document.querySelector('[contenteditable="true"]').focus();
|
||||
requestAnimationFrame(function() {
|
||||
// Move before the three x
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
}
|
||||
// Select <span>
|
||||
synthesizeKey("KEY_ArrowLeft", { shiftKey: true });
|
||||
document.documentElement.removeAttribute("class");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<title>Select non-editable content in an editor</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
div:focus {
|
||||
outline: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
<div contenteditable="true" spellcheck="false">
|
||||
xx<img src="image_rgrg-256x256.png">xxx
|
||||
</div>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function() {
|
||||
document.querySelector('[contenteditable="true"]').focus();
|
||||
requestAnimationFrame(function() {
|
||||
// Move after the two x
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
}
|
||||
// Select <img>
|
||||
synthesizeKey("KEY_ArrowRight", { shiftKey: true });
|
||||
document.documentElement.removeAttribute("class");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<title>Select non-editable content in an editor</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
div:focus {
|
||||
outline: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
<div contenteditable="true" spellcheck="false">
|
||||
xx<img contenteditable="false" src="image_rgrg-256x256.png">xxx
|
||||
</div>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function() {
|
||||
document.querySelector('[contenteditable="true"]').focus();
|
||||
requestAnimationFrame(function() {
|
||||
// Move after the two x
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
}
|
||||
// Select <img>
|
||||
synthesizeKey("KEY_ArrowRight", { shiftKey: true });
|
||||
document.documentElement.removeAttribute("class");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html class="reftest-wait">
|
||||
<title>Select non-editable content in an editor</title>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
div:focus {
|
||||
outline: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
<div contenteditable="true" spellcheck="false">
|
||||
xx<img contenteditable="false" src="image_rgrg-256x256.png">xxx
|
||||
</div>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function() {
|
||||
document.querySelector('[contenteditable="true"]').focus();
|
||||
requestAnimationFrame(function() {
|
||||
// Move before the three x
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
synthesizeKey("KEY_ArrowRight");
|
||||
}
|
||||
// Select <img>
|
||||
synthesizeKey("KEY_ArrowLeft", { shiftKey: true });
|
||||
document.documentElement.removeAttribute("class");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -375,6 +375,11 @@ support-files =
|
|||
bug1637476-2-ref.html
|
||||
bug1637476-3.html
|
||||
bug1637476-3-ref.html
|
||||
bug1670531-1.html
|
||||
bug1670531-2.html
|
||||
bug1670531-3.html
|
||||
bug1670531-3-ref.html
|
||||
bug1670531-4.html
|
||||
image_rgrg-256x256.png
|
||||
input-invalid-ref.html
|
||||
input-maxlength-invalid-change.html
|
||||
|
|
|
@ -274,6 +274,10 @@ var tests = [
|
|||
[ 'bug1637476-1.html' , 'bug1637476-1-ref.html' ] ,
|
||||
[ 'bug1637476-2.html' , 'bug1637476-2-ref.html' ] ,
|
||||
[ 'bug1637476-3.html' , 'bug1637476-3-ref.html' ] ,
|
||||
// shift+arrow key should select non-editable only
|
||||
[ 'bug1670531-1.html' , 'bug1670531-2.html' ] ,
|
||||
[ 'bug1670531-3.html' , 'bug1670531-3-ref.html' ] ,
|
||||
[ 'bug1670531-4.html' , 'bug1670531-3-ref.html' ] ,
|
||||
function() {SpecialPowers.pushPrefEnv({'clear': [['layout.accessiblecaret.enabled_on_touch']]}, nextTest);} ,
|
||||
function() {SpecialPowers.pushPrefEnv({'set': [['accessibility.browsewithcaret', true]]}, nextTest);} ,
|
||||
[ 'bug1529492-1.html' , 'bug1529492-1-ref.html' ] ,
|
||||
|
|
|
@ -8448,6 +8448,7 @@ nsresult nsIFrame::PeekOffsetForCharacter(nsPeekOffsetStruct* aPos,
|
|||
}
|
||||
next.mJumpedLine |= current.mJumpedLine;
|
||||
next.mMovedOverNonSelectableText |= current.mMovedOverNonSelectableText;
|
||||
next.mHasSelectableFrame |= current.mHasSelectableFrame;
|
||||
current = next;
|
||||
}
|
||||
|
||||
|
@ -8455,7 +8456,7 @@ nsresult nsIFrame::PeekOffsetForCharacter(nsPeekOffsetStruct* aPos,
|
|||
// the offset to be at the frame edge. Note that if we are extending the
|
||||
// selection, this doesn't matter.
|
||||
if (peekSearchState == FOUND && current.mMovedOverNonSelectableText &&
|
||||
!aPos->mExtend) {
|
||||
(!aPos->mExtend || current.mHasSelectableFrame)) {
|
||||
int32_t start, end;
|
||||
current.mFrame->GetOffsets(start, end);
|
||||
current.mOffset = aPos->mDirection == eDirNext ? 0 : end - start;
|
||||
|
@ -9017,6 +9018,9 @@ nsIFrame::SelectablePeekReport nsIFrame::GetFrameFromDirection(
|
|||
|
||||
selectable = IsSelectable(traversedFrame);
|
||||
if (!selectable) {
|
||||
if (traversedFrame->IsSelectable(nullptr)) {
|
||||
result.mHasSelectableFrame = true;
|
||||
}
|
||||
result.mMovedOverNonSelectableText = true;
|
||||
}
|
||||
} // while (!selectable)
|
||||
|
|
|
@ -3773,6 +3773,9 @@ class nsIFrame : public nsQueryFrame {
|
|||
bool mJumpedHardBreak = false;
|
||||
/** whether we jumped over a non-selectable frame during the search */
|
||||
bool mMovedOverNonSelectableText = false;
|
||||
/** whether we met selectable text frame that isn't editable during the
|
||||
* search */
|
||||
bool mHasSelectableFrame = false;
|
||||
|
||||
FrameSearchResult PeekOffsetNoAmount(bool aForward) {
|
||||
return mFrame->PeekOffsetNoAmount(aForward, &mOffset);
|
||||
|
|
Загрузка…
Ссылка в новой задаче