Bug 1318312 part.3 Selection should move focus at every selection change when it's called by JS r=smaug
Selection may be changed by methods of Selection or methods of Range retrieved by Selection.getRangeAt(). Selection::NotifySelectionListeners() is called after every selection change of each of them, so, this method must be a good point to move focus.
If new common ancestor of all ranges is editable and in an editing host, we should move focus to it. Otherwise, if an editing host has focus but new common ancestor is not editable, we should move focus from the editing host.
For consistency with the other browsers, this patch doesn't move focus to other focusable element.
MozReview-Commit-ID: 6sNsuzwqECX
<!DOCTYPE>
<html>
<head>
<title>Test for bug1318312</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style type="text/css">
</style>
</head>
<body>
<div id="outerEditor" contenteditable><p>content of outer editor</p>
<div id="staticInEditor" contenteditable="false"><p>static content of outer editor</p>
<div id="innerEditor" contenteditable><p>content of inner editor</p></div></div></div>
<pre id="test">
<script class="testbody" type="text/javascript">
var outerEditor = document.getElementById("outerEditor");
function runTests()
{
outerEditor.focus();
is(document.activeElement, outerEditor,
"outerEditor should have focus");
// Move cursor into the innerEditor with ArrowDown key. Then, focus shouldn't
// be moved to innerEditor from outerEditor.
// Note that Chrome moves focus in this case. However, we should do that
// at least for now because user can move focus with ArrowUp key even from
// innerEditor to outerEditor but we don't allow such navigation.
// FYI: Edge behaves same as us.
synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by moving caret");
is(document.getSelection().focusNode, document.getElementById("innerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the innerEditor");
is(document.getSelection().focusOffset, 0,
"focus offset of selection should be 0");
synthesizeKey("a", { code: "KeyA" });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by typing a character");
is(document.getSelection().focusNode, document.getElementById("innerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the innerEditor");
is(document.getSelection().focusOffset, 1,
"focus offset of selection should be 1");
synthesizeKey("KEY_Enter", { code: "Enter" });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by typing Enter");
is(document.getSelection().focusNode, document.getElementById("innerEditor").childNodes.item(1).firstChild,
"focus node of selection should be the text node in the second paragraph in the innerEditor");
is(document.getSelection().focusOffset, 0,
"focus offset of selection should be 0");
synthesizeKey("KEY_Backspace", { code: "Backspace" });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by typing Backspace (removing the line breaker)");
is(document.getSelection().focusNode, document.getElementById("innerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the innerEditor");
is(document.getSelection().focusOffset, 1,
"focus offset of selection should be 1");
synthesizeKey("KEY_ArrowLeft", { code: "ArrowLeft", shiftKey: true });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by typing Shift+ArrowLeft (selecting 'a')");
is(document.getSelection().focusNode, document.getElementById("innerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the innerEditor");
is(document.getSelection().focusOffset, 0,
"focus offset of selection should be 0");
is(document.getSelection().anchorNode, document.getElementById("innerEditor").firstChild.firstChild,
"anchor node of selection should be the text node in the innerEditor");
is(document.getSelection().anchorOffset, 1,
"anchor offset of selection should be 1");
synthesizeKey("KEY_Delete", { code: "Delete" });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by typing Delete (removing the 'a')");
is(document.getSelection().focusNode, document.getElementById("innerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the innerEditor");
is(document.getSelection().focusOffset, 0,
"focus offset of selection should be 0");
synthesizeKey("KEY_ArrowUp", { code: "ArrowUp" });
is(document.activeElement, outerEditor,
"outerEditor should still have focus because focus shouldn't be moved by moving caret from innerEditor to outerEditor");
is(document.getSelection().focusNode, document.getElementById("outerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the outerEditor");
is(document.getSelection().focusOffset, 0,
"focus offset of selection should be 0");
// However, clicking in innerEditor should move focus.
synthesizeMouseAtCenter(innerEditor, {});
is(document.activeElement, innerEditor,
"innerEditor should get focus because focus should be moved to innerEditor even from outerEditor by click");
is(document.getSelection().focusNode, document.getElementById("innerEditor").firstChild.firstChild,
"focus node of selection should be the text node in the innerEditor");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTests);
</script>
</pre>
</body>
</html>