diff --git a/addon/chrome/content/icons/section-16.svg b/addon/chrome/content/icons/section-16.svg
new file mode 100644
index 00000000..04cfc582
--- /dev/null
+++ b/addon/chrome/content/icons/section-16.svg
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/addon/chrome/content/icons/section-20.svg b/addon/chrome/content/icons/section-20.svg
new file mode 100644
index 00000000..fd0b0628
--- /dev/null
+++ b/addon/chrome/content/icons/section-20.svg
@@ -0,0 +1,15 @@
+
+
\ No newline at end of file
diff --git a/addon/chrome/content/icons/swap.svg b/addon/chrome/content/icons/swap.svg
new file mode 100644
index 00000000..dd83a128
--- /dev/null
+++ b/addon/chrome/content/icons/swap.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addon/locale/en-US/mainWindow.ftl b/addon/locale/en-US/mainWindow.ftl
new file mode 100644
index 00000000..097c86c9
--- /dev/null
+++ b/addon/locale/en-US/mainWindow.ftl
@@ -0,0 +1,4 @@
+itemPaneSection-header =
+ .label = Translate
+itemPaneSection-sidenav =
+ .tooltiptext = Translate
diff --git a/addon/locale/it-IT/mainWindow.ftl b/addon/locale/it-IT/mainWindow.ftl
new file mode 100644
index 00000000..097c86c9
--- /dev/null
+++ b/addon/locale/it-IT/mainWindow.ftl
@@ -0,0 +1,4 @@
+itemPaneSection-header =
+ .label = Translate
+itemPaneSection-sidenav =
+ .tooltiptext = Translate
diff --git a/addon/locale/zh-CN/mainWindow.ftl b/addon/locale/zh-CN/mainWindow.ftl
new file mode 100644
index 00000000..09956d6d
--- /dev/null
+++ b/addon/locale/zh-CN/mainWindow.ftl
@@ -0,0 +1,4 @@
+itemPaneSection-header =
+ .label = 翻译
+itemPaneSection-sidenav =
+ .tooltiptext = 翻译
diff --git a/addon/manifest.json b/addon/manifest.json
index 35b3d7d1..53ee0ea7 100644
--- a/addon/manifest.json
+++ b/addon/manifest.json
@@ -13,7 +13,7 @@
"zotero": {
"id": "__addonID__",
"update_url": "__updateURL__",
- "strict_min_version": "6.999",
+ "strict_min_version": "7.0.0-beta.70",
"strict_max_version": "7.0.*"
}
}
diff --git a/src/addon.ts b/src/addon.ts
index ef2b8d89..89c26ebf 100644
--- a/src/addon.ts
+++ b/src/addon.ts
@@ -18,7 +18,7 @@ class Addon {
};
panel: {
tabOptionId: string;
- activePanels: HTMLElement[];
+ activePanels: Record void>;
windowPanel: Window | null;
};
popup: {
@@ -47,7 +47,7 @@ class Addon {
ztoolkit: createZToolkit(),
locale: {},
prefs: { window: null },
- panel: { tabOptionId: "", activePanels: [], windowPanel: null },
+ panel: { tabOptionId: "", activePanels: {}, windowPanel: null },
popup: { currentPopup: null },
translate: {
selectedText: "",
diff --git a/src/hooks.ts b/src/hooks.ts
index d0f9f110..031d70d7 100644
--- a/src/hooks.ts
+++ b/src/hooks.ts
@@ -73,6 +73,11 @@ async function onMainWindowLoad(win: Window): Promise {
]);
// Create ztoolkit for every window
addon.data.ztoolkit = createZToolkit();
+
+ (win as any).MozXULElement.insertFTLIfNeeded(
+ `${config.addonRef}-mainWindow.ftl`,
+ );
+
registerReaderTabPanel();
registerPrefsWindow();
registerMenu();
@@ -87,6 +92,10 @@ async function onMainWindowLoad(win: Window): Promise {
async function onMainWindowUnload(win: Window): Promise {
ztoolkit.unregisterAll();
+
+ win.document
+ .querySelector(`[href="${config.addonRef}-mainWindow.ftl"]`)
+ ?.remove();
}
function onShutdown(): void {
diff --git a/src/modules/popup.ts b/src/modules/popup.ts
index 436c9e59..aeaee374 100644
--- a/src/modules/popup.ts
+++ b/src/modules/popup.ts
@@ -63,14 +63,22 @@ export function updateReaderPopup() {
audiobox,
);
}
- translateButton.hidden = task.status !== "waiting";
+ if (task.status !== "waiting") {
+ translateButton.style.display = "none";
+ } else {
+ translateButton.style.removeProperty("display");
+ }
textarea.hidden = hidePopupTextarea || task.status === "waiting";
textarea.value = task.result || task.raw;
textarea.style.fontSize = `${getPref("fontSize")}px`;
textarea.style.lineHeight = `${
Number(getPref("lineHeight")) * Number(getPref("fontSize"))
}px`;
- addToNoteButton.hidden = !ZoteroContextPane.getActiveEditor();
+ if (!ZoteroContextPane.activeEditor) {
+ addToNoteButton.style.display = "none";
+ } else {
+ addToNoteButton.style.removeProperty("display");
+ }
updatePopupSize(popup, textarea);
}
@@ -113,9 +121,14 @@ export function buildReaderPopup(
ignoreIfExists: true,
},
{
- tag: "div",
+ tag: "button",
+ namespace: "html",
id: makeId("translate"),
- classList: ["wide-button", `${config.addonRef}-readerpopup`],
+ classList: [
+ "toolbar-button",
+ "wide-button",
+ `${config.addonRef}-readerpopup`,
+ ],
properties: {
innerHTML: `${SVGIcon}${getString("readerpopup-translate-label")}`,
hidden: getPref("enableAuto"),
@@ -217,9 +230,17 @@ export function buildReaderPopup(
],
},
{
- tag: "div",
+ tag: "button",
+ namespace: "html",
id: makeId("addtonote"),
- classList: ["wide-button", `${config.addonRef}-readerpopup`],
+ classList: [
+ "toolbar-button",
+ "wide-button",
+ `${config.addonRef}-readerpopup`,
+ ],
+ styles: {
+ marginTop: "8px",
+ },
properties: {
innerHTML: `${SVGIcon}${Zotero.getString("pdfReader.addToNote")}`,
},
@@ -229,7 +250,7 @@ export function buildReaderPopup(
type: "click",
listener: async (ev) => {
const noteEditor =
- ZoteroContextPane && ZoteroContextPane.getActiveEditor();
+ ZoteroContextPane && ZoteroContextPane.activeEditor;
if (!noteEditor) {
return;
}
diff --git a/src/modules/tabpanel.ts b/src/modules/tabpanel.ts
index 2183ef4d..b55cefef 100644
--- a/src/modules/tabpanel.ts
+++ b/src/modules/tabpanel.ts
@@ -10,157 +10,82 @@ import {
} from "../utils/task";
export function registerReaderTabPanel() {
- ztoolkit.ReaderTabPanel.register(
- getString("readerpanel-label"),
- (
- panel: XUL.TabPanel | undefined,
- ownerDeck: XUL.Deck,
- ownerWindow: Window,
- readerInstance: _ZoteroTypes.ReaderInstance,
- ) => {
- if (ownerDeck.selectedPanel?.children[0].tagName === "vbox") {
- panel = createPanel(ownerDeck, readerInstance._instanceID);
- }
- panel && buildPanel(panel, readerInstance._instanceID);
+ Zotero.ItemPaneManager.registerSection({
+ paneID: "translate",
+ pluginID: config.addonID,
+ header: {
+ l10nID: `${config.addonRef}-itemPaneSection-header`,
+ icon: `chrome://${config.addonRef}/content/icons/section-16.svg`,
},
- {
- selectPanel: getPref("autoFocus") as boolean,
+ sidenav: {
+ l10nID: `${config.addonRef}-itemPaneSection-sidenav`,
+ icon: `chrome://${config.addonRef}/content/icons/section-20.svg`,
},
- ).then((tabId) => {
- addon.data.panel.tabOptionId = tabId;
- });
- new (ztoolkit.getGlobal("MutationObserver"))((_muts) => {
- updateTextAreasSize();
- }).observe(document.querySelector("#zotero-context-pane")!, {
- attributes: true,
- attributeFilter: ["width"],
+ onInit,
+ onDestroy,
+ onRender,
+ onItemChange,
});
- document
- .querySelector("#zotero-context-pane")
- ?.querySelector("grippy")
- ?.addEventListener("click", (ev) => {
- updateTextAreasSize();
- });
- updateTextAreasSize(true);
}
async function openWindowPanel() {
- if (addon.data.panel.windowPanel && !addon.data.panel.windowPanel.closed) {
- addon.data.panel.windowPanel.close();
- }
- const dialogData = {
- loadLock: Zotero.Promise.defer(),
- };
- const win: Window = ztoolkit.getGlobal("openDialog")(
- `chrome://${config.addonRef}/content/standalone.xhtml`,
- `${config.addonRef}-standalone`,
- `chrome,extrachrome,menubar,resizable=yes,scrollbars,status,dialog=no,${
- getPref("keepWindowTop") ? ",alwaysRaised=yes" : ""
- }`,
- dialogData,
- );
- await dialogData.loadLock.promise;
- buildPanel(
- win.document.querySelector("#panel-container") as XUL.Box,
- "standalone",
- );
- win.addEventListener("resize", (ev) => {
- updateTextAreaSize(win.document);
- });
- buildExtraPanel(win.document.querySelector("#extra-container") as XUL.Box);
- updateTextAreaSize(win.document);
- addon.data.panel.windowPanel = win;
+ window.alert("Not implemented yet, please wait for the next update.");
+ return;
+ // if (addon.data.panel.windowPanel && !addon.data.panel.windowPanel.closed) {
+ // addon.data.panel.windowPanel.close();
+ // }
+ // const dialogData = {
+ // loadLock: Zotero.Promise.defer(),
+ // };
+ // const win: Window = ztoolkit.getGlobal("openDialog")(
+ // `chrome://${config.addonRef}/content/standalone.xhtml`,
+ // `${config.addonRef}-standalone`,
+ // `chrome,extrachrome,menubar,resizable=yes,scrollbars,status,dialog=no,${
+ // getPref("keepWindowTop") ? ",alwaysRaised=yes" : ""
+ // }`,
+ // dialogData,
+ // );
+ // await dialogData.loadLock.promise;
+ // // onInit(win.document.querySelector("#panel-container") as XUL.Box);
+ // buildExtraPanel(win.document.querySelector("#extra-container") as XUL.Box);
+ // addon.data.panel.windowPanel = win;
}
export function updateReaderTabPanels() {
- ztoolkit.ReaderTabPanel.changeTabPanel(addon.data.panel.tabOptionId, {
- selectPanel: getPref("autoFocus") as boolean,
- });
- cleanPanels();
- addon.data.panel.activePanels.forEach((panel) => updatePanel(panel));
- if (addon.data.panel.windowPanel && !addon.data.panel.windowPanel.closed) {
- updateExtraPanel(addon.data.panel.windowPanel.document);
- }
- updateTextAreasSize(true);
-}
-
-function createPanel(ownerDeck: XUL.Deck, refID: string) {
- const container = ownerDeck.selectedPanel;
- container.innerHTML = "";
- ztoolkit.UI.appendElement(
- {
- tag: "tabbox",
- id: `${config.addonRef}-${refID}-extra-tabbox`,
- classList: ["zotero-view-tabbox"],
- attributes: {
- flex: "1",
- },
- ignoreIfExists: true,
- children: [
- {
- tag: "tabs",
- classList: ["zotero-editpane-tabs"],
- attributes: {
- orient: "horizontal",
- },
- children: [
- {
- tag: "tab",
- attributes: {
- label: getString("readerpanel-label"),
- },
- },
- ],
- },
- {
- tag: "tabpanels",
- classList: ["zotero-view-item"],
- attributes: {
- flex: "1",
- },
- children: [
- {
- tag: "tabpanel",
- attributes: {
- flex: "1",
- },
- },
- ],
- },
- ],
- },
- container,
+ // ztoolkit.ReaderTabPanel.changeTabPanel(addon.data.panel.tabOptionId, {
+ // selectPanel: getPref("autoFocus") as boolean,
+ // });
+ Object.values(addon.data.panel.activePanels).forEach((refresh: any) =>
+ refresh(),
);
- return container.querySelector("tabpanel") as XUL.TabPanel;
+ // if (addon.data.panel.windowPanel && !addon.data.panel.windowPanel.closed) {
+ // updateExtraPanel(addon.data.panel.windowPanel.document);
+ // }
+ // updateTextAreasSize(true);
}
-function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
- const makeId = (type: string) => `${config.addonRef}-${refID}-panel-${type}`;
- const itemID = Zotero.Reader._readers.find(
- (reader) => reader._instanceID === refID,
- )?._item?.id;
- panel.setAttribute("item-id", String(itemID) || "");
- // Manually existance check to avoid unnecessary element creation with ...
- if (!force && panel.querySelector(`#${makeId("root")}`)) {
- return;
- }
+function onInit({
+ body,
+ refresh,
+ item,
+}: _ZoteroTypes.ItemPaneManager.SectionInitHookArgs) {
+ const paneUID = Zotero_Tabs.selectedID;
+ body.dataset.paneUid = paneUID;
+ addon.data.panel.activePanels[paneUID] = refresh;
+
+ const makeClass = (type: string) => `${paneUID}-${type}`;
+
+ body.style.display = "flex";
+ body.style.flexDirection = "column";
+ body.style.gap = "6px";
+
ztoolkit.UI.appendElement(
{
- tag: "vbox",
- id: makeId("root"),
- classList: [`${config.addonRef}-panel-root`],
- attributes: {
- flex: "1",
- align: "stretch",
- },
- styles: {
- padding: "8px",
- },
- ignoreIfExists: true,
+ tag: "fragment",
children: [
{
tag: "hbox",
- id: makeId("engine"),
+ classList: [makeClass("engine")],
attributes: {
flex: "0",
align: "center",
@@ -168,7 +93,7 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
children: [
{
tag: "menulist",
- id: makeId("services"),
+ classList: [makeClass("services")],
attributes: {
flex: "0",
native: "true",
@@ -210,11 +135,13 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
tag: "button",
namespace: "xul",
attributes: {
- label: `${getString(
- "readerpanel-translate-button-label",
- )}(${getString("ctrl")} + T)`,
+ label: getString("readerpanel-translate-button-label"),
+ tooltiptext: `(${getString("ctrl")} + T)`,
flex: "1",
},
+ styles: {
+ minWidth: "auto",
+ },
listeners: [
{
type: "click",
@@ -222,8 +149,8 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
if (!getLastTranslateTask()) {
addTranslateTask(
(
- panel.querySelector(
- `#${makeId(
+ body.querySelector(
+ `.${makeClass(
getPref("rawResultOrder")
? "resulttext"
: "rawtext",
@@ -243,18 +170,15 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
},
{
tag: "hbox",
- id: makeId("lang"),
+ classList: [makeClass("lang")],
attributes: {
flex: "0",
align: "center",
},
- styles: {
- marginTop: "8px",
- },
children: [
{
tag: "menulist",
- id: makeId("langfrom"),
+ classList: [makeClass("langfrom")],
attributes: {
flex: "1",
native: "true",
@@ -265,6 +189,7 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
listener: (e: Event) => {
const newValue = (e.target as XUL.MenuList).value;
setPref("sourceLanguage", newValue);
+ const itemID = item?.id;
itemID &&
(addon.data.translate.cachedSourceLanguage[itemID] =
newValue);
@@ -286,17 +211,21 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
],
},
{
- tag: "div",
+ tag: "toolbarbutton",
styles: {
- paddingLeft: "8px",
- paddingRight: "8px",
+ width: "24px",
+ height: "24px",
+ fill: "var(--fill-secondary)",
+ stroke: "var(--fill-secondary)",
+ listStyleImage: `url(chrome://${config.addonRef}/content/icons/swap.svg)`,
},
- properties: {
- innerHTML: "↔️",
+ attributes: {
+ style: `width: 24px; height: 24px; fill: var(--fill-secondary); stroke: var(--fill-secondary); -moz-context-properties: fill,fill-opacity,stroke,stroke-opacity; list-style-image: url(chrome://${config.addonRef}/content/icons/swap.svg)`,
+ tooltiptext: "Swap languages",
},
listeners: [
{
- type: "click",
+ type: "command",
listener: (ev) => {
const langfrom = getPref("sourceLanguage") as string;
const langto = getPref("targetLanguage") as string;
@@ -309,7 +238,7 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
},
{
tag: "menulist",
- id: makeId("langto"),
+ classList: [makeClass("langto")],
attributes: {
flex: "1",
native: "true",
@@ -339,359 +268,389 @@ function buildPanel(panel: HTMLElement, refID: string, force: boolean = false) {
],
},
{
- tag: "hbox",
- id: makeId("auto"),
+ tag: "div",
+ styles: {
+ borderTop: "var(--material-border)",
+ },
+ },
+ {
+ tag: "editable-text",
+ namespace: "xul",
+ classList: [makeClass("rawtext")],
attributes: {
- flex: "0",
- align: "center",
+ multiline: "true",
+ placeholder: "Select or type to translate",
},
styles: {
- marginTop: "8px",
+ minHeight: "100px",
+ maxHeight: "calc((100vh - 100px) / 2)",
},
- children: [
- {
- tag: "div",
- styles: {
- paddingLeft: "8px",
- },
- properties: {
- innerHTML: getString("readerpanel-auto-description-label"),
- },
- },
- {
- tag: "checkbox",
- styles: {
- paddingLeft: "8px",
- },
- id: makeId("autotrans"),
- attributes: {
- label: getString("readerpanel-auto-selection-label"),
- native: "true",
- },
- listeners: [
- {
- type: "command",
- listener: (e: Event) => {
- setPref("enableAuto", (e.target as XUL.Checkbox).checked);
- addon.hooks.onReaderTabPanelRefresh();
- },
- },
- ],
- },
+ listeners: [
{
- tag: "checkbox",
- styles: {
- paddingLeft: "8px",
- },
- id: makeId("autoannot"),
- attributes: {
- label: getString("readerpanel-auto-annotation-label"),
- native: "true",
+ type: "change",
+ listener: (ev) => {
+ const task = getLastTranslateTask({
+ id: body.getAttribute("translate-task-id") || "",
+ });
+ if (!task) {
+ return;
+ }
+ const reverseRawResult = getPref("rawResultOrder");
+ if (!reverseRawResult) {
+ task.raw = (ev.target as HTMLTextAreaElement).value;
+ } else {
+ task.result = (ev.target as HTMLTextAreaElement).value;
+ }
+ putTranslateTaskAtHead(task.id);
},
- listeners: [
- {
- type: "command",
- listener: (e: Event) => {
- setPref(
- "enableComment",
- (e.target as XUL.Checkbox).checked,
- );
- addon.hooks.onReaderTabPanelRefresh();
- },
- },
- ],
},
],
},
{
- tag: "hbox",
- id: makeId("concat"),
+ tag: "div",
styles: {
- marginTop: "8px",
- },
- attributes: {
- flex: "0",
- align: "center",
+ borderTop: "var(--material-border)",
},
- children: [
- {
- tag: "div",
- styles: {
- paddingLeft: "8px",
- },
- properties: {
- innerHTML: getString("readerpanel-concat-description-label"),
- },
- },
- {
- tag: "checkbox",
- styles: {
- paddingLeft: "8px",
- },
- id: makeId("concat"),
- attributes: {
- label: `${getString(
- "readerpanel-concat-enable-label",
- )}/${getString("alt")}`,
- native: "true",
- },
- listeners: [
- {
- type: "command",
- listener: (e) => {
- addon.data.translate.concatCheckbox = (
- e.target as XUL.Checkbox
- ).checked;
- addon.hooks.onReaderTabPanelRefresh();
- },
- },
- ],
- },
- {
- tag: "button",
- namespace: "xul",
- attributes: {
- label: getString("readerpanel-concat-clear-label"),
- flex: "0",
- },
- listeners: [
- {
- type: "click",
- listener: (e) => {
- const task = getLastTranslateTask();
- if (task) {
- task.raw = "";
- task.result = "";
- addon.hooks.onReaderTabPanelRefresh();
- }
- },
- },
- ],
- },
- ],
},
{
- tag: "hbox",
- id: makeId("raw"),
+ tag: "editable-text",
+ namespace: "xul",
+ classList: [makeClass("resulttext")],
attributes: {
- flex: "1",
- spellcheck: false,
+ multiline: "true",
+ placeholder: "Translate result",
},
styles: {
- marginTop: "8px",
+ minHeight: "100px",
+ maxHeight: "calc((100vh - 100px) / 2)",
},
- children: [
+ listeners: [
{
- tag: "textarea",
- id: makeId("rawtext"),
- styles: {
- resize: "none",
- fontFamily: "inherit",
+ type: "change",
+ listener: (ev) => {
+ const task = getLastTranslateTask({
+ id: body.getAttribute("translate-task-id") || "",
+ });
+ if (!task) {
+ return;
+ }
+ const reverseRawResult = getPref("rawResultOrder");
+ if (!reverseRawResult) {
+ task.result = (ev.target as HTMLTextAreaElement).value;
+ } else {
+ task.raw = (ev.target as HTMLTextAreaElement).value;
+ }
+ putTranslateTaskAtHead(task.id);
},
- listeners: [
- {
- type: "input",
- listener: (ev) => {
- const task = getLastTranslateTask({
- id: panel.getAttribute("translate-task-id") || "",
- });
- if (!task) {
- return;
- }
- const reverseRawResult = getPref("rawResultOrder");
- if (!reverseRawResult) {
- task.raw = (ev.target as HTMLTextAreaElement).value;
- } else {
- task.result = (ev.target as HTMLTextAreaElement).value;
- }
- putTranslateTaskAtHead(task.id);
- },
- },
- ],
},
],
},
{
- tag: "splitter",
- id: makeId("splitter"),
- attributes: { collapse: "after" },
+ tag: "div",
styles: {
- height: "3px",
+ borderTop: "var(--material-border)",
},
- children: [
- {
- tag: "grippy",
- },
- ],
},
{
- tag: "hbox",
- id: makeId("result"),
- attributes: {
- flex: "1",
- spellcheck: false,
+ tag: "div",
+ styles: {
+ display: "grid",
+ gridTemplateColumns: "max-content 1fr",
+ columnGap: "8px",
+ rowGap: "2px",
+ width: "inherit",
},
children: [
{
- tag: "textarea",
- id: makeId("resulttext"),
+ tag: "div",
+ classList: [makeClass("auto")],
styles: {
- resize: "none",
- fontFamily: "inherit",
+ display: "grid",
+ gridTemplateColumns: "subgrid",
+ gridColumn: "span 2",
},
- listeners: [
+ children: [
{
- type: "input",
- listener: (ev) => {
- const task = getLastTranslateTask({
- id: panel.getAttribute("translate-task-id") || "",
- });
- if (!task) {
- return;
- }
- const reverseRawResult = getPref("rawResultOrder");
- if (!reverseRawResult) {
- task.result = (ev.target as HTMLTextAreaElement).value;
- } else {
- task.raw = (ev.target as HTMLTextAreaElement).value;
- }
- putTranslateTaskAtHead(task.id);
+ tag: "div",
+ styles: {
+ display: "flex",
+ justifyContent: "center",
+ flexDirection: "column",
+ color: "var(--fill-secondary)",
+ },
+ properties: {
+ innerHTML: getString("readerpanel-auto-description-label"),
},
},
+ {
+ tag: "div",
+ styles: {
+ display: "flex",
+ flexDirection: "row",
+ },
+ children: [
+ {
+ tag: "checkbox",
+ classList: [makeClass("autotrans")],
+ attributes: {
+ label: getString("readerpanel-auto-selection-label"),
+ native: "true",
+ },
+ listeners: [
+ {
+ type: "command",
+ listener: (e: Event) => {
+ setPref(
+ "enableAuto",
+ (e.target as XUL.Checkbox).checked,
+ );
+ addon.hooks.onReaderTabPanelRefresh();
+ },
+ },
+ ],
+ },
+ {
+ tag: "checkbox",
+ classList: [makeClass("autoannot")],
+ attributes: {
+ label: getString("readerpanel-auto-annotation-label"),
+ native: "true",
+ },
+ listeners: [
+ {
+ type: "command",
+ listener: (e: Event) => {
+ setPref(
+ "enableComment",
+ (e.target as XUL.Checkbox).checked,
+ );
+ addon.hooks.onReaderTabPanelRefresh();
+ },
+ },
+ ],
+ },
+ ],
+ },
],
},
- ],
- },
- {
- tag: "hbox",
- id: makeId("copy"),
- attributes: {
- flex: "0",
- align: "center",
- },
- styles: {
- marginTop: "8px",
- },
- children: [
{
tag: "div",
- properties: {
- innerHTML: getString("readerpanel-copy-description-label"),
- },
- },
- {
- tag: "button",
- namespace: "xul",
- attributes: {
- label: getString("readerpanel-copy-raw-label"),
- flex: "1",
+ classList: [makeClass("concat")],
+ styles: {
+ display: "grid",
+ gridTemplateColumns: "subgrid",
+ gridColumn: "span 2",
},
- listeners: [
+ children: [
{
- type: "click",
- listener: (e: Event) => {
- const task = getLastTranslateTask({
- id: panel.getAttribute("translate-task-id") || "",
- });
- if (!task) {
- return;
- }
- new ztoolkit.Clipboard()
- .addText(task.raw, "text/unicode")
- .copy();
+ tag: "div",
+ styles: {
+ display: "flex",
+ justifyContent: "center",
+ flexDirection: "column",
+ color: "var(--fill-secondary)",
+ },
+ properties: {
+ innerHTML: getString("readerpanel-concat-enable-label"),
},
},
- ],
- },
- {
- tag: "button",
- namespace: "xul",
- attributes: {
- label: getString("readerpanel-copy-result-label"),
- flex: "1",
- },
- listeners: [
{
- type: "click",
- listener: (e: Event) => {
- const task = getLastTranslateTask({
- id: panel.getAttribute("translate-task-id") || "",
- });
- if (!task) {
- return;
- }
- new ztoolkit.Clipboard()
- .addText(task.result, "text/unicode")
- .copy();
+ tag: "div",
+ styles: {
+ display: "flex",
+ flexDirection: "row",
},
+ children: [
+ {
+ tag: "checkbox",
+ classList: [makeClass("concat")],
+ attributes: {
+ label: `${getString(
+ "readerpanel-concat-enable-label",
+ )}/${getString("alt")}`,
+ native: "true",
+ },
+ listeners: [
+ {
+ type: "command",
+ listener: (e) => {
+ addon.data.translate.concatCheckbox = (
+ e.target as XUL.Checkbox
+ ).checked;
+ addon.hooks.onReaderTabPanelRefresh();
+ },
+ },
+ ],
+ },
+ {
+ tag: "button",
+ namespace: "xul",
+ attributes: {
+ label: getString("readerpanel-concat-clear-label"),
+ flex: "0",
+ },
+ styles: {
+ minWidth: "auto",
+ },
+ listeners: [
+ {
+ type: "click",
+ listener: (e) => {
+ const task = getLastTranslateTask();
+ if (task) {
+ task.raw = "";
+ task.result = "";
+ addon.hooks.onReaderTabPanelRefresh();
+ }
+ },
+ },
+ ],
+ },
+ ],
},
],
},
{
- tag: "button",
- namespace: "xul",
- attributes: {
- label: getString("readerpanel-copy-both-label"),
- flex: "1",
+ tag: "div",
+ classList: [makeClass("copy")],
+ styles: {
+ display: "grid",
+ gridTemplateColumns: "subgrid",
+ gridColumn: "span 2",
},
- listeners: [
+ children: [
{
- type: "click",
- listener: (e: Event) => {
- const task = getLastTranslateTask({
- id: panel.getAttribute("translate-task-id") || "",
- });
- if (!task) {
- return;
- }
- new ztoolkit.Clipboard()
- .addText(
- `${task.raw}\n----\n${task.result}`,
- "text/unicode",
- )
- .copy();
+ tag: "div",
+ styles: {
+ display: "flex",
+ justifyContent: "center",
+ flexDirection: "column",
+ color: "var(--fill-secondary)",
},
+ properties: {
+ innerHTML: getString("readerpanel-copy-description-label"),
+ },
+ },
+ {
+ tag: "div",
+ styles: {
+ display: "flex",
+ flexDirection: "row",
+ },
+ children: [
+ {
+ tag: "button",
+ namespace: "xul",
+ attributes: {
+ label: getString("readerpanel-copy-raw-label"),
+ flex: "1",
+ },
+ styles: {
+ minWidth: "auto",
+ },
+ listeners: [
+ {
+ type: "click",
+ listener: (e: Event) => {
+ const task = getLastTranslateTask({
+ id: body.getAttribute("translate-task-id") || "",
+ });
+ if (!task) {
+ return;
+ }
+ new ztoolkit.Clipboard()
+ .addText(task.raw, "text/unicode")
+ .copy();
+ },
+ },
+ ],
+ },
+ {
+ tag: "button",
+ namespace: "xul",
+ attributes: {
+ label: getString("readerpanel-copy-result-label"),
+ flex: "1",
+ },
+ styles: {
+ minWidth: "auto",
+ },
+ listeners: [
+ {
+ type: "click",
+ listener: (e: Event) => {
+ const task = getLastTranslateTask({
+ id: body.getAttribute("translate-task-id") || "",
+ });
+ if (!task) {
+ return;
+ }
+ new ztoolkit.Clipboard()
+ .addText(task.result, "text/unicode")
+ .copy();
+ },
+ },
+ ],
+ },
+ {
+ tag: "button",
+ namespace: "xul",
+ attributes: {
+ label: getString("readerpanel-copy-both-label"),
+ flex: "1",
+ },
+ styles: {
+ minWidth: "auto",
+ },
+ listeners: [
+ {
+ type: "click",
+ listener: (e: Event) => {
+ const task = getLastTranslateTask({
+ id: body.getAttribute("translate-task-id") || "",
+ });
+ if (!task) {
+ return;
+ }
+ new ztoolkit.Clipboard()
+ .addText(
+ `${task.raw}\n----\n${task.result}`,
+ "text/unicode",
+ )
+ .copy();
+ },
+ },
+ ],
+ },
+ ],
},
],
},
],
},
{
- tag: "hbox",
- id: makeId("openwindow"),
- styles: {
- marginTop: "8px",
- },
+ tag: "button",
+ namespace: "xul",
attributes: {
- flex: "0",
- align: "center",
+ label: getString("readerpanel-openwindow-open-label"),
+ flex: "1",
},
- children: [
+ styles: {
+ minWidth: "auto",
+ },
+ listeners: [
{
- tag: "button",
- namespace: "xul",
- attributes: {
- label: getString("readerpanel-openwindow-open-label"),
- flex: "1",
+ type: "click",
+ listener: (e: Event) => {
+ openWindowPanel();
},
- listeners: [
- {
- type: "click",
- listener: (e: Event) => {
- openWindowPanel();
- },
- },
- ],
},
],
},
],
},
- panel,
+ body,
);
- updatePanel(panel);
- updateTextAreaSize(panel);
- recordPanel(panel);
}
function buildExtraPanel(panel: XUL.Box) {
@@ -923,27 +882,35 @@ function buildExtraPanel(panel: XUL.Box) {
);
}
-function updatePanel(panel: HTMLElement) {
- const idPrefix = panel
- .querySelector(`.${config.addonRef}-panel-root`)!
- .id.split("-")
- .slice(0, -1)
- .join("-");
- const makeId = (type: string) => `${idPrefix}-${type}`;
+function onItemChange({
+ tabType,
+ setEnabled,
+}: _ZoteroTypes.ItemPaneManager.SectionHookArgs) {
+ if (tabType !== "reader") {
+ setEnabled(false);
+ }
+ return true;
+}
+
+function onRender({
+ body,
+ item,
+}: _ZoteroTypes.ItemPaneManager.SectionHookArgs) {
+ const makeClass = (type: string) => `${body.dataset.paneUid}-${type}`;
const updateHidden = (type: string, pref: string) => {
- const elem = panel.querySelector(`#${makeId(type)}`) as XUL.Box;
+ const elem = body.querySelector(`.${makeClass(type)}`) as XUL.Box;
elem.hidden = !getPref(pref) as boolean;
};
const setCheckBox = (type: string, checked: boolean) => {
- const elem = panel.querySelector(`#${makeId(type)}`) as XUL.Checkbox;
+ const elem = body.querySelector(`.${makeClass(type)}`) as XUL.Checkbox;
elem.checked = checked;
};
const setValue = (type: string, value: string) => {
- const elem = panel.querySelector(`#${makeId(type)}`) as XUL.Textbox;
+ const elem = body.querySelector(`.${makeClass(type)}`) as XUL.Textbox;
elem.value = value;
};
const setTextBoxStyle = (type: string) => {
- const elem = panel.querySelector(`#${makeId(type)}`) as XUL.Textbox;
+ const elem = body.querySelector(`.${makeClass(type)}`) as XUL.Textbox;
elem.style.fontSize = `${getPref("fontSize")}px`;
elem.style.lineHeight = getPref("lineHeight") as string;
};
@@ -952,15 +919,12 @@ function updatePanel(panel: HTMLElement) {
updateHidden("lang", "showSidebarLanguage");
updateHidden("auto", "showSidebarSettings");
updateHidden("concat", "showSidebarConcat");
- updateHidden("raw", "showSidebarRaw");
- updateHidden("splitter", "showSidebarRaw");
+ updateHidden("rawtext", "showSidebarRaw");
updateHidden("copy", "showSidebarCopy");
setValue("services", getPref("translateSource") as string);
- const { fromLanguage, toLanguage } = autoDetectLanguage(
- Zotero.Items.get(panel.getAttribute("item-id") as string),
- );
+ const { fromLanguage, toLanguage } = autoDetectLanguage(item);
setValue("langfrom", fromLanguage);
setValue("langto", toLanguage);
@@ -973,15 +937,12 @@ function updatePanel(panel: HTMLElement) {
return;
}
// For manually update translation task
- panel.setAttribute("translate-task-id", lastTask.id);
+ body.setAttribute("translate-task-id", lastTask.id);
const reverseRawResult = getPref("rawResultOrder");
setValue("rawtext", reverseRawResult ? lastTask.result : lastTask.raw);
setValue("resulttext", reverseRawResult ? lastTask.raw : lastTask.result);
setTextBoxStyle("rawtext");
setTextBoxStyle("resulttext");
- panel
- .querySelector(`#${makeId("splitter")}`)
- ?.setAttribute("collapse", reverseRawResult ? "after" : "before");
}
function updateExtraPanel(container: HTMLElement | Document) {
@@ -996,36 +957,8 @@ function updateExtraPanel(container: HTMLElement | Document) {
});
}
-function updateTextAreaSize(
- container: HTMLElement | Document,
- noDelay: boolean = false,
-) {
- const setTimeout = ztoolkit.getGlobal("setTimeout");
- Array.from(container.querySelectorAll("textarea")).forEach((elem) => {
- if (noDelay) {
- elem.style.width = `${elem.parentElement?.scrollWidth}px`;
- return;
- }
- elem.style.width = "0px";
- setTimeout(() => {
- elem.style.width = `${elem.parentElement?.scrollWidth}px`;
- }, 0);
- });
-}
-
-function updateTextAreasSize(noDelay: boolean = false) {
- cleanPanels();
- addon.data.panel.activePanels.forEach((panel) =>
- updateTextAreaSize(panel, noDelay),
- );
-}
-
-function recordPanel(panel: HTMLElement) {
- addon.data.panel.activePanels.push(panel);
-}
-
-function cleanPanels() {
- addon.data.panel.activePanels = addon.data.panel.activePanels.filter(
- (elem) => elem.parentElement && (elem as any).ownerGlobal,
- );
+function onDestroy(options: any) {
+ const { body } = options;
+ const paneUID = body.dataset.paneUid;
+ delete addon.data.panel.activePanels[paneUID];
}