diff --git a/addon/chrome/content/overlay.xul b/addon/chrome/content/overlay.xul index 9b34507..8605929 100644 --- a/addon/chrome/content/overlay.xul +++ b/addon/chrome/content/overlay.xul @@ -63,10 +63,10 @@ - + - + diff --git a/addon/chrome/content/workspace.xul b/addon/chrome/content/workspace.xul index d56cfed..cd22b24 100644 --- a/addon/chrome/content/workspace.xul +++ b/addon/chrome/content/workspace.xul @@ -70,10 +70,10 @@ - + - + diff --git a/addon/chrome/locale/en-US/addon.properties b/addon/chrome/locale/en-US/addon.properties new file mode 100644 index 0000000..9b3f32c --- /dev/null +++ b/addon/chrome/locale/en-US/addon.properties @@ -0,0 +1,22 @@ +library.workspace=Workspace +library.openWorkspace=Open Workspace +library.newMainNote=New Main Note +library.newMainNote.confirmHead=Will create a new note under collection +library.newMainNote.confirmTail=and set it the main note. Continue? +library.importMD=Import MarkDown as Note +editor.mainNote=Main Note +editor.recentMainNotes=Set Main Note from Recent +editor.refreshEditor=Refresh Editor +editor.previewInWorkspace=Preview in Workspace +editor.copyNoteLink=Copy Note Link +editor.copyNoteLinkOfLine=Copy Note Link of Current Line +editor.importMD=Import from MarkDown +editor.resizeImage=Resize Image +editor.resizeImage.prompt=Enter new width (px): +editor.previewImage=Preview Image +editor.insertAnchor=Insert Position Preview +editor.endOfNote=End of Note +menu.insertTextTemplate=Insert Note Template [Text] +menu.insertItemTemplate=Insert Note Template [Item] +export.withLinkedNotes.confirm=Export linked notes to markdown files? +export.withYAML.confirm=With YAML Front Matter? \ No newline at end of file diff --git a/addon/chrome/locale/en-US/overlay.dtd b/addon/chrome/locale/en-US/overlay.dtd index a52f664..762bbda 100644 --- a/addon/chrome/locale/en-US/overlay.dtd +++ b/addon/chrome/locale/en-US/overlay.dtd @@ -7,9 +7,8 @@ - - - + + diff --git a/addon/chrome/locale/zh-CN/addon.properties b/addon/chrome/locale/zh-CN/addon.properties new file mode 100644 index 0000000..9d30de1 --- /dev/null +++ b/addon/chrome/locale/zh-CN/addon.properties @@ -0,0 +1,22 @@ +library.workspace=工作区 +library.openWorkspace=打开工作区 +library.newMainNote=新建笔记并设为主笔记 +library.newMainNote.confirmHead=将在当前分类 +library.newMainNote.confirmTail=创建新笔记并将它设为主笔记。确认继续吗? +library.importMD=导入Markdown为笔记 +editor.mainNote=主笔记 +editor.recentMainNotes=从最近笔记设置主笔记 +editor.refreshEditor=刷新编辑器 +editor.previewInWorkspace=在工作区中预览 +editor.copyNoteLink=复制笔记链接 +editor.copyNoteLinkOfLine=复制当前行的笔记链接 +editor.importMD=从Markdown导入 +editor.resizeImage=调整图片大小 +editor.resizeImage.prompt=输入新的宽度(单位:像素): +editor.previewImage=预览图片 +editor.insertAnchor=插入位置预览 +editor.endOfNote=笔记结尾 +menu.insertTextTemplate=插入笔记模板[文本/Text] +menu.insertItemTemplate=插入笔记模板[条目/Item] +export.withLinkedNotes.confirm=导出链接的子笔记到Markdown? +export.withYAML.confirm=导出带有YAML Front Matter? \ No newline at end of file diff --git a/addon/chrome/locale/zh-CN/overlay.dtd b/addon/chrome/locale/zh-CN/overlay.dtd index f3255f0..3bac511 100644 --- a/addon/chrome/locale/zh-CN/overlay.dtd +++ b/addon/chrome/locale/zh-CN/overlay.dtd @@ -7,9 +7,8 @@ - - - + + diff --git a/src/addon.ts b/src/addon.ts index e5804d0..ffae6f6 100644 --- a/src/addon.ts +++ b/src/addon.ts @@ -26,9 +26,11 @@ import EditorImageViewer from "./editor/imageViewerWindow"; import TemplateWindow from "./template/templateWindow"; import { SyncUtils } from "./sync/syncUtils"; import ZoteroToolkit from "zotero-plugin-toolkit"; +import AddonLocale from "./zotero/locale"; class BetterNotes { public env: "development" | "production"; + public Locale: AddonLocale; public ZoteroEvents: ZoteroEvents; public ZoteroNotifies: ZoteroNotifies; // Zotero UI @@ -65,6 +67,7 @@ class BetterNotes { public toolkit: ZoteroToolkit; constructor() { + this.Locale = new AddonLocale(this); this.ZoteroEvents = new ZoteroEvents(this); this.ZoteroNotifies = new ZoteroNotifies(this); this.ZoteroViews = new ZoteroViews(this); diff --git a/src/editor/editorViews.ts b/src/editor/editorViews.ts index 4c15440..8a88874 100644 --- a/src/editor/editorViews.ts +++ b/src/editor/editorViews.ts @@ -99,8 +99,9 @@ class EditorViews extends AddonBase { _window.document, "div" ) as HTMLDivElement; - titleNode.innerHTML = "Set Recent Main Notes"; - titleNode.title = "Click item to set it main note"; + titleNode.innerHTML = titleNode.title = this._Addon.Locale.getString( + "editor.recentMainNotes" + ); titleNode.style.textAlign = "center"; popup.childNodes[0].before( titleNode, @@ -136,7 +137,7 @@ class EditorViews extends AddonBase { "div" ) as HTMLDivElement; header.setAttribute("title", "This is a Main Note"); - header.innerHTML = "Main Note"; + header.innerHTML = this._Addon.Locale.getString("editor.mainNote"); header.setAttribute("style", "font-size: medium"); addLinkDropDown.append(header); } else { @@ -359,7 +360,9 @@ class EditorViews extends AddonBase { "button" ) as HTMLButtonElement; refreshButton.classList.add("option"); - refreshButton.innerText = "Refresh Editor"; + refreshButton.innerText = this._Addon.Locale.getString( + "editor.refreshEditor" + ); refreshButton.addEventListener("click", async (e) => { if ( !confirm( @@ -388,7 +391,9 @@ class EditorViews extends AddonBase { "button" ) as HTMLButtonElement; previewButton.classList.add("option"); - previewButton.innerText = "Preview in Workspace"; + previewButton.innerText = this._Addon.Locale.getString( + "editor.previewInWorkspace" + ); previewButton.addEventListener("click", async (e) => { await this._Addon.WorkspaceWindow.openWorkspaceWindow(); await this._Addon.WorkspaceWindow.setWorkspaceNote( @@ -401,7 +406,9 @@ class EditorViews extends AddonBase { "button" ) as HTMLButtonElement; copyLinkButton.classList.add("option"); - copyLinkButton.innerText = "Copy Note Link"; + copyLinkButton.innerText = this._Addon.Locale.getString( + "editor.copyNoteLink" + ); copyLinkButton.addEventListener("click", (e) => { const linkText = this._Addon.NoteUtils.getNoteLink(noteItem); const linkHTML = `

${ @@ -425,7 +432,9 @@ class EditorViews extends AddonBase { "button" ) as HTMLButtonElement; copyLinkAtLineButton.classList.add("option"); - copyLinkAtLineButton.innerText = "Copy Note Link of Current Line"; + copyLinkAtLineButton.innerText = this._Addon.Locale.getString( + "editor.copyNoteLinkOfLine" + ); copyLinkAtLineButton.addEventListener("click", (e) => { const linkText = this._Addon.NoteUtils.getNoteLink(noteItem, { withLine: true, @@ -451,7 +460,8 @@ class EditorViews extends AddonBase { "button" ) as HTMLButtonElement; importButton.classList.add("option"); - importButton.innerText = "Import from MarkDown"; + importButton.innerText = + this._Addon.Locale.getString("editor.importMD"); importButton.addEventListener("click", async (e) => { await this._Addon.NoteImport.doImport(noteItem, { ignoreVersion: true, @@ -893,6 +903,25 @@ class EditorViews extends AddonBase { } } + public openImagePreview(instance: Zotero.EditorInstance) { + const _window = instance._iframeWindow; + const imgs = _window.document + .querySelector(".primary-editor") + ?.querySelectorAll("img"); + this._Addon.EditorImageViewer.onInit( + Array.prototype.map.call(imgs, (e: HTMLImageElement) => e.src), + Array.prototype.indexOf.call( + imgs, + _window.document + .querySelector(".primary-editor") + .querySelector(".selected") + .querySelector("img") + ), + instance._item.getNoteTitle(), + this._Addon.EditorImageViewer.pined + ); + } + public updateEditorImagePopup(instance: Zotero.EditorInstance) { const _window = instance._iframeWindow; @@ -904,21 +933,7 @@ class EditorViews extends AddonBase { previewButton.innerHTML = `

`; previewButton.id = "bn-image-preview"; previewButton.addEventListener("click", (e) => { - const imgs = _window.document - .querySelector(".primary-editor") - ?.querySelectorAll("img"); - this._Addon.EditorImageViewer.onInit( - Array.prototype.map.call(imgs, (e: HTMLImageElement) => e.src), - Array.prototype.indexOf.call( - imgs, - _window.document - .querySelector(".primary-editor") - .querySelector(".selected") - .querySelector("img") - ), - instance._item.getNoteTitle(), - this._Addon.EditorImageViewer.pined - ); + this.openImagePreview(instance); }); _window.document.querySelector(".image-popup").append(previewButton); } @@ -964,193 +979,245 @@ class EditorViews extends AddonBase { ); }; - const elementOptions = { - tag: "fragment", - subElementOptions: [ - { - tag: "menuseparator", - id: "menupopup-betternotessplitter", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - }, - { - tag: "menuitem", - id: "menupopup-resizeImage", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { label: "Resize Image" }, - customCheck: checkImageSelected, - listeners: [ - { - type: "command", - listener: (e: Event) => { - const newWidth = parseFloat( - prompt( - "Enter new width (px):", - (instance._iframeWindow as any).wrappedJSObject - ._currentEditorInstance._editorCore.view.state.selection - .node?.attrs?.width - ) - ); - if (newWidth && newWidth > 10) { - instance._iframeWindow.postMessage( - { type: "resizeImage", width: newWidth }, - "*" - ); - } - }, - }, - ], - }, - { - tag: "menuseparator", - id: "menupopup-resizeimagesplitter", - checkExistanceParent: instance._popup, - customCheck: checkImageSelected, - ignoreIfExists: true, - }, - { - tag: "menuitem", - id: "menupopup-copylink", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { label: "Copy Note Link" }, - listeners: [ - { - type: "command", - listener: (e: Event) => { - const linkText = this._Addon.NoteUtils.getNoteLink(noteItem); - const linkHTML = `

${ - noteItem.getNoteTitle().trim() - ? noteItem.getNoteTitle().trim() - : linkText - }

`; - - this._Addon.toolkit.Tool.getCopyHelper() - .addText(linkText, "text/unicode") - .addText(linkHTML, "text/html") - .copy(); - this._Addon.ZoteroViews.showProgressWindow( - "Better Notes", - "Note Link Copied" - ); - }, - }, - ], - }, - { - tag: "menuitem", - id: "menupopup-copylinkline", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { label: `Copy Note Link of Line ${lineIndex + 1}` }, - listeners: [ - { - type: "command", - listener: ((e: Event) => { - const linkText = this._Addon.NoteUtils.getNoteLink(noteItem, { - withLine: true, - }); - const linkHTML = `

${ - noteItem.getNoteTitle().trim() - ? noteItem.getNoteTitle().trim() - : linkText - }

`; - this._Addon.toolkit.Tool.getCopyHelper() - .addText(linkText, "text/unicode") - .addText(linkHTML, "text/html") - .copy(); - this._Addon.ZoteroViews.showProgressWindow( - "Better Notes", - `Note Link of Line ${lineIndex + 1} Copied` - ); - }) as EventListener, - }, - ], - }, - { - tag: "menu", - id: "menupopup-insertTextTemplateMenu", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { label: "Insert Template (Text)" }, - subElementOptions: [ - { - tag: "menupopup", - id: `menu_insert${instance._item.id}TextTemplatePopup`, - ignoreIfExists: true, - attributes: { - onpopupshowing: `Zotero.BetterNotes.ZoteroViews.updateTemplateMenu('Text', Zotero.BetterNotes.EditorController.activeEditor._popup.ownerDocument, '${instance._item.id}', false);`, - }, - }, - ], - }, - { - tag: "menu", - id: "menupopup-insertItemTemplate", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { label: "Insert Template (Item)" }, - subElementOptions: [ - { - tag: "menupopup", - id: `menu_insert${instance._item.id}ItemTemplatePopup`, - ignoreIfExists: true, - attributes: { - onpopupshowing: `Zotero.BetterNotes.ZoteroViews.updateTemplateMenu('Item', Zotero.BetterNotes.EditorController.activeEditor._popup.ownerDocument, '${instance._item.id}', false);`, - }, - }, - ], - }, - { - tag: "menuseparator", - id: "menupopup-linepreviewsplitter", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - }, - { - tag: "menuitem", - id: "menupopup-lineprevious", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { - label: `L${lineIndex + 1}:${shorten( - lineElements[lineIndex].innerText, - 25 - )}`, - - disabled: true, - }, - }, - { - tag: "menuitem", - id: "menupopup-insertposition", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { label: "<--- Insert Anchor", disabled: true }, - }, - { - tag: "menuitem", - id: "menupopup-linenext", - checkExistanceParent: instance._popup, - ignoreIfExists: true, - attributes: { - label: - lineIndex + 1 >= lineElements.length - ? "End of Note" - : `L${lineIndex + 2}:${shorten( - lineElements[lineIndex + 1].innerText, - 25 - )}`, - disabled: true, - }, - }, - ], - }; + const prefix = `editormenu-betternotes-${instance.instanceID}-`; const fragment = this._Addon.toolkit.UI.creatElementsFromJSON( instance._popup.ownerDocument, - elementOptions + { + tag: "fragment", + namespace: "xul", + subElementOptions: [ + { + tag: "menuseparator", + id: prefix + "splitter", + checkExistanceParent: instance._popup, + removeIfExists: true, + }, + { + tag: "menuitem", + id: prefix + "resizeImage", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: this._Addon.Locale.getString("editor.resizeImage"), + }, + customCheck: checkImageSelected, + listeners: [ + { + type: "command", + listener: (e: Event) => { + const newWidth = parseFloat( + prompt( + this._Addon.Locale.getString("editor.resizeImage.prompt"), + (instance._iframeWindow as any).wrappedJSObject + ._currentEditorInstance._editorCore.view.state.selection + .node?.attrs?.width + ) + ); + if (newWidth && newWidth > 10) { + instance._iframeWindow.postMessage( + { type: "resizeImage", width: newWidth }, + "*" + ); + } + }, + }, + ], + }, + { + tag: "menuitem", + id: prefix + "previewImage", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: this._Addon.Locale.getString("editor.previewImage"), + }, + customCheck: checkImageSelected, + listeners: [ + { + type: "command", + listener: (e: Event) => { + this.openImagePreview(instance); + }, + }, + ], + }, + { + tag: "menuseparator", + id: prefix + "resizeimagesplitter", + checkExistanceParent: instance._popup, + customCheck: checkImageSelected, + removeIfExists: true, + }, + { + tag: "menuitem", + id: prefix + "copylink", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: this._Addon.Locale.getString("editor.copyNoteLink"), + }, + listeners: [ + { + type: "command", + listener: (e: Event) => { + const linkText = this._Addon.NoteUtils.getNoteLink(noteItem); + const linkHTML = `

${ + noteItem.getNoteTitle().trim() + ? noteItem.getNoteTitle().trim() + : linkText + }

`; + + this._Addon.toolkit.Tool.getCopyHelper() + .addText(linkText, "text/unicode") + .addText(linkHTML, "text/html") + .copy(); + this._Addon.ZoteroViews.showProgressWindow( + "Better Notes", + "Note Link Copied" + ); + }, + }, + ], + }, + { + tag: "menuitem", + id: prefix + "copylinkline", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: `${this._Addon.Locale.getString( + "editor.copyNoteLinkOfLine" + )} ${lineIndex + 1}`, + }, + listeners: [ + { + type: "command", + listener: ((e: Event) => { + const linkText = this._Addon.NoteUtils.getNoteLink(noteItem, { + withLine: true, + }); + const linkHTML = `

${ + noteItem.getNoteTitle().trim() + ? noteItem.getNoteTitle().trim() + : linkText + }

`; + this._Addon.toolkit.Tool.getCopyHelper() + .addText(linkText, "text/unicode") + .addText(linkHTML, "text/html") + .copy(); + this._Addon.ZoteroViews.showProgressWindow( + "Better Notes", + `Note Link of Line ${lineIndex + 1} Copied` + ); + }) as EventListener, + }, + ], + }, + { + tag: "menu", + id: prefix + "insertTextTemplateMenu", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: this._Addon.Locale.getString("menu.insertTextTemplate"), + }, + subElementOptions: [ + { + tag: "menupopup", + ignoreIfExists: true, + listeners: [ + { + type: "popupshowing", + listener: (e) => { + this._Addon.ZoteroViews.updateTemplateMenu( + e, + "Text", + false + ); + }, + }, + ], + }, + ], + }, + { + tag: "menu", + id: prefix + "insertItemTemplate", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: this._Addon.Locale.getString("menu.insertItemTemplate"), + }, + subElementOptions: [ + { + tag: "menupopup", + ignoreIfExists: true, + listeners: [ + { + type: "popupshowing", + listener: (e) => { + this._Addon.ZoteroViews.updateTemplateMenu( + e, + "Item", + false + ); + }, + }, + ], + }, + ], + }, + { + tag: "menuseparator", + id: prefix + "linepreviewsplitter", + checkExistanceParent: instance._popup, + removeIfExists: true, + }, + { + tag: "menuitem", + id: prefix + "lineprevious", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: `L${lineIndex + 1}:${shorten( + lineElements[lineIndex].innerText, + 25 + )}`, + + disabled: true, + }, + }, + { + tag: "menuitem", + id: prefix + "insertposition", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: `<--- ${this._Addon.Locale.getString( + "editor.insertAnchor" + )}`, + disabled: true, + }, + }, + { + tag: "menuitem", + id: prefix + "linenext", + checkExistanceParent: instance._popup, + removeIfExists: true, + attributes: { + label: + lineIndex + 1 >= lineElements.length + ? this._Addon.Locale.getString("editor.endOfNote") + : `L${lineIndex + 2}:${shorten( + lineElements[lineIndex + 1].innerText, + 25 + )}`, + disabled: true, + }, + }, + ], + } ); if (fragment) { instance._popup.append(fragment); diff --git a/src/note/noteExportController.ts b/src/note/noteExportController.ts index d19002c..2e332cc 100644 --- a/src/note/noteExportController.ts +++ b/src/note/noteExportController.ts @@ -361,7 +361,7 @@ class NoteExport extends AddonBase { const content: string = await this._Addon.NoteParse.parseNoteToMD(note, { withMeta: withMeta, }); - console.log( + this._Addon.toolkit.Tool.log( `Exporting MD file: ${filename}, content length: ${content.length}` ); await Zotero.File.putContentsAsync(filename, content); diff --git a/src/note/noteUtils.ts b/src/note/noteUtils.ts index 5740055..04319a1 100644 --- a/src/note/noteUtils.ts +++ b/src/note/noteUtils.ts @@ -709,7 +709,10 @@ class NoteUtils extends AddonBase { }; } - public async onSelectionChange(editor: Zotero.EditorInstance) { + public async onSelectionChange( + editor: Zotero.EditorInstance, + itemID: number + ) { // Update current line index const _window = editor._iframeWindow; const selection = _window.document.getSelection(); @@ -772,12 +775,9 @@ class NoteUtils extends AddonBase { } } } - this._Addon.toolkit.Tool.log(`line ${currentLineIndex} selected.`); - // Zotero.debug( - // `Current Element: ${focusNode.outerHTML}; Real Element: ${realElement.outerHTML}` - // ); - this.currentLine[editor._item.id] = currentLineIndex; - // this._Addon.toolkit.Tool.log(realElement); + this._Addon.toolkit.Tool.log(`line ${currentLineIndex} of item ${itemID} selected.`); + // Don't use the instance._item.id, as it might not be updated. + this.currentLine[itemID] = currentLineIndex; if (realElement.tagName === "A") { let link = (realElement as HTMLLinkElement).href; let linkedNote = (await this.getNoteFromLink(link)).item; diff --git a/src/workspace/workspaceWindow.ts b/src/workspace/workspaceWindow.ts index 22b6546..b66ec73 100644 --- a/src/workspace/workspaceWindow.ts +++ b/src/workspace/workspaceWindow.ts @@ -76,7 +76,7 @@ class WorkspaceWindow extends AddonBase { Zotero_Tabs.jump(0); let { id, container } = Zotero_Tabs.add({ type: "betternotes", - title: Zotero.locale.includes("zh") ? "工作区" : "Workspace", + title: this._Addon.Locale.getString("library.workspace"), index: 1, data: {}, select: select, diff --git a/src/zotero/events.ts b/src/zotero/events.ts index 7eb4791..6ce7076 100644 --- a/src/zotero/events.ts +++ b/src/zotero/events.ts @@ -22,6 +22,7 @@ class ZoteroEvents extends AddonBase { this._Addon.toolkit.Tool.logOptionsGlobal.disableConsole = this._Addon.env === "production"; this._Addon.toolkit.Tool.log("init called"); + this._Addon.Locale.initLocale(); this.initProxyHandler(); this.addEditorInstanceListener(); @@ -91,6 +92,7 @@ class ZoteroEvents extends AddonBase { "Recovering Note Workspace Failed", e ); + this._Addon.toolkit.Tool.log(e); } await Zotero.Promise.delay(1000); } @@ -130,18 +132,27 @@ class ZoteroEvents extends AddonBase { await this._Addon.EditorViews.initEditor(instance); this._Addon.toolkit.Tool.log("note editor initialized."); + const currentID = instance._item.id; + if ( instance._iframeWindow.document.body.getAttribute( "betternotes-status" - ) !== "initialized" + ) !== String(currentID) ) { // Put event listeners here to access Zotero instance instance._iframeWindow.document.addEventListener( "selectionchange", - async (e) => { + async (e: Event) => { e.stopPropagation(); e.preventDefault(); - await this._Addon.NoteUtils.onSelectionChange(instance); + await this._Addon.NoteUtils.onSelectionChange( + instance, + parseInt( + instance._iframeWindow.document.body.getAttribute( + "betternotes-status" + ) + ) + ); } ); instance._iframeWindow.document.addEventListener("click", async (e) => { @@ -250,14 +261,16 @@ class ZoteroEvents extends AddonBase { }); instance._iframeWindow.document.body.setAttribute( "betternotes-status", - "initialized" + String(instance._item.id) ); } - instance._popup.setAttribute( - "onpopupshowing", - "Zotero.BetterNotes.EditorViews.updatePopupMenu()" - ); + instance._popup.addEventListener("popupshowing", (e) => { + if (e.originalTarget !== instance._popup) { + return; + } + this._Addon.EditorViews.updatePopupMenu(); + }); instance._iframeWindow.addEventListener("mousedown", (e) => { this._Addon.EditorController.activeEditor = instance; @@ -351,7 +364,11 @@ class ZoteroEvents extends AddonBase { return; } const res = confirm( - `Will create a new note under collection '${currentCollection.getName()}' and set it the main note. Continue?` + `${this._Addon.Locale.getString( + "library.newMainNote.confirmHead" + )} '${currentCollection.getName()}' ${this._Addon.Locale.getString( + "library.newMainNote.confirmTail" + )}` ); if (!res) { return; @@ -936,8 +953,12 @@ class ZoteroEvents extends AddonBase { new EditorMessage("export", { params: { item: noteItems[0] } }) ); } else { - const useSingleFile = confirm("Export linked notes to markdown files?"); - const withMeta = confirm("With YAML header?"); + const useSingleFile = confirm( + this._Addon.Locale.getString("export.withLinkedNotes.confirm") + ); + const withMeta = confirm( + this._Addon.Locale.getString("export.withYAML.confirm") + ); await this._Addon.NoteExport.exportNotesToMDFiles(noteItems, { useEmbed: !useSingleFile, withMeta: withMeta, diff --git a/src/zotero/locale.ts b/src/zotero/locale.ts new file mode 100644 index 0000000..21b39d1 --- /dev/null +++ b/src/zotero/locale.ts @@ -0,0 +1,18 @@ +import AddonModule from "../module"; +import { addonRef } from "../../package.json"; + +class AddonLocale extends AddonModule { + private stringBundle: any; + + public initLocale() { + this.stringBundle = Components.classes["@mozilla.org/intl/stringbundle;1"] + .getService(Components.interfaces.nsIStringBundleService) + .createBundle(`chrome://${addonRef}/locale/addon.properties`); + } + + public getString(localString: string): string { + return this.stringBundle.GetStringFromName(localString); + } +} + +export default AddonLocale; diff --git a/src/zotero/views.ts b/src/zotero/views.ts index 7a90587..3309085 100644 --- a/src/zotero/views.ts +++ b/src/zotero/views.ts @@ -64,54 +64,27 @@ class ZoteroViews extends AddonBase { } public addNewMainNoteButton() { - // Top toolbar button - let addNoteItem = document - .getElementById("zotero-tb-note-add") - .getElementsByTagName("menuitem")[1]; - let buttons = this._Addon.toolkit.UI.creatElementsFromJSON(document, { - tag: "fragment", - subElementOptions: [ - { - tag: "menuitem", - id: "zotero-tb-knowledge-create-mainnote", - attributes: { - label: "New Main Note", - class: "menuitem-iconic", - style: - "list-style-image: url('chrome://Knowledge4Zotero/skin/favicon.png');", - }, - listeners: [ - { - type: "click", - listener: (e) => { - this._Addon.ZoteroEvents.onEditorEvent( - new EditorMessage("createWorkspace", {}) - ); - }, - }, - ], - }, - { - tag: "menuitem", - id: "zotero-tb-knowledge-import-md", - attributes: { - label: "Import MarkDown as Note", - class: "menuitem-iconic", - style: - "list-style-image: url('chrome://Knowledge4Zotero/skin/favicon.png');", - }, - listeners: [ - { - type: "click", - listener: async (e) => { - await this._Addon.NoteImport.doImport(); - }, - }, - ], - }, - ], + const menupopup = document + .querySelector("#zotero-tb-note-add") + .querySelector("menupopup") as XUL.MenuPopup; + this._Addon.toolkit.UI.insertMenuItem(menupopup, { + tag: "menuitem", + label: this._Addon.Locale.getString("library.newMainNote"), + icon: "chrome://Knowledge4Zotero/skin/favicon.png", + commandListener: (e) => { + this._Addon.ZoteroEvents.onEditorEvent( + new EditorMessage("createWorkspace", {}) + ); + }, + }); + this._Addon.toolkit.UI.insertMenuItem(menupopup, { + tag: "menuitem", + label: this._Addon.Locale.getString("library.importMD"), + icon: "chrome://Knowledge4Zotero/skin/favicon.png", + commandListener: async (e) => { + await this._Addon.NoteImport.doImport(); + }, }); - addNoteItem.after(buttons); } public addOpenWorkspaceButton() { @@ -198,9 +171,7 @@ class ZoteroViews extends AddonBase { style: "margin-left: 6px;", }, directAttributes: { - innerHTML: Zotero.locale.includes("zh") - ? "打开工作区" - : "Open Workspace", + innerHTML: this._Addon.Locale.getString("library.openWorkspace"), }, }, ], @@ -211,13 +182,13 @@ class ZoteroViews extends AddonBase { } public updateTemplateMenu( - type: "Note" | "Item" | "Text", - _document: Document, - prefix: string = "", + event: Event, + type: "Item" | "Text", useMainNote: boolean = true ) { - _document = - _document || this._Addon.WorkspaceMenu.getWorkspaceMenuWindow().document; + // @ts-ignore + const menupopup = event.originalTarget as XUL.MenuPopup; + const _document = menupopup.ownerDocument; // If no note is activated, use copy const targetItemId = @@ -229,17 +200,14 @@ class ZoteroViews extends AddonBase { : Zotero_Tabs.selectedID === this._Addon.WorkspaceWindow.workspaceTabId ? this._Addon.WorkspaceWindow.getWorkspaceNote().id : -1; - this._Addon.toolkit.Tool.log(`updateTemplateMenu`); + this._Addon.toolkit.Tool.log("updateTemplateMenu"); let templates = this._Addon.TemplateController.getTemplateKeys() .filter((e) => e.name.indexOf(type) !== -1) .filter( (e) => !this._Addon.TemplateController._systemTemplateNames.includes(e.name) ); - const popup = _document.getElementById( - `menu_insert${prefix}${type}TemplatePopup` - ); - popup.innerHTML = ""; + menupopup.innerHTML = ""; if (templates.length === 0) { templates = [ { @@ -250,28 +218,32 @@ class ZoteroViews extends AddonBase { ]; } for (const template of templates) { - const menuitem = this._Addon.toolkit.UI.createElement( - _document, - "menuitem", - "xul" - ) as XUL.MenuItem; - // menuitem.setAttribute("id", template.name); - menuitem.setAttribute("label", template.name); - menuitem.setAttribute( - "oncommand", - ` - Zotero.BetterNotes.ZoteroEvents.onEditorEvent({ - type: "insert${type}UsingTemplate", - content: { - params: { templateName: "${template.name}", targetItemId: ${targetItemId}, useMainNote: ${useMainNote} }, + const menuitem = this._Addon.toolkit.UI.creatElementsFromJSON(_document, { + tag: "menuitem", + namespace: "xul", + attributes: { + label: template.name, + disabled: template.disabled, + }, + listeners: [ + { + type: "command", + listener: (e) => { + this._Addon.ZoteroEvents.onEditorEvent({ + type: `insert${type}UsingTemplate`, + content: { + params: { + templateName: template.name, + targetItemId, + useMainNote, + }, + }, + }); + }, }, - });` - ); - - if (template.disabled) { - menuitem.setAttribute("disabled", true as any); - } - popup.append(menuitem); + ], + }) as XUL.MenuItem; + menupopup.append(menuitem); } }