Bug 508477, add a flag to distinguish key focus navigation from other types of focus navigation, allows initial focused textboxes in a dialog to be selected by default, r=smaug

This commit is contained in:
Neil Deakin 2009-08-26 09:19:41 -07:00
parent 7f629101b9
commit 0beee44e9d
6 changed files with 65 additions and 13 deletions

View File

@ -1784,12 +1784,14 @@ nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm && (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) &&
SelectTextFieldOnFocus()) {
// select the text if the field was focused by the keyboard.
// select the text if the field was focused by the keyboard or a
// navigation.
nsIDocument* document = GetCurrentDoc();
if (document) {
PRUint32 lastFocusMethod;
fm->GetLastFocusMethod(document->GetWindow(), &lastFocusMethod);
if (lastFocusMethod & nsIFocusManager::FLAG_BYKEY) {
if (lastFocusMethod &
(nsIFocusManager::FLAG_BYKEY | nsIFocusManager::FLAG_BYMOVEFOCUS)) {
nsCOMPtr<nsPresContext> presContext = GetPresContext();
if (DispatchSelectEvent(presContext)) {
SelectAll(presContext);

View File

@ -292,12 +292,13 @@ nsHTMLLabelElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
// Use FLAG_BYKEY here so that the label is scrolled to. Also,
// within nsHTMLInputElement::PostHandleEvent, inputs will be
// selected only when focused via a key and we want to select
// the text on label clicks as well.
// Use FLAG_BYMOVEFOCUS here so that the label is scrolled to.
// Also, within nsHTMLInputElement::PostHandleEvent, inputs will
// be selected only when focused via a key or when the navigation
// flag is used and we want to select the text on label clicks as
// well.
nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(content);
fm->SetFocus(elem, nsIFocusManager::FLAG_BYKEY);
fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS);
}
// Dispatch a new click event to |content|

View File

@ -434,6 +434,14 @@ nsFocusManager::MoveFocus(nsIDOMWindow* aWindow, nsIDOMElement* aStartElement,
PRINTTAGF(">> $[[%s]]\n", mFocusedContent);
#endif
// use FLAG_BYMOVEFOCUS when switching focus with MoveFocus unless one of
// the other focus methods is already set, or we're just moving to the root
// or caret position.
if (aType != MOVEFOCUS_ROOT && aType != MOVEFOCUS_CARET &&
(aFlags & FOCUSMETHOD_MASK) == 0) {
aFlags |= FLAG_BYMOVEFOCUS;
}
nsCOMPtr<nsPIDOMWindow> window;
nsCOMPtr<nsIContent> startContent;
if (aStartElement) {

View File

@ -198,6 +198,14 @@ interface nsIFocusManager : nsISupports
*/
const unsigned long FLAG_BYKEY = 0x2000;
/**
* Focus is changing due to a call to MoveFocus. This flag will be implied
* when MoveFocus is called except when one of the other mechanisms (mouse
* or key) is specified, or when the type is MOVEFOCUS_ROOT or
* MOVEFOCUS_CARET.
*/
const unsigned long FLAG_BYMOVEFOCUS = 0x4000;
// these constants are used with the aType argument to MoveFocus
/** move focus forward one element, used when pressing TAB */

View File

@ -470,9 +470,11 @@ function startTest()
// the focus() method on the legend element should focus the legend if it is
// focusable, or the first element after the legend if it is not focusable.
if (!gPartialTabbing) {
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
var legend = getById("legend");
expectFocusShift(function () legend.focus(),
null, "t28", true, "focus method on unfocusable legend");
gLastFocusMethod = 0;
legend.tabIndex = "0";
expectFocusShift(function () legend.focus(),
null, "legend", true, "focus method on focusable legend");
@ -488,7 +490,8 @@ function startTest()
for (var k = 0; k < keys.length; k++) {
var key = String.fromCharCode(65 + k);
gLastFocusMethod = fm.FLAG_BYKEY;
// accesskeys D and G are for labels so get redirected
gLastFocusMethod = (key == "D" || key == "G") ? fm.FLAG_BYMOVEFOCUS : fm.FLAG_BYKEY;
// on Windows and Linux, the shift key must be pressed for content area access keys
if (navigator.platform.indexOf("Mac") == -1)
@ -499,18 +502,18 @@ function startTest()
}
// clicking on the labels
gLastFocusMethod = -1;
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
expectFocusShift(function () synthesizeMouse(getById("ad"), 2, 2, { }, gChildWindow),
null, "t29", true, "mouse on html label with content inside");
expectFocusShift(function () synthesizeMouse(getById("ag"), 2, 2, { }, gChildWindow),
null, "n14", true, "mouse on html label with for attribute");
gLastFocusMethod = 0;
expectFocusShift(function () synthesizeMouse(getById("aj"), 2, 2, { }),
null, "o9", true, "mouse on xul label with content inside");
expectFocusShift(function () synthesizeMouse(getById("ak"), 2, 2, { }),
null, "n6", true, "mouse on xul label with control attribute");
// test accesskeys that shouldn't work
gLastFocusMethod = 0;
k = "o".charCodeAt(0);
while (k++ < "v".charCodeAt(0)) {
var key = String.fromCharCode(k);
@ -677,10 +680,10 @@ function startTest()
if (!gPartialTabbing)
doCommandDispatcherTests();
doRemoveTests();
testMoveFocus();
doRemoveTests();
// tests various focus manager apis for null checks
var exh = false;
try {
@ -701,6 +704,7 @@ function startTest()
// ---- tests for the FLAG_NOSWITCHFRAME flag
getById("o5").focus();
gLastFocusMethod = 0;
gEvents = "";
// focus is being shifted in a child, so the focus should not change
expectFocusShift(function () fm.setFocus(getById("t20"), fm.FLAG_NOSWITCHFRAME),
@ -741,19 +745,24 @@ function startTest()
$("innerbox").appendChild(textbox2);
textbox2.inputField.id = "innerinput2";
gLastFocusMethod = 0;
expectFocusShift(function () textbox2.focus(),
null, "innerinput2", true, "focus on textbox");
gLastFocusMethod = fm.FLAG_BYKEY;
expectFocusShift(function () synthesizeKey("VK_TAB", { shiftKey: true }),
null, "innerinput1", true, "shift+tab on textbox");
textbox1.tabIndex = 2;
textbox2.tabIndex = 2;
gLastFocusMethod = 0;
expectFocusShift(function () textbox2.focus(),
null, "innerinput2", true, "focus on textbox with tabindex set");
gLastFocusMethod = fm.FLAG_BYKEY;
expectFocusShift(function () synthesizeKey("VK_TAB", { shiftKey: true }),
null, "innerinput1", true, "shift+tab on textbox with tabindex set");
setFocusTo("t9", window);
gLastFocusMethod = -1;
window.openDialog("focus_window2.xul", "_blank", "chrome", otherWindowFocused, null);
}
@ -814,6 +823,7 @@ function testMoveFocus()
// moving focus while an element is already focused
var newFocus;
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
var expectedFirst = gPartialTabbing ? "t3" : "t1";
expectFocusShift(function () newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FIRST, 0),
window, expectedFirst, true, "moveFocus to first null window null content");
@ -823,6 +833,7 @@ function testMoveFocus()
window, "last", true, "moveFocus to last null window null content");
is(newFocus, fm.focusedElement, "moveFocus to last null window null content return value");
gLastFocusMethod = 0;
newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_ROOT, 0);
is(newFocus, null, "moveFocus to root null window null content return value");
is(fm.focusedWindow, window, "moveFocus to root null window null content focusedWindow");
@ -832,6 +843,7 @@ function testMoveFocus()
fm.clearFocus(window);
gEvents = "";
gLastFocus = null;
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
expectFocusShift(function () newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FIRST, 0),
window, expectedFirst, true, "moveFocus to first null window null content no focus");
is(newFocus, fm.focusedElement, "moveFocus to first null window null content no focus return value");
@ -843,6 +855,7 @@ function testMoveFocus()
is(newFocus, fm.focusedElement, "moveFocus to last null window null content no focus return value");
fm.clearFocus(window);
gEvents = "";
gLastFocusMethod = 0;
newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_ROOT, 0);
is(newFocus, null, "moveFocus to root null window null content no focus return value");
is(fm.focusedWindow, window, "moveFocus to root null window null content no focus focusedWindow");
@ -850,6 +863,7 @@ function testMoveFocus()
// moving focus from a specified element
setFocusTo("t6", window);
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
expectFocusShift(function () newFocus = fm.moveFocus(null, getById("specialroot"), fm.MOVEFOCUS_FIRST, 0),
window, "t3", true, "moveFocus to first null window with content");
// XXXndeakin P3 this doesn't work
@ -875,6 +889,7 @@ function testMoveFocus()
// move focus to root in child window
setFocusTo("t6", window);
var childroot = getById("t" + kChildDocumentRootIndex);
gLastFocusMethod = 0;
newFocus = fm.moveFocus(gChildWindow, null, fm.MOVEFOCUS_ROOT, 0),
is(newFocus, childroot, "moveFocus to root child window null content return value");
is(fm.focusedWindow, gChildWindow, "moveFocus to root child window null content focusedWindow");
@ -919,6 +934,24 @@ function testMoveFocus()
is(fm.focusedElement, getById("t24"), "move caret away onto link");
prefs.setBoolPref("accessibility.browsewithcaret", false);
var t19 = getById("t19");
t19.setSelectionRange(0, 0);
setFocusTo("t18", gChildWindow);
gLastFocusMethod = fm.FLAG_BYMOVEFOCUS;
expectFocusShift(function () newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, 0),
gChildWindow, t19, true, "moveFocus to next textbox");
is(t19.selectionStart, 0, "input focused after moveFocus selectionStart");
is(t19.selectionEnd, 5, "input focused after moveFocus selectionEnd");
t19.setSelectionRange(0, 0);
setFocusTo("t18", gChildWindow);
gLastFocusMethod = fm.FLAG_BYKEY;
expectFocusShift(function () newFocus = fm.moveFocus(null, null, fm.MOVEFOCUS_FORWARD, fm.FLAG_BYKEY),
gChildWindow, t19, true, "moveFocus to next textbox by key");
is(t19.selectionStart, 0, "input focused after moveFocus by key selectionStart");
is(t19.selectionEnd, 5, "input focused after moveFocus by key selectionEnd");
}
function otherWindowFocused(otherWindow)

View File

@ -204,7 +204,7 @@ nsPrintPreviewListener::HandleEvent(nsIDOMEvent* aEvent)
fm->MoveFocus(win, from,
forward ? nsIFocusManager::MOVEFOCUS_FORWARD :
nsIFocusManager::MOVEFOCUS_BACKWARD,
0, getter_AddRefs(result));
nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
}
}
}