Bug 1050439 - Focus should be restored to previously active element after split console is closed;r=jwalker

This commit is contained in:
Brian Grinstead 2014-08-15 07:50:43 -05:00
parent 02f68bcd12
commit a537346a65
3 changed files with 104 additions and 2 deletions

View File

@ -76,6 +76,7 @@ function Toolbox(target, selectedTool, hostType, hostOptions) {
this._highlighterHidden = this._highlighterHidden.bind(this);
this._prefChanged = this._prefChanged.bind(this);
this._saveSplitConsoleHeight = this._saveSplitConsoleHeight.bind(this);
this._onFocus = this._onFocus.bind(this);
this._target.on("close", this.destroy);
@ -253,7 +254,7 @@ Toolbox.prototype = {
this._applyCacheSettings();
this._addKeysToWindow();
this._addReloadKeys();
this._addToolSwitchingKeys();
this._addHostListeners();
this._addZoomKeys();
this._loadInitialZoom();
@ -345,7 +346,7 @@ Toolbox.prototype = {
});
},
_addToolSwitchingKeys: function() {
_addHostListeners: function() {
let nextKey = this.doc.getElementById("toolbox-next-tool-key");
nextKey.addEventListener("command", this.selectNextTool.bind(this), true);
let prevKey = this.doc.getElementById("toolbox-previous-tool-key");
@ -354,6 +355,8 @@ Toolbox.prototype = {
// Split console uses keypress instead of command so the event can be
// cancelled with stopPropagation on the keypress, and not preventDefault.
this.doc.addEventListener("keypress", this._splitConsoleOnKeypress, false);
this.doc.addEventListener("focus", this._onFocus, true);
},
_saveSplitConsoleHeight: function() {
@ -982,6 +985,23 @@ Toolbox.prototype = {
}
},
/**
* If the console is split and we are focusing an element outside
* of the console, then store the newly focused element, so that
* it can be restored once the split console closes.
*/
_onFocus: function({originalTarget}) {
// Ignore any non element nodes, or any elements contained
// within the webconsole frame.
let webconsoleURL = gDevTools.getToolDefinition("webconsole").url;
if (originalTarget.nodeType !== 1 ||
originalTarget.baseURI === webconsoleURL) {
return;
}
this._lastFocusedElement = originalTarget;
},
/**
* Opens the split console.
*
@ -993,6 +1013,7 @@ Toolbox.prototype = {
Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, true);
this._refreshConsoleDisplay();
this.emit("split-console");
return this.loadTool("webconsole").then(() => {
this.focusConsoleInput();
});
@ -1009,6 +1030,10 @@ Toolbox.prototype = {
Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, false);
this._refreshConsoleDisplay();
this.emit("split-console");
if (this._lastFocusedElement) {
this._lastFocusedElement.focus();
}
return promise.resolve();
},
@ -1312,6 +1337,7 @@ Toolbox.prototype = {
destroyHost: function() {
this.doc.removeEventListener("keypress",
this._splitConsoleOnKeypress, false);
this.doc.removeEventListener("focus", this._onFocus, true);
return this._host.destroy();
},
@ -1334,6 +1360,7 @@ Toolbox.prototype = {
gDevTools.off("pref-changed", this._prefChanged);
this._lastFocusedElement = null;
this._saveSplitConsoleHeight();
this.webconsolePanel.removeEventListener("resize",
this._saveSplitConsoleHeight);

View File

@ -281,6 +281,7 @@ skip-if = buildapp == 'mulet'
[browser_webconsole_scratchpad_panel_link.js]
[browser_webconsole_split.js]
[browser_webconsole_split_escape_key.js]
[browser_webconsole_split_focus.js]
[browser_webconsole_split_persist.js]
[browser_webconsole_view_source.js]
[browser_webconsole_reflow.js]

View File

@ -0,0 +1,74 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
info("Test that the split console state is persisted");
let toolbox;
let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
Task.spawn(runner).then(finish);
function* runner() {
info("Opening a tab while there is no user setting on split console pref");
let {tab} = yield loadTab(TEST_URI);
let target = TargetFactory.forTab(tab);
toolbox = yield gDevTools.showToolbox(target, "inspector");
ok(!toolbox.splitConsole, "Split console is hidden by default");
info ("Focusing the search box before opening the split console");
let inspector = toolbox.getPanel("inspector");
inspector.searchBox.focus();
// Use the binding element since inspector.searchBox is a XUL element.
let activeElement = getActiveElement(inspector.panelDoc);
activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
is (activeElement, inspector.searchBox, "Search box is focused");
yield toolbox.openSplitConsole();
ok(toolbox.splitConsole, "Split console is now visible");
// Use the binding element since jsterm.inputNode is a XUL textarea element.
let activeElement = getActiveElement(toolbox.doc);
activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
is(activeElement, inputNode, "Split console input is focused by default");
yield toolbox.closeSplitConsole();
info ("Making sure that the search box is refocused after closing the split console");
// Use the binding element since inspector.searchBox is a XUL element.
let activeElement = getActiveElement(inspector.panelDoc);
activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
is (activeElement, inspector.searchBox, "Search box is focused");
yield toolbox.destroy();
}
function getActiveElement(doc) {
let activeElement = doc.activeElement;
while (activeElement && activeElement.contentDocument) {
activeElement = activeElement.contentDocument.activeElement;
}
return activeElement;
}
function toggleSplitConsoleWithEscape() {
let onceSplitConsole = toolbox.once("split-console");
let contentWindow = toolbox.frame.contentWindow;
contentWindow.focus();
EventUtils.sendKey("ESCAPE", contentWindow);
return onceSplitConsole;
}
function finish() {
toolbox = TEST_URI = null;
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight");
finishTest();
}
}