Bug 1109968 - Make all links in editable regions unfocusable; r=roc

The content inside an editable region is either editable itself, or
is inside a contenteditable="false" subtree.  In the first case,
it should not be focusable since it is editable.  In the second
case, it should not be focusable since the entire non-editable
region is treated as a special single entity for the purposes of
selection and caret movement, and having something focusable in
the middle of such a subtree breaks that model.
This commit is contained in:
Ehsan Akhgari 2015-01-17 18:50:09 -05:00
parent 78c5bea5db
commit ad6e9a36cc
7 changed files with 101 additions and 1 deletions

View File

@ -193,6 +193,18 @@ HTMLAnchorElement::UnbindFromTree(bool aDeep, bool aNullParent)
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}
static bool
IsNodeInEditableRegion(nsINode* aNode)
{
while (aNode) {
if (aNode->IsEditable()) {
return true;
}
aNode = aNode->GetParent();
}
return false;
}
bool
HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
bool *aIsFocusable, int32_t *aTabIndex)
@ -214,7 +226,9 @@ HTMLAnchorElement::IsHTMLFocusable(bool aWithMouse,
}
}
if (IsEditable()) {
// Links that are in an editable region should never be focusable, even if
// they are in a contenteditable="false" region.
if (IsNodeInEditableRegion(this)) {
if (aTabIndex) {
*aTabIndex = -1;
}

View File

@ -0,0 +1,17 @@
<html class="reftest-wait">
<body onload="start()">
<div onfocus="done()" contenteditable>foo<div contenteditable="false"><a href="#">bar</a></div>baz</div>
<script>
var div = document.querySelector("div");
function start() {
div.focus();
}
function done() {
var sel = getSelection();
// Set the caret right before "baz"
sel.collapse(div.lastChild, 0);
document.documentElement.removeAttribute("class");
}
</script>
</body>
</html>

View File

@ -0,0 +1,23 @@
<html class="reftest-wait">
<head>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
</head>
<body onload="start()">
<div onfocus="done()" contenteditable>foo<div contenteditable="false"><a href="#">bar</a></div>baz</div>
<script>
var div = document.querySelector("div");
function start() {
div.focus();
}
function done() {
var sel = getSelection();
sel.collapse(div, 0);
// Press Right four times to set the caret right before "baz"
for (var i = 0; i < 5; ++i) {
synthesizeKey("VK_RIGHT", {});
}
document.documentElement.removeAttribute("class");
}
</script>
</body>
</html>

View File

@ -0,0 +1,17 @@
<html class="reftest-wait">
<body onload="start()">
<div onfocus="done()" contenteditable>foo<div contenteditable="false"><img src="image_rgrg-256x256.png" width="10" height="10"></div>bar</div>
<script>
var div = document.querySelector("div");
function start() {
div.focus();
}
function done() {
var sel = getSelection();
// Set the caret right before "bar"
sel.collapse(div.lastChild, 0);
document.documentElement.removeAttribute("class");
}
</script>
</body>
</html>

View File

@ -0,0 +1,23 @@
<html class="reftest-wait">
<head>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
</head>
<body onload="start()">
<div onfocus="done()" contenteditable>foo<div contenteditable="false"><img src="image_rgrg-256x256.png" width="10" height="10"></div>bar</div>
<script>
var div = document.querySelector("div");
function start() {
div.focus();
}
function done() {
var sel = getSelection();
sel.collapse(div, 0);
// Press Right four times to set the caret right before "bar"
for (var i = 0; i < 6; ++i) {
synthesizeKey("VK_RIGHT", {});
}
document.documentElement.removeAttribute("class");
}
</script>
</body>
</html>

View File

@ -55,6 +55,10 @@ support-files =
bug644768.html
bug1061468.html
bug1061468-ref.html
bug1109968-1-ref.html
bug1109968-1.html
bug1109968-2-ref.html
bug1109968-2.html
[test_preserve3d_sorting_hit_testing.html]
[test_after_paint_pref.html]

View File

@ -109,6 +109,8 @@ var tests = [
[ 'bug613807-1.html' , 'bug613807-1-ref.html' ] ,
[ 'bug1082486-1.html', 'bug1082486-1-ref.html'] ,
[ 'bug1082486-2.html', 'bug1082486-2-ref.html'] ,
[ 'bug1109968-1.html', 'bug1109968-1-ref.html'] ,
[ 'bug1109968-2.html', 'bug1109968-2-ref.html'] ,
// The following test cases are all involving with one sending
// synthesizeKey(), the other without. They ought to be failed
// when touch caret preference on. Test them with preference off.