vpat 17: itemTree view menu for non-main windows (#4433)
- adds View > Columns and View > Sort By menu options to all windows that contains an itemTree (Select Items dialog, Advanced Search, classic Add Citation, Edit Bibliography dialog). - the menubar is global on macOS. On Windows/Linux it is displayed and focused on Alt keypress - added menu option to move a selected column left, which we need as an alternative for drag-drop reordering that would not require using a mouse
This commit is contained in:
parent
504ec7eb4a
commit
8e87aa15e7
6 changed files with 203 additions and 37 deletions
|
@ -29,6 +29,7 @@ Services.scriptloader.loadSubScript("chrome://zotero/content/include.js", this);
|
|||
Services.scriptloader.loadSubScript("chrome://global/content/customElements.js", this);
|
||||
Services.scriptloader.loadSubScript("chrome://zotero/content/elements/base.js", this);
|
||||
Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemPaneSection.js', this);
|
||||
Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemTreeMenuBar.js', this);
|
||||
|
||||
{
|
||||
// https://searchfox.org/mozilla-central/rev/8e885f04a0a4ff6d64ea59741c10d9b8e45d9ff8/toolkit/content/customElements.js#826-832
|
||||
|
|
150
chrome/content/zotero/elements/itemTreeMenuBar.js
Normal file
150
chrome/content/zotero/elements/itemTreeMenuBar.js
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright © 2022 Corporation for Digital Scholarship
|
||||
Vienna, Virginia, USA
|
||||
https://www.zotero.org
|
||||
|
||||
This file is part of Zotero.
|
||||
|
||||
Zotero is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Zotero is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
|
||||
class ItemTreeMenuBar extends XULElement {
|
||||
// Menu bar containing View options for manipulating the itemTree table
|
||||
// (View > Columns, Sort By, Move Column).
|
||||
// Added to windows without a menubar by ItemTree.init()
|
||||
// to expose the functionality of table manipulation to keyboard users.
|
||||
// On Windows or Linux, this menubar appears on Alt keypress.
|
||||
constructor() {
|
||||
super();
|
||||
this._inactiveTimeout = null;
|
||||
|
||||
this.content = MozXULElement.parseXULToFragment(`
|
||||
<keyset id="sortSubmenuKeys">
|
||||
<key id="key_sortCol0"/>
|
||||
<key id="key_sortCol1"/>
|
||||
<key id="key_sortCol2"/>
|
||||
<key id="key_sortCol3"/>
|
||||
<key id="key_sortCol4"/>
|
||||
<key id="key_sortCol5"/>
|
||||
<key id="key_sortCol6"/>
|
||||
<key id="key_sortCol7"/>
|
||||
<key id="key_sortCol8"/>
|
||||
<key id="key_sortCol9"/>
|
||||
</keyset>
|
||||
<menubar id="main-menubar">
|
||||
<menu id="view-menu"
|
||||
label="&viewMenu.label;"
|
||||
accesskey="&viewMenu.accesskey;">
|
||||
<menupopup id="menu_viewPopup">
|
||||
<menu id="column-picker-submenu"
|
||||
class="menu-type-library"
|
||||
label="&columns.label;">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
<menu id="sort-submenu"
|
||||
class="menu-type-library"
|
||||
label="&sortBy.label;">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menubar>
|
||||
`, ['chrome://zotero/locale/standalone.dtd']);
|
||||
}
|
||||
|
||||
|
||||
connectedCallback() {
|
||||
this.append(document.importNode(this.content, true));
|
||||
this.hidden = true;
|
||||
}
|
||||
|
||||
// Show View > Columns, Sort By menus for windows that have an itemTree
|
||||
static handleItemTreeMenuShowing(event, menu, itemsView) {
|
||||
if (event.target !== menu.menupopup) {
|
||||
return;
|
||||
}
|
||||
menu.menupopup.replaceChildren();
|
||||
if (menu.id == "column-picker-submenu") {
|
||||
// View > Columns
|
||||
itemsView.buildColumnPickerMenu(menu.menupopup);
|
||||
}
|
||||
else if (menu.id == "sort-submenu") {
|
||||
// View > Sort By
|
||||
itemsView.buildSortMenu(menu.menupopup);
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (!menu.menupopup.children[i]) {
|
||||
break;
|
||||
}
|
||||
menu.menupopup.children[i].setAttribute('key', 'key_sortCol' + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the access keys for menuitems to sort the itemTree
|
||||
static setItemTreeSortKeys(itemsView) {
|
||||
let sortSubmenuKeys = document.getElementById('sortSubmenuKeys');
|
||||
for (let i = 0; i < 10; i++) {
|
||||
let key = sortSubmenuKeys.children[i];
|
||||
key.setAttribute('modifiers', Zotero.isMac ? 'accel alt control' : 'alt');
|
||||
key.setAttribute('key', (i + 1) % 10);
|
||||
key.addEventListener('command', () => {
|
||||
if (!window.Zotero_Tabs || window.Zotero_Tabs.selectedType == 'library') {
|
||||
itemsView.toggleSort(i, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
init(itemTree) {
|
||||
this.constructor.setItemTreeSortKeys(itemTree);
|
||||
for (let menu of [...this.querySelectorAll(".menu-type-library")]) {
|
||||
menu.addEventListener("popupshowing", (event) => {
|
||||
this.constructor.handleItemTreeMenuShowing(event, menu, itemTree);
|
||||
});
|
||||
}
|
||||
if (!Zotero.isMac) {
|
||||
// On Windows and Linux, display and focus menubar on Alt keypress
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key == "Alt") {
|
||||
this.hidden = !this.hidden;
|
||||
document.getElementById("main-menubar").focus();
|
||||
}
|
||||
}, true);
|
||||
// Hide menubar on click or tab away. If a selected menu is clicked, it will
|
||||
// fire DOMMenuBarInactive event first followed by DOMMenuBarActive.
|
||||
// Listen to both events and hide inactive menu after delay if it is not cancelled.
|
||||
// https://searchfox.org/mozilla-central/source/browser/base/content/browser-customization.js#165
|
||||
document.addEventListener("DOMMenuBarInactive", (_) => {
|
||||
this._inactiveTimeout = setTimeout(() => {
|
||||
this._inactiveTimeout = null;
|
||||
this.hidden = true;
|
||||
});
|
||||
});
|
||||
document.addEventListener("DOMMenuBarActive", (_) => {
|
||||
if (this._inactiveTimeout) {
|
||||
clearTimeout(this._inactiveTimeout);
|
||||
this._inactiveTimeout = null;
|
||||
}
|
||||
this.hidden = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("item-tree-menu-bar", ItemTreeMenuBar);
|
|
@ -59,6 +59,12 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
Zotero.debug(`Initializing React ItemTree ${opts.id}`);
|
||||
var ref;
|
||||
opts.domEl = domEl;
|
||||
let itemTreeMenuBar = null;
|
||||
// Add a menubar with View options to manipulate the table (only if a menubar doesn't already exist in .xhtml)
|
||||
if (!document.querySelector("menubar")) {
|
||||
itemTreeMenuBar = document.createXULElement("item-tree-menu-bar");
|
||||
document.documentElement.prepend(itemTreeMenuBar);
|
||||
}
|
||||
await new Promise((resolve) => {
|
||||
ReactDOM.createRoot(domEl).render(<ItemTree ref={(c) => {
|
||||
ref = c;
|
||||
|
@ -66,6 +72,9 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
} } {...opts} />);
|
||||
});
|
||||
|
||||
if (itemTreeMenuBar) {
|
||||
itemTreeMenuBar.init(ref);
|
||||
}
|
||||
Zotero.debug(`React ItemTree ${opts.id} initialized`);
|
||||
return ref;
|
||||
}
|
||||
|
@ -2666,6 +2675,41 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
// sep.setAttribute('anonid', prefix + 'sep');
|
||||
menupopup.appendChild(sep);
|
||||
|
||||
//
|
||||
// Move Column Left
|
||||
//
|
||||
let moveColumnMenu = document.createXULElement('menu');
|
||||
document.l10n.setAttributes(
|
||||
moveColumnMenu,
|
||||
Zotero.rtl ? 'menu-view-columns-move-right' : 'menu-view-columns-move-left'
|
||||
);
|
||||
moveColumnMenu.setAttribute('anonid', prefix + 'move-column');
|
||||
let moveColumnPopup = document.createXULElement('menupopup');
|
||||
moveColumnPopup.setAttribute('anonid', prefix + 'move-column-popup');
|
||||
moveColumnMenu.appendChild(moveColumnPopup);
|
||||
menupopup.appendChild(moveColumnMenu);
|
||||
|
||||
let firstColumn = true;
|
||||
// Only list visible columns
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
let column = columns[i];
|
||||
if (column.hidden) continue;
|
||||
// Skip first column (since there is nowhere to move it)
|
||||
if (firstColumn) {
|
||||
firstColumn = false;
|
||||
continue;
|
||||
}
|
||||
let label = formatColumnName(column);
|
||||
let menuitem = document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', label);
|
||||
menuitem.setAttribute('colindex', i);
|
||||
// Swap the column with its previous visible neighbor
|
||||
menuitem.addEventListener('command', () => {
|
||||
let previousIndex = columns.findLastIndex((col, index) => index < i && !col.hidden);
|
||||
this.tree._columns.setOrder(i, previousIndex);
|
||||
});
|
||||
moveColumnPopup.appendChild(menuitem);
|
||||
}
|
||||
//
|
||||
// Restore Default Column Order
|
||||
//
|
||||
|
|
|
@ -1655,17 +1655,7 @@ var ZoteroPane = new function()
|
|||
ZoteroPane.itemsView.onRefresh.addListener(() => ZoteroPane.setTagScope());
|
||||
ZoteroPane.itemsView.waitForLoad().then(() => Zotero.uiIsReady());
|
||||
|
||||
let sortSubmenuKeys = document.getElementById('sortSubmenuKeys');
|
||||
for (let i = 0; i < 10; i++) {
|
||||
let key = sortSubmenuKeys.children[i];
|
||||
key.setAttribute('modifiers', Zotero.isMac ? 'accel alt control' : 'alt');
|
||||
key.setAttribute('key', (i + 1) % 10);
|
||||
key.addEventListener('command', () => {
|
||||
if (Zotero_Tabs.selectedType === 'library') {
|
||||
ZoteroPane.itemsView.toggleSort(i, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
ItemTreeMenuBar.setItemTreeSortKeys(ZoteroPane.itemsView);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
@ -6745,30 +6735,6 @@ var ZoteroPane = new function()
|
|||
this.itemPane.handleResize();
|
||||
}
|
||||
|
||||
this.onColumnPickerPopupShowing = function (event) {
|
||||
let menuPopup = document.getElementById('column-picker-submenu').menupopup;
|
||||
if (event.target !== menuPopup) {
|
||||
return;
|
||||
}
|
||||
menuPopup.replaceChildren();
|
||||
this.itemsView?.buildColumnPickerMenu(menuPopup);
|
||||
};
|
||||
|
||||
this.onSortPopupShowing = function (event) {
|
||||
let menuPopup = document.getElementById('sort-submenu').menupopup;
|
||||
if (event.target !== menuPopup) {
|
||||
return;
|
||||
}
|
||||
menuPopup.replaceChildren();
|
||||
this.itemsView?.buildSortMenu(menuPopup);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (!menuPopup.children[i]) {
|
||||
break;
|
||||
}
|
||||
menuPopup.children[i].setAttribute('key', 'key_sortCol' + i);
|
||||
}
|
||||
};
|
||||
|
||||
// Set the label of the dynamic tooltip. Can be used when we cannot set .tooltiptext
|
||||
// property, e.g. if we don't want the tooltip to be announced by screenreaders.
|
||||
|
|
|
@ -645,13 +645,13 @@
|
|||
<menu id="column-picker-submenu"
|
||||
class="menu-type-library"
|
||||
label="&columns.label;"
|
||||
onpopupshowing="ZoteroPane_Local.onColumnPickerPopupShowing(event)">
|
||||
onpopupshowing="ItemTreeMenuBar.handleItemTreeMenuShowing(event, this, ZoteroPane.itemsView)">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
<menu id="sort-submenu"
|
||||
class="menu-type-library"
|
||||
label="&sortBy.label;"
|
||||
onpopupshowing="ZoteroPane_Local.onSortPopupShowing(event)">
|
||||
onpopupshowing="ItemTreeMenuBar.handleItemTreeMenuShowing(event, this, ZoteroPane.itemsView)">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
<menuseparator class="menu-type-library"/>
|
||||
|
|
|
@ -75,6 +75,11 @@ menu-deletePermanently =
|
|||
menu-tools-plugins =
|
||||
.label = Plugins
|
||||
|
||||
menu-view-columns-move-left =
|
||||
.label = Move Column Left
|
||||
menu-view-columns-move-right =
|
||||
.label = Move Column Right
|
||||
|
||||
main-window-command =
|
||||
.label = { -app-name }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue