diff --git a/README.md b/README.md
index c713556..f6cfbea 100644
--- a/README.md
+++ b/README.md
@@ -164,6 +164,7 @@ An action has the following settings:
- Collection Menu
+ - Tools Menu
- Reader Menu
- Annotation Menu
diff --git a/addon/locale/en-US/addon.ftl b/addon/locale/en-US/addon.ftl
index 7b863ac..cbe8cc9 100644
--- a/addon/locale/en-US/addon.ftl
+++ b/addon/locale/en-US/addon.ftl
@@ -9,6 +9,7 @@ prefs-action-enabled = Enabled
prefs-action-menu = Menu Label
prefs-action-showInMenuItem = In Item Menu
prefs-action-showInMenuCollection = In Collection Menu
+prefs-action-showInMenuTools = In Tools Menu
prefs-action-showInMenuReader = In Reader Menu
prefs-action-showInMenuReaderAnnotation = In Annotation Menu
diff --git a/addon/locale/zh-CN/addon.ftl b/addon/locale/zh-CN/addon.ftl
index b833a32..c5b9f15 100644
--- a/addon/locale/zh-CN/addon.ftl
+++ b/addon/locale/zh-CN/addon.ftl
@@ -9,6 +9,7 @@ prefs-action-enabled = 启用
prefs-action-menu = 菜单项
prefs-action-showInMenuItem = 条目菜单中
prefs-action-showInMenuCollection = 分类菜单中
+prefs-action-showInMenuTools = 工具菜单中
prefs-action-showInMenuReader = 阅读器菜单中
prefs-action-showInMenuReaderAnnotation = 注释菜单中
diff --git a/src/modules/edit.ts b/src/modules/edit.ts
index e105cce..4f1dded 100644
--- a/src/modules/edit.ts
+++ b/src/modules/edit.ts
@@ -24,6 +24,7 @@ async function editAction(currentKey?: string) {
`[${getString("prefs-action-edit-shortcut-empty")}]`;
dialogData.showInMenuItem = !(action.showInMenu?.item === false);
dialogData.showInMenuCollection = !(action.showInMenu?.collection === false);
+ dialogData.showInMenuTools = !(action.showInMenu?.tools === false);
dialogData.showInMenuReader = !(action.showInMenu?.reader === false);
dialogData.showInMenuReaderAnnotation = !(
action.showInMenu?.readerAnnotation === false
@@ -144,7 +145,7 @@ async function editAction(currentKey?: string) {
const content = await openEditorWindow(dialogData.data);
(
dialog.window.document.querySelector(
- "#data-input",
+ "#data-input"
) as HTMLTextAreaElement
).value = content;
dialogData.data = content;
@@ -178,7 +179,7 @@ async function editAction(currentKey?: string) {
const key = ev.target as HTMLElement;
const win = dialog.window;
key.textContent = `[${getString(
- "prefs-action-edit-shortcut-placeholder",
+ "prefs-action-edit-shortcut-placeholder"
)}]`;
dialogData.shortcut = "";
const keyDownListener = (e: KeyboardEvent) => {
@@ -240,88 +241,30 @@ async function editAction(currentKey?: string) {
gridColumnEnd: "3",
},
},
- {
- tag: "label",
- namespace: "html",
- properties: {
- textContent: getString("prefs-action-showInMenuItem"),
- },
- },
- {
- tag: "input",
- properties: {
- type: "checkbox",
- },
- attributes: {
- "data-bind": "showInMenuItem",
- "data-prop": "checked",
- },
- styles: {
- width: "fit-content",
- },
- },
- {
- tag: "label",
- namespace: "html",
- properties: {
- textContent: getString("prefs-action-showInMenuCollection"),
- },
- },
- {
- tag: "input",
- properties: {
- type: "checkbox",
- },
- attributes: {
- "data-bind": "showInMenuCollection",
- "data-prop": "checked",
- },
- styles: {
- width: "fit-content",
- },
- },
- {
- tag: "label",
- namespace: "html",
- properties: {
- textContent: getString("prefs-action-showInMenuReader"),
- },
- },
- {
- tag: "input",
- properties: {
- type: "checkbox",
- },
- attributes: {
- "data-bind": "showInMenuReader",
- "data-prop": "checked",
- },
- styles: {
- width: "fit-content",
- },
- },
- {
- tag: "label",
- namespace: "html",
- properties: {
- textContent: getString(
- "prefs-action-showInMenuReaderAnnotation",
- ),
- },
- },
- {
- tag: "input",
- properties: {
- type: "checkbox",
- },
- attributes: {
- "data-bind": "showInMenuReaderAnnotation",
- "data-prop": "checked",
- },
- styles: {
- width: "fit-content",
- },
- },
+ ...["Item", "Collection", "Tools", "Reader", "ReaderAnnotation"]
+ .map((key) => [
+ {
+ tag: "label",
+ namespace: "html",
+ properties: {
+ textContent: getString(`prefs-action-showInMenu${key}`),
+ },
+ },
+ {
+ tag: "input",
+ properties: {
+ type: "checkbox",
+ },
+ attributes: {
+ "data-bind": `showInMenu${key}`,
+ "data-prop": "checked",
+ },
+ styles: {
+ width: "fit-content",
+ },
+ },
+ ])
+ .flat(),
],
},
{
@@ -380,11 +323,12 @@ async function editAction(currentKey?: string) {
showInMenu: {
item: dialogData.showInMenuItem,
collection: dialogData.showInMenuCollection,
+ tools: dialogData.showInMenuTools,
reader: dialogData.showInMenuReader,
readerAnnotation: dialogData.showInMenuReaderAnnotation,
},
},
- currentKey,
+ currentKey
);
edited = true;
}
@@ -408,7 +352,7 @@ async function openEditorWindow(content: string) {
const editorWin = addon.data.prefs.window?.openDialog(
"chrome://scaffold/content/monaco/monaco.html",
"monaco",
- "chrome,centerscreen,dialog=no,resizable,scrollbars=yes,width=800,height=600",
+ "chrome,centerscreen,dialog=no,resizable,scrollbars=yes,width=800,height=600"
) as
| (Window & {
loadMonaco: (options: Record) => Promise<{ editor: any }>;
@@ -419,7 +363,7 @@ async function openEditorWindow(content: string) {
}
await waitUtilAsync(() => !!editorWin.loadMonaco);
const isDark = addon.data.prefs.window?.matchMedia(
- "(prefers-color-scheme: dark)",
+ "(prefers-color-scheme: dark)"
).matches;
const { editor } = await editorWin.loadMonaco({
language: "javascript",
diff --git a/src/modules/menu.ts b/src/modules/menu.ts
index 6e43f70..7c973c0 100644
--- a/src/modules/menu.ts
+++ b/src/modules/menu.ts
@@ -43,6 +43,21 @@ function initItemMenu(win: Window) {
],
});
+ ztoolkit.Menu.register("menuTools", {
+ tag: "menu",
+ popupId: `${config.addonRef}-tools-popup`,
+ label: getString("menupopup-label"),
+ icon: `chrome://${config.addonRef}/content/icons/favicon.png`,
+ onpopupshowing: `Zotero.${config.addonInstance}.hooks.onMenuEvent("showing", { window, target: "tools" })`,
+ children: [
+ {
+ tag: "menuitem",
+ label: getString("menupopup-placeholder"),
+ disabled: true,
+ },
+ ],
+ });
+
ztoolkit.UI.appendElement(
{
tag: "menupopup",
@@ -56,7 +71,7 @@ function initItemMenu(win: Window) {
},
],
},
- win.document.querySelector("popupset")!,
+ win.document.querySelector("popupset")!
);
}
@@ -85,56 +100,55 @@ function initReaderMenu() {
z-index: 1;
}
`;
- Zotero.Reader.registerEventListener("renderToolbar", (event) => {
- const { append, doc } = event;
- append(
- ztoolkit.UI.createElement(doc, "button", {
- namespace: "html",
- classList: ["toolbarButton", "actions-tags-reader-menu"],
- properties: {
- tabIndex: -1,
- title: "Actions",
- },
- listeners: [
- {
- type: "click",
- listener: (ev: Event) => {
- const _ev = ev as MouseEvent;
- const target = ev.target as HTMLElement;
- const elemRect = target.getBoundingClientRect();
-
- const x = _ev.screenX - _ev.offsetX;
- const y =
- _ev.screenY - _ev.offsetY + elemRect.bottom - elemRect.top;
-
- document
- .querySelector(`#${config.addonRef}-reader-popup`)
- // @ts-ignore XUL.MenuPopup
- ?.openPopupAtScreen(x + 1, y + 1, true);
- },
- },
- ],
- children: [
- {
- tag: "span",
- classList: ["button-background"],
+ Zotero.Reader.registerEventListener(
+ "renderToolbar",
+ (event) => {
+ const { append, doc } = event;
+ append(
+ ztoolkit.UI.createElement(doc, "button", {
+ namespace: "html",
+ classList: ["toolbarButton", "actions-tags-reader-menu"],
+ properties: {
+ tabIndex: -1,
+ title: "Actions",
},
- {
- tag: "span",
- classList: ["dropmarker"],
+ listeners: [
+ {
+ type: "click",
+ listener: (ev: Event) => {
+ document
+ .querySelector(`#${config.addonRef}-reader-popup`)
+ // @ts-ignore XUL.MenuPopup
+ ?.openPopup(
+ doc.querySelector(".actions-tags-reader-menu"),
+ "after_start"
+ );
+ },
+ },
+ ],
+ children: [
+ {
+ tag: "span",
+ classList: ["button-background"],
+ },
+ {
+ tag: "span",
+ classList: ["dropmarker"],
+ },
+ ],
+ })
+ );
+ append(
+ ztoolkit.UI.createElement(doc, "style", {
+ id: `${config.addonRef}-reader-button`,
+ properties: {
+ textContent: readerButtonCSS,
},
- ],
- }),
- );
- append(
- ztoolkit.UI.createElement(doc, "style", {
- id: `${config.addonRef}-reader-button`,
- properties: {
- textContent: readerButtonCSS,
- },
- }),
- );
- });
+ })
+ );
+ },
+ config.addonID,
+ );
}
function initReaderAnnotationMenu() {
@@ -148,19 +162,23 @@ function initReaderAnnotationMenu() {
label: action.menu!,
onCommand: () => {
triggerMenuCommand(action.key, () =>
- getItemsByKey(reader._item.libraryID, ...params.ids),
+ getItemsByKey(reader._item.libraryID, ...params.ids)
);
},
});
}
},
+ config.addonID
);
}
-function buildItemMenu(win: Window, target: "item" | "collection" | "reader") {
+function buildItemMenu(
+ win: Window,
+ target: "item" | "collection" | "tools" | "reader"
+) {
const doc = win.document;
const popup = doc.querySelector(
- `#${config.addonRef}-${target}-popup`,
+ `#${config.addonRef}-${target}-popup`
) as XUL.MenuPopup;
// Remove all children in popup
while (popup?.firstChild) {
@@ -196,7 +214,7 @@ function buildItemMenu(win: Window, target: "item" | "collection" | "reader") {
triggerMenuCommand(
action.key,
() => getCurrentItems(target),
- target === "collection",
+ target === "collection"
);
},
},
@@ -217,7 +235,7 @@ function getActionsByMenu(target: ActionShowInMenu) {
action &&
action.menu &&
action.enabled &&
- (!action.showInMenu || action.showInMenu[target] !== false),
+ (!action.showInMenu || action.showInMenu[target] !== false)
)
.sort((x, y) => {
if (!x && !y) {
@@ -231,7 +249,7 @@ function getActionsByMenu(target: ActionShowInMenu) {
}
return ((x[sortBy] as string) || "").localeCompare(
(y[sortBy] || "") as string,
- Zotero.locale,
+ Zotero.locale
);
});
}
@@ -241,7 +259,7 @@ async function triggerMenuCommand(
getItems: () =>
| Zotero.DataObject[]
| Promise = getCurrentItems,
- withCollection: boolean = false,
+ withCollection: boolean = false
) {
const items = await getItems();
let collection: Zotero.Collection | undefined = undefined;
diff --git a/src/utils/actions.ts b/src/utils/actions.ts
index 1d3b916..735db26 100644
--- a/src/utils/actions.ts
+++ b/src/utils/actions.ts
@@ -46,7 +46,7 @@ enum ActionOperationTypes {
"triggerAction",
}
-type ActionShowInMenu = "item" | "collection" | "reader" | "readerAnnotation";
+type ActionShowInMenu = "item" | "collection" | "tools" | "reader" | "readerAnnotation";
interface ActionData {
event: ActionEventTypes;
@@ -95,6 +95,7 @@ const emptyAction: ActionData = {
showInMenu: {
item: false,
collection: false,
+ tools: false,
reader: false,
readerAnnotation: false,
},
diff --git a/src/utils/items.ts b/src/utils/items.ts
index 8dceae7..c2dfb3b 100644
--- a/src/utils/items.ts
+++ b/src/utils/items.ts
@@ -4,7 +4,7 @@ export { getCurrentItems, getItemsByKey };
async function getCurrentItems(type?: ActionShowInMenu) {
let items = [] as Zotero.Item[];
- if (!type) {
+ if (!type || type === "tools") {
type = getCurrentTargetType();
}
switch (type) {