move logic into ItemTreeMenuBar class
- menupopup handling moved from Zotero.Utilities.Internal into ItemTreeMenuBar as static functions - menu to move columns renamed for "Move Column Back" and moved into the submenu of "Columns" - improved the logic of hiding menubar to not remove it if it is clicked while acgive - a few additional minor fixes
This commit is contained in:
parent
9b6a401afe
commit
0cd2c7a225
8 changed files with 161 additions and 153 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
|
||||
|
@ -70,8 +71,7 @@ Services.scriptloader.loadSubScript('chrome://zotero/content/elements/itemPaneSe
|
|||
['note-row', 'chrome://zotero/content/elements/noteRow.js'],
|
||||
['notes-context', 'chrome://zotero/content/elements/notesContext.js'],
|
||||
['libraries-collections-box', 'chrome://zotero/content/elements/librariesCollectionsBox.js'],
|
||||
['autocomplete-textarea', 'chrome://zotero/content/elements/autocompleteTextArea.js'],
|
||||
['item-tree-menu-bar', 'chrome://zotero/content/elements/itemTreeMenuBar.js'],
|
||||
['autocomplete-textarea', 'chrome://zotero/content/elements/autocompleteTextArea.js']
|
||||
]) {
|
||||
customElements.setElementCreationCallback(tag, () => {
|
||||
Services.scriptloader.loadSubScript(script, window);
|
||||
|
|
|
@ -23,85 +23,128 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
{
|
||||
class ItemTreeMenuBar extends XULElement {
|
||||
// Menu bar containing View options for manipulating the itemTree table
|
||||
// (View > Columns, Sort By, Move Column).
|
||||
// Should be added to non-main windows or dialogs containing an itemTree
|
||||
// to expose the functionality of table manipulation to keyboard users.
|
||||
// On Windows or Linux, this menubar appears on Alt keypress.
|
||||
constructor() {
|
||||
super();
|
||||
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>
|
||||
<menu id="column-move-submenu"
|
||||
class="menu-type-library"
|
||||
label="&moveColumn.label;">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menubar>
|
||||
`, ['chrome://zotero/locale/standalone.dtd']);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
connectedCallback() {
|
||||
this.append(document.importNode(this.content, true));
|
||||
this.hidden = true;
|
||||
menu.menupopup.replaceChildren();
|
||||
if (menu.id == "column-picker-submenu") {
|
||||
// View > Columns
|
||||
itemsView.buildColumnPickerMenu(menu.menupopup);
|
||||
}
|
||||
|
||||
init(itemTree) {
|
||||
Zotero.Utilities.Internal.setItemTreeSortKeys(window, itemTree);
|
||||
for (let menu of [...this.querySelectorAll(".menu-type-library")]) {
|
||||
menu.addEventListener("popupshowing", (event) => {
|
||||
Zotero.Utilities.Internal.handleItemTreeMenuShowing(event, menu.id, 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 when it is no longer active
|
||||
document.addEventListener("DOMMenuBarInactive", (_) => {
|
||||
this.hidden = true;
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("item-tree-menu-bar", ItemTreeMenuBar);
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -54,8 +54,7 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
// 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");
|
||||
let win = document.querySelector("window");
|
||||
win.insertBefore(itemTreeMenuBar, win.firstChild);
|
||||
document.documentElement.prepend(itemTreeMenuBar);
|
||||
}
|
||||
await new Promise((resolve) => {
|
||||
ReactDOM.createRoot(domEl).render(<ItemTree ref={(c) => {
|
||||
|
@ -2670,6 +2669,43 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
menuitem.setAttribute('anonid', prefix + 'restore-order');
|
||||
menuitem.addEventListener('command', () => this.tree._columns.restoreDefaultOrder());
|
||||
menupopup.appendChild(menuitem);
|
||||
|
||||
|
||||
sep = document.createXULElement('menuseparator');
|
||||
menupopup.appendChild(sep);
|
||||
|
||||
//
|
||||
// Move Column Back
|
||||
//
|
||||
let moveColumnMenu = document.createXULElement('menu');
|
||||
moveColumnMenu.setAttribute('label', Zotero.getString('zotero.items.moveColumn.label'));
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
buildSortMenu(menupopup) {
|
||||
|
@ -2687,25 +2723,6 @@ var ItemTree = class ItemTree extends LibraryTree {
|
|||
});
|
||||
}
|
||||
|
||||
buildColumnMoverMenu(menupopup) {
|
||||
let columns = this._getColumns();
|
||||
let menuitem;
|
||||
for (let i = 0; i < columns.length; i++) {
|
||||
let column = columns[i];
|
||||
if (column.hidden) continue;
|
||||
let label = formatColumnName(column);
|
||||
menuitem = document.createXULElement('menuitem');
|
||||
menuitem.setAttribute('label', label);
|
||||
menuitem.setAttribute('colindex', i);
|
||||
// swap the column with its next nearest visible column
|
||||
menuitem.addEventListener('command', () => {
|
||||
let nextIndex = columns.findIndex((col, index) => index > i && !col.hidden);
|
||||
this.tree._columns.setOrder(i, nextIndex + 1);
|
||||
});
|
||||
menupopup.appendChild(menuitem);
|
||||
}
|
||||
}
|
||||
|
||||
toggleSort(sortIndex, countVisible = false) {
|
||||
if (countVisible) {
|
||||
let cols = this._getColumns();
|
||||
|
|
|
@ -1701,52 +1701,6 @@ Zotero.Utilities.Internal = {
|
|||
return menu;
|
||||
},
|
||||
|
||||
// Show View > Columns, Sort By and Move Column menus for windows that have an itemTree
|
||||
handleItemTreeMenuShowing: function (event, menuID, itemsView) {
|
||||
let document = event.target.ownerDocument;
|
||||
let menuPopup = document.getElementById(menuID).menupopup;
|
||||
if (event.target !== menuPopup) {
|
||||
return;
|
||||
}
|
||||
menuPopup.replaceChildren();
|
||||
if (menuID == "column-picker-submenu") {
|
||||
// View > Columns
|
||||
itemsView?.buildColumnPickerMenu(menuPopup);
|
||||
}
|
||||
else if (menuID == "sort-submenu") {
|
||||
// View > Sort By
|
||||
itemsView?.buildSortMenu(menuPopup);
|
||||
for (let i = 0; i < 10; i++) {
|
||||
if (!menuPopup.children[i]) {
|
||||
break;
|
||||
}
|
||||
menuPopup.children[i].setAttribute('key', 'key_sortCol' + i);
|
||||
}
|
||||
}
|
||||
else if (menuID == "column-move-submenu") {
|
||||
// View > Move Column
|
||||
itemsView?.buildColumnMoverMenu(menuPopup);
|
||||
}
|
||||
},
|
||||
|
||||
// Set the access keys for menuitems to sort the itemTree
|
||||
setItemTreeSortKeys(window, itemsView, condition) {
|
||||
let sortSubmenuKeys = window.document.getElementById('sortSubmenuKeys');
|
||||
if (!condition) {
|
||||
condition = () => true;
|
||||
}
|
||||
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 (condition()) {
|
||||
itemsView.toggleSort(i, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
openPreferences: function (paneID, options = {}) {
|
||||
if (typeof options == 'string') {
|
||||
throw new Error("openPreferences() now takes an 'options' object -- update your code");
|
||||
|
|
|
@ -1655,7 +1655,7 @@ var ZoteroPane = new function()
|
|||
ZoteroPane.itemsView.onRefresh.addListener(() => ZoteroPane.setTagScope());
|
||||
ZoteroPane.itemsView.waitForLoad().then(() => Zotero.uiIsReady());
|
||||
|
||||
Zotero.Utilities.Internal.setItemTreeSortKeys(window, ZoteroPane.itemsView, () => Zotero_Tabs.selectedType === 'library');
|
||||
ItemTreeMenuBar.setItemTreeSortKeys(ZoteroPane.itemsView);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
|
|
@ -645,19 +645,13 @@
|
|||
<menu id="column-picker-submenu"
|
||||
class="menu-type-library"
|
||||
label="&columns.label;"
|
||||
onpopupshowing="Zotero.Utilities.Internal.handleItemTreeMenuShowing(event, 'column-picker-submenu', ZoteroPane.itemsView)">
|
||||
onpopupshowing="ItemTreeMenuBar.handleItemTreeMenuShowing(event, this, ZoteroPane.itemsView)">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
<menu id="sort-submenu"
|
||||
class="menu-type-library"
|
||||
label="&sortBy.label;"
|
||||
onpopupshowing="Zotero.Utilities.Internal.handleItemTreeMenuShowing(event, 'sort-submenu', ZoteroPane.itemsView)">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
<menu id="column-move-submenu"
|
||||
class="menu-type-library"
|
||||
label="&moveColumn.label;"
|
||||
onpopupshowing="Zotero.Utilities.Internal.handleItemTreeMenuShowing(event, 'column-move-submenu', ZoteroPane.itemsView)">
|
||||
onpopupshowing="ItemTreeMenuBar.handleItemTreeMenuShowing(event, this, ZoteroPane.itemsView)">
|
||||
<menupopup/>
|
||||
</menu>
|
||||
<menuseparator class="menu-type-library"/>
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
<!ENTITY noteFontSize.label "Note Font Size">
|
||||
<!ENTITY columns.label "Columns">
|
||||
<!ENTITY sortBy.label "Sort By">
|
||||
<!ENTITY moveColumn.label "Move Column">
|
||||
|
||||
<!--TOOLS MENU-->
|
||||
<!ENTITY toolsMenu.label "Tools">
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
<!ENTITY zotero.items.dateModified_column "Date Modified">
|
||||
<!ENTITY zotero.items.moreColumns.label "More Columns">
|
||||
<!ENTITY zotero.items.restoreColumnOrder.label "Restore Column Order">
|
||||
<!ENTITY zotero.items.moveColumn.label "Move Column Back">
|
||||
|
||||
<!ENTITY zotero.items.menu.showInLibrary "Show in Library">
|
||||
<!ENTITY zotero.items.menu.attach.note "Add Note">
|
||||
|
|
Loading…
Reference in a new issue