Skip to content

Commit e74b2bf

Browse files
committed
add: menu in reader
1 parent d4fb0fc commit e74b2bf

File tree

5 files changed

+109
-27
lines changed

5 files changed

+109
-27
lines changed
-836 Bytes
Binary file not shown.

src/hooks.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async function onStartup() {
3232

3333
await addon.api.actionManager.dispatchActionByEvent(
3434
ActionEventTypes.programStartup,
35-
{},
35+
{}
3636
);
3737

3838
initReaderShortcuts();
@@ -42,12 +42,12 @@ async function onStartup() {
4242

4343
async function onMainWindowLoad(win: Window): Promise<void> {
4444
initWindowShortcuts(win);
45-
initMenu();
45+
initMenu(win);
4646
await addon.api.actionManager.dispatchActionByEvent(
4747
ActionEventTypes.mainWindowLoad,
4848
{
4949
window: win,
50-
},
50+
}
5151
);
5252
}
5353

@@ -57,7 +57,7 @@ async function onMainWindowUnload(win: Window): Promise<void> {
5757
ActionEventTypes.mainWindowUnload,
5858
{
5959
window: win,
60-
},
60+
}
6161
);
6262
}
6363

@@ -88,7 +88,7 @@ async function onPrefsEvent(type: string, data: { [key: string]: any }) {
8888
async function onMenuEvent(type: "showing", data: { [key: string]: any }) {
8989
switch (type) {
9090
case "showing":
91-
buildItemMenu(data.window);
91+
buildItemMenu(data.window, data.target);
9292
break;
9393
default:
9494
return;

src/modules/menu.ts

+81-6
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ import { config } from "../../package.json";
33
import { getString } from "../utils/locale";
44
import { getPref } from "../utils/prefs";
55
import { ActionData } from "../utils/actions";
6+
import { getCurrentItems } from "../utils/items";
67

78
export { initMenu, buildItemMenu };
89

9-
function initMenu() {
10+
function initMenu(win: Window) {
1011
ztoolkit.Menu.register("item", {
1112
tag: "menu",
12-
popupId: `${config.addonRef}-itemPopup`,
13+
popupId: `${config.addonRef}-item-popup`,
1314
label: getString("menupopup-label"),
1415
icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
15-
onpopupshowing: `Zotero.${config.addonInstance}.hooks.onMenuEvent("showing", { window })`,
16+
onpopupshowing: `Zotero.${config.addonInstance}.hooks.onMenuEvent("showing", { window, target: "item" })`,
1617
children: [
1718
{
1819
tag: "menuitem",
@@ -21,12 +22,86 @@ function initMenu() {
2122
},
2223
],
2324
});
25+
26+
ztoolkit.UI.appendElement(
27+
{
28+
tag: "menupopup",
29+
id: `${config.addonRef}-reader-popup`,
30+
listeners: [
31+
{
32+
type: "popupshowing",
33+
listener: (ev) => {
34+
addon.hooks.onMenuEvent("showing", { window, target: "reader" });
35+
},
36+
},
37+
],
38+
},
39+
win.document.querySelector("popupset")!
40+
);
41+
const image =
42+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsSAAALEgHS3X78AAAA40lEQVRYCWP8//8/AyFwJL/hjsbXJ8oEFSKBG9wyd20mNqgQUsdESMGCypkppFoOAiA924s711PsAOmfb2NItRwGWP7/FaTYAbQGow4YdcCoA0YdMOqAUQcMuANYCCm4yS394AWboD05hn9k5XrgSqkDjgloPiDHcih4kENAwWgaGHXAqAModcBFKB4QB4AsdoBish1BrgPAli8rNvsAwpQ4ghwHLIRZDhNAcsRCUg0jWBSjW76s2CwBmwTUEQlRvadA3HhiDSQlBHBajuYQkBqiQ4JYBxQSYzmaIwoJKmRgYAAAgCNBYXH3oBUAAAAASUVORK5CYII=";
43+
const readerButtonCSS = `
44+
.actions-tags-reader-menu::before {
45+
background-image: url(${image});
46+
background-size: 100%;
47+
content: "";
48+
display: inline-block;
49+
height: 16px;
50+
vertical-align: top;
51+
width: 16px;
52+
}`;
53+
Zotero.Reader.registerEventListener("renderToolbar", (event) => {
54+
const { append, doc } = event;
55+
append(
56+
ztoolkit.UI.createElement(doc, "button", {
57+
namespace: "html",
58+
classList: ["toolbarButton", "actions-tags-reader-menu"],
59+
properties: {
60+
tabIndex: -1,
61+
title: "Actions",
62+
},
63+
listeners: [
64+
{
65+
type: "click",
66+
listener: (ev: Event) => {
67+
const _ev = ev as MouseEvent;
68+
const target = ev.target as HTMLElement;
69+
const elemRect = target.getBoundingClientRect();
70+
71+
const x = _ev.screenX - _ev.offsetX;
72+
const y =
73+
_ev.screenY - _ev.offsetY + elemRect.bottom - elemRect.top;
74+
75+
win.document
76+
.querySelector(`#${config.addonRef}-reader-popup`)
77+
// @ts-ignore XUL.MenuPopup
78+
?.openPopupAtScreen(x + 1, y + 1, true);
79+
},
80+
},
81+
],
82+
children: [
83+
{
84+
tag: "span",
85+
classList: ["button-background"],
86+
},
87+
],
88+
})
89+
);
90+
append(
91+
ztoolkit.UI.createElement(doc, "style", {
92+
id: `${config.addonRef}-reader-button`,
93+
properties: {
94+
textContent: readerButtonCSS,
95+
},
96+
})
97+
);
98+
});
2499
}
25100

26-
function buildItemMenu(win: Window) {
101+
function buildItemMenu(win: Window, target: "item" | "reader") {
27102
const doc = win.document;
28103
const popup = doc.querySelector(
29-
`#${config.addonRef}-itemPopup`
104+
`#${config.addonRef}-${target}-popup`
30105
) as XUL.MenuPopup;
31106
// Remove all children in popup
32107
while (popup.firstChild) {
@@ -93,7 +168,7 @@ function getActionsByMenu() {
93168
}
94169

95170
async function triggerMenuCommand(key: string) {
96-
const items = Zotero.getActiveZoteroPane().getSelectedItems();
171+
const items = getCurrentItems();
97172
// Trigger action for all items
98173
await addon.api.actionManager.dispatchActionByKey(key, {
99174
itemIDs: items.map((item) => item.id),

src/modules/shortcuts.ts

+4-16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getCurrentItems } from "../utils/items";
12
import { KeyModifier } from "../utils/shorcut";
23
import { waitUntil } from "../utils/wait";
34

@@ -19,8 +20,8 @@ function initReaderShortcuts() {
1920
() => (reader._internalReader?._primaryView as any)?._iframeWindow,
2021
() =>
2122
_initShortcuts(
22-
(reader._internalReader._primaryView as any)?._iframeWindow,
23-
),
23+
(reader._internalReader._primaryView as any)?._iframeWindow
24+
)
2425
);
2526
});
2627
}
@@ -62,20 +63,7 @@ async function triggerShortcut(e: KeyboardEvent) {
6263
const shortcut = new KeyModifier(addon.data.shortcut.getRaw());
6364
addon.data.shortcut = undefined;
6465

65-
let items = [] as Zotero.Item[];
66-
switch (Zotero_Tabs.selectedType) {
67-
case "library": {
68-
items = Zotero.getActiveZoteroPane().getSelectedItems();
69-
break;
70-
}
71-
case "reader": {
72-
const reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
73-
if (reader) {
74-
items = [reader._item];
75-
}
76-
break;
77-
}
78-
}
66+
const items = getCurrentItems();
7967
// Trigger action for multiple items
8068
await addon.api.actionManager.dispatchActionByShortcut(shortcut, {
8169
itemIDs: items.map((item) => item?.id),

src/utils/items.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export { getCurrentItems };
2+
3+
function getCurrentItems() {
4+
let items = [] as Zotero.Item[];
5+
switch (Zotero_Tabs.selectedType) {
6+
case "library": {
7+
items = Zotero.getActiveZoteroPane().getSelectedItems();
8+
break;
9+
}
10+
case "reader": {
11+
const reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
12+
if (reader) {
13+
items = [reader._item];
14+
}
15+
break;
16+
}
17+
}
18+
return items;
19+
}

0 commit comments

Comments
 (0)