Keep plugin focus route in toolbar order

This commit is contained in:
MinhHaDuong 2026-09-22 11:38:09 +02:00
parent 785e363390
commit f55d038913
2 changed files with 20 additions and 9 deletions

View file

@ -174,8 +174,8 @@ var ZoteroPane = new function () {
function setUpKeyboardNavigation() {
let collectionTreeToolbar = document.getElementById("zotero-toolbar-collection-tree");
let itemTreeToolbar = document.getElementById("zotero-toolbar-item-tree");
// Plugins append their toolbar buttons after Zotero's built-in controls.
// Read the current buttons for each key event so installation needs no registration.
// Plugins can opt into keyboard focus with tabindex=0 on an appended
// toolbarbutton. Read the current buttons for each key event.
let pluginButtons = () => [...document.querySelectorAll(
'#zotero-items-toolbar > toolbarbutton[tabindex="0"]'
)].filter(button => !button.disabled && !button.hidden
@ -408,7 +408,7 @@ var ZoteroPane = new function () {
ShiftTab: () => document.getElementById('zotero-tb-collections-search').click()
},
'zotero-tb-note-add': {
ArrowNext: () => pluginButtons()[0] || null,
ArrowNext: () => null,
ArrowPrevious: () => document.getElementById("zotero-tb-attachment-add"),
Tab: () => document.getElementById("zotero-tb-search").focus(),
ShiftTab: () => document.getElementById('zotero-tb-collections-search').click()
@ -438,8 +438,7 @@ var ZoteroPane = new function () {
if (pluginButtons().includes(event.target)) {
actionsMap[event.target.id] = {
ArrowNext: () => adjacentPluginButton(event.target, 1) || null,
ArrowPrevious: () => adjacentPluginButton(event.target, -1)
|| document.getElementById('zotero-tb-note-add'),
ArrowPrevious: () => adjacentPluginButton(event.target, -1) || null,
Tab: () => adjacentPluginButton(event.target, 1)
|| itemTree.querySelector(".virtualized-table"),
ShiftTab: () => adjacentPluginButton(event.target, -1)

View file

@ -1930,10 +1930,11 @@ describe("ZoteroPane", function () {
doc.activeElement.dispatchEvent(shiftTab);
assert.equal(doc.activeElement, buttons[0]);
doc.activeElement.dispatchEvent(shiftTab);
assert.include(
['zotero-tb-toggle-item-pane-stacked', 'zotero-tb-search-advanced-button'],
doc.activeElement.id
);
let toggleHidden = paneToggle.disabled || paneToggle.hidden
|| paneToggle.parentNode.hidden
|| win.getComputedStyle(paneToggle).display === 'none';
assert.equal(doc.activeElement.id, toggleHidden
? 'zotero-tb-search-advanced-button' : paneToggle.id);
doc.getElementById('zotero-tb-lookup').focus();
doc.activeElement.dispatchEvent(tab);
assert.equal(doc.activeElement.id, 'zotero-tb-search-textbox');
@ -1943,6 +1944,9 @@ describe("ZoteroPane", function () {
doc.getElementById('zotero-tb-note-add').focus();
doc.activeElement.dispatchEvent(rightArrow);
assert.equal(doc.activeElement.id, 'zotero-tb-note-add');
buttons[0].focus();
doc.activeElement.dispatchEvent(leftArrow);
assert.equal(doc.activeElement, buttons[0]);
doc.activeElement.dispatchEvent(rightArrow);
assert.equal(doc.activeElement, buttons[1]);
@ -1952,6 +1956,14 @@ describe("ZoteroPane", function () {
buttons[0].hidden = true;
paneToggle.dispatchEvent(tab);
assert.equal(doc.activeElement, buttons[1]);
buttons[0].hidden = false;
buttons[0].disabled = true;
paneToggle.dispatchEvent(tab);
assert.equal(doc.activeElement, buttons[1]);
buttons[0].disabled = false;
buttons[0].style.display = 'none';
paneToggle.dispatchEvent(tab);
assert.equal(doc.activeElement, buttons[1]);
}
finally {
buttons.forEach(button => button.remove());