vpat 3: consistent focus order in all directions (#3953)
On last tab in the itemPane/contextPane, focus will wrap around to the selected tab to complete the loop. It ensures that the focus order is consistent regardless of the directions. Also, minor tweaks to focusWrapAround in Zotero_Tabs to properly move focus to the last focusable entry in the contextPane.
This commit is contained in:
parent
4432f88f1d
commit
9421e09e84
2 changed files with 55 additions and 25 deletions
|
@ -749,36 +749,41 @@ var Zotero_Tabs = new function () {
|
|||
|
||||
// Used to move focus back to itemTree or contextPane from the tabs.
|
||||
this.focusWrapAround = function () {
|
||||
// Focus the last field of contextPane when reader is opened
|
||||
if (Zotero_Tabs.selectedIndex > 0) {
|
||||
Services.focus.moveFocus(window, document.getElementById("zotero-context-pane-sidenav"),
|
||||
Services.focus.MOVEFOCUS_BACKWARD, 0);
|
||||
return;
|
||||
}
|
||||
// If no item is selected, focus items list.
|
||||
if (ZoteroPane.itemPane.mode == "message") {
|
||||
document.getElementById("item-tree-main-default").focus();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
let selected = ZoteroPane.getSelectedItems();
|
||||
// If the selected collection row is duplicates, just focus on the
|
||||
// itemTree until the merge pane is keyboard accessible
|
||||
// If multiple items selected, focus on itemTree as well.
|
||||
let collectionRow = ZoteroPane.collectionsView.selectedTreeRow;
|
||||
if (collectionRow.isDuplicates() || selected.length !== 1) {
|
||||
document.getElementById("item-tree-main-default").focus();
|
||||
return;
|
||||
}
|
||||
// Special treatment for notes and attachments in itemPane
|
||||
selected = selected[0];
|
||||
if (selected.isNote()) {
|
||||
document.getElementById("zotero-note-editor").focus();
|
||||
return;
|
||||
}
|
||||
if (selected.isAttachment()) {
|
||||
document.getElementById("attachment-note-editor").focus();
|
||||
return;
|
||||
}
|
||||
// For regular items, focus the last field
|
||||
// We do that by moving focus backwards from the element following the pane, because Services.focus doesn't
|
||||
// support MOVEFOCUS_LAST on subtrees
|
||||
Services.focus.moveFocus(window, document.getElementById('zotero-context-splitter'),
|
||||
Services.focus.MOVEFOCUS_BACKWARD, 0);
|
||||
let selected = ZoteroPane.getSelectedItems();
|
||||
// If the selected collection row is duplicates, just focus on the
|
||||
// itemTree until the merge pane is keyboard accessible
|
||||
// If multiple items selected, focus on itemTree as well.
|
||||
let collectionRow = ZoteroPane.collectionsView.selectedTreeRow;
|
||||
if (collectionRow.isDuplicates() || selected.length !== 1) {
|
||||
document.getElementById("item-tree-main-default").focus();
|
||||
return;
|
||||
}
|
||||
// Special treatment for notes and attachments in itemPane
|
||||
selected = selected[0];
|
||||
if (selected.isNote()) {
|
||||
document.getElementById("zotero-note-editor").focus();
|
||||
return;
|
||||
}
|
||||
if (selected.isAttachment()) {
|
||||
document.getElementById("attachment-note-editor").focus();
|
||||
return;
|
||||
}
|
||||
// For regular items, focus the last field
|
||||
// We do that by moving focus backwards from the element following the pane, because Services.focus doesn't
|
||||
// support MOVEFOCUS_LAST on subtrees
|
||||
Services.focus.moveFocus(window, document.getElementById("zotero-context-splitter"),
|
||||
Services.focus.MOVEFOCUS_BACKWARD, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,6 +39,7 @@ var ZoteroPane = new function()
|
|||
this.__defineGetter__('loaded', function () { return _loaded; });
|
||||
var _lastSelectedItems = [];
|
||||
var lastFocusedElement = null;
|
||||
this.lastKeyPress = null;
|
||||
|
||||
//Privileged methods
|
||||
this.destroy = destroy;
|
||||
|
@ -879,6 +880,7 @@ var ZoteroPane = new function()
|
|||
* E.g. tab navigation hotkeys should work regardless of which component is focused.
|
||||
*/
|
||||
function captureKeyDown(event) {
|
||||
ZoteroPane.lastKeyPress = (event.shiftKey ? "Shift" : "") + event.key;
|
||||
const cmdOrCtrlOnly = Zotero.isMac
|
||||
? (event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey)
|
||||
: (event.ctrlKey && !event.shiftKey && !event.altKey);
|
||||
|
@ -1102,6 +1104,29 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
this.handleBlur = (event) => {
|
||||
// If one tabs through the item/context pane all the way to the end and
|
||||
// the focus leaves the pane, wrap it around to refocus the selected tab
|
||||
let itemPane = document.getElementById("zotero-item-pane");
|
||||
let contextPane = document.getElementById("zotero-context-pane");
|
||||
let loosingFocus = event.target;
|
||||
let receivingFocus = event.relatedTarget;
|
||||
let itemPaneLostFocus = itemPane.contains(loosingFocus) && !itemPane.contains(receivingFocus);
|
||||
let contextPaneLostFocus = contextPane.contains(loosingFocus) && !contextPane.contains(receivingFocus);
|
||||
// Do not do anything if the window lost focus or if the last
|
||||
// keypress was anything but a Tab. That way, it won't interfere with other navigation such as
|
||||
// Shift-tab from the header into the itemsView.
|
||||
if (Services.focus.activeWindow === window && this.lastKeyPress === "Tab"
|
||||
&& (itemPaneLostFocus || contextPaneLostFocus)) {
|
||||
if (receivingFocus) {
|
||||
Zotero_Tabs.moveFocus("current");
|
||||
}
|
||||
// event.relatedTarget is null when the reader is opened and we need a small
|
||||
// delay otherwise the focus lands within the reader
|
||||
else {
|
||||
setTimeout(() => Zotero_Tabs.moveFocus("current"));
|
||||
}
|
||||
this.lastKeyPress = null;
|
||||
}
|
||||
// When focus shifts, unless we are inside of a panel, save
|
||||
// the last focused element to be able to return focus to it when the panel closes
|
||||
if (!event.target.closest("panel")) {
|
||||
|
|
Loading…
Reference in a new issue