From 44b5a0dfa45dcb5dde51694cfe3292924ff9ccd3 Mon Sep 17 00:00:00 2001 From: xiangyu <3170102889@zju.edu.cn> Date: Sat, 15 Oct 2022 00:51:38 +0800 Subject: [PATCH] add: note editor right-click menu --- addon/defaults/preferences/defaults.js | 3 + src/editor/editorController.ts | 1 + src/editor/editorViews.ts | 117 +++++++++++++++++++++++++ src/zotero/events.ts | 42 +++++++-- src/zotero/views.ts | 36 +++++--- 5 files changed, 176 insertions(+), 23 deletions(-) diff --git a/addon/defaults/preferences/defaults.js b/addon/defaults/preferences/defaults.js index 55c7b35..3e8cea9 100644 --- a/addon/defaults/preferences/defaults.js +++ b/addon/defaults/preferences/defaults.js @@ -17,3 +17,6 @@ pref("extensions.zotero.Knowledge4Zotero.OCRMathpix.Appkey", ""); pref("extensions.zotero.Knowledge4Zotero.OCRXunfei.APPID", ""); pref("extensions.zotero.Knowledge4Zotero.OCRMathpix.APISecret", ""); pref("extensions.zotero.Knowledge4Zotero.OCRMathpix.APIKey", ""); +pref("extensions.zotero.Knowledge4Zotero.linkAction.click", ""); +pref("extensions.zotero.Knowledge4Zotero.linkAction.shiftclick", ""); +pref("extensions.zotero.Knowledge4Zotero.linkAction.ctrlclick", ""); diff --git a/src/editor/editorController.ts b/src/editor/editorController.ts index 6abf47b..aaeedb0 100644 --- a/src/editor/editorController.ts +++ b/src/editor/editorController.ts @@ -11,6 +11,7 @@ class EditorController extends AddonBase { time: number; }>; editorPromise: ZoteroPromise; + activeEditor: Zotero.EditorInstance; constructor(parent: Knowledge4Zotero) { super(parent); diff --git a/src/editor/editorViews.ts b/src/editor/editorViews.ts index 004a53b..3b8b589 100644 --- a/src/editor/editorViews.ts +++ b/src/editor/editorViews.ts @@ -864,6 +864,123 @@ class EditorViews extends AddonBase { } } + public updatePopupMenu() { + console.log("updating editor popup"); + const instance = this._Addon.EditorController.activeEditor; + const noteItem = instance._item; + + const copyLinkId = "menupopup-copylink"; + if (!instance._popup.querySelector(`#${copyLinkId}`)) { + const copyLinkMenu = + instance._popup.ownerDocument.createElement("menuitem"); + copyLinkMenu.id = copyLinkId; + copyLinkMenu.setAttribute("label", "Copy Note Link"); + copyLinkMenu.addEventListener("command", (e) => { + const linkText = this._Addon.NoteUtils.getNoteLink(noteItem); + const linkHTML = `
${ + noteItem.getNoteTitle().trim() + ? noteItem.getNoteTitle().trim() + : linkText + }
`; + + new CopyHelper() + .addText(linkText, "text/unicode") + .addText(linkHTML, "text/html") + .copy(); + this._Addon.ZoteroViews.showProgressWindow( + "Better Notes", + "Note Link Copied" + ); + }); + instance._popup.append(copyLinkMenu); + } + + const copyLinkAtLineId = "menupopup-copylinkline"; + if (!instance._popup.querySelector(`#${copyLinkAtLineId}`)) { + const copyLinkAtLineMenu = + instance._popup.ownerDocument.createElement("menuitem"); + copyLinkAtLineMenu.id = copyLinkAtLineId; + copyLinkAtLineMenu.setAttribute( + "label", + `Copy Note Link of Line ${ + this._Addon.NoteUtils.currentLine[noteItem.id] + 1 + }` + ); + copyLinkAtLineMenu.addEventListener("command", (e) => { + const linkText = this._Addon.NoteUtils.getNoteLink(noteItem, { + withLine: true, + }); + const linkHTML = `${ + noteItem.getNoteTitle().trim() + ? noteItem.getNoteTitle().trim() + : linkText + }
`; + new CopyHelper() + .addText(linkText, "text/unicode") + .addText(linkHTML, "text/html") + .copy(); + this._Addon.ZoteroViews.showProgressWindow( + "Better Notes", + `Note Link of Line ${ + this._Addon.NoteUtils.currentLine[noteItem.id] + 1 + } Copied` + ); + }); + instance._popup.append(copyLinkAtLineMenu); + } + + const templateTextId = "menupopup-insertTextTemplate"; + if (!instance._popup.querySelector(`#${templateTextId}`)) { + const templateTextMenu = + instance._popup.ownerDocument.createElement("menu"); + templateTextMenu.id = templateTextId; + templateTextMenu.setAttribute("label", "Insert Template (Text)"); + const templateTextMenuPopup = + instance._popup.ownerDocument.createElement("menupopup"); + templateTextMenuPopup.id = `menu_insert${instance._item.id}TextTemplatePopup`; + templateTextMenuPopup.setAttribute( + "onpopupshowing", + `Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Text', Zotero.Knowledge4Zotero.EditorController.activeEditor._popup.ownerDocument, '${instance._item.id}');` + ); + templateTextMenu.append(templateTextMenuPopup); + instance._popup.append(templateTextMenu); + } + + const templateNoteId = "menupopup-insertNoteTemplate"; + if (!instance._popup.querySelector(`#${templateNoteId}`)) { + const templateNoteMenu = + instance._popup.ownerDocument.createElement("menu"); + templateNoteMenu.id = templateNoteId; + templateNoteMenu.setAttribute("label", "Insert Template (Note)"); + const templateNoteMenuPopup = + instance._popup.ownerDocument.createElement("menupopup"); + templateNoteMenuPopup.id = `menu_insert${instance._item.id}NoteTemplatePopup`; + templateNoteMenuPopup.setAttribute( + "onpopupshowing", + `Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Note', Zotero.Knowledge4Zotero.EditorController.activeEditor._popup.ownerDocument, ${instance._item.id});` + ); + templateNoteMenu.append(templateNoteMenuPopup); + instance._popup.append(templateNoteMenu); + } + + const templateItemId = "menupopup-insertItemTemplate"; + if (!instance._popup.querySelector(`#${templateItemId}`)) { + const templateItemMenu = + instance._popup.ownerDocument.createElement("menu"); + templateItemMenu.id = templateItemId; + templateItemMenu.setAttribute("label", "Insert Template (Item)"); + const templateItemMenuPopup = + instance._popup.ownerDocument.createElement("menupopup"); + templateItemMenuPopup.id = `menu_insert${instance._item.id}ItemTemplatePopup`; + templateItemMenuPopup.setAttribute( + "onpopupshowing", + `Zotero.Knowledge4Zotero.ZoteroViews.updateTemplateMenu('Item', Zotero.Knowledge4Zotero.EditorController.activeEditor._popup.ownerDocument, ${instance._item.id});` + ); + templateItemMenu.append(templateItemMenuPopup); + instance._popup.append(templateItemMenu); + } + } + public async scrollToLine( instance: Zotero.EditorInstance, lineIndex: number diff --git a/src/zotero/events.ts b/src/zotero/events.ts index 80e62aa..da0e656 100644 --- a/src/zotero/events.ts +++ b/src/zotero/events.ts @@ -335,6 +335,15 @@ class ZoteroEvents extends AddonBase { return; } + instance._popup.setAttribute( + "onpopupshowing", + "Zotero.Knowledge4Zotero.EditorViews.updatePopupMenu()" + ); + + instance._iframeWindow.addEventListener("mousedown", (e) => { + this._Addon.EditorController.activeEditor = instance; + }); + instance._knowledgeUIInitialized = true; this._Addon.EditorController.recordEditor(instance); @@ -777,10 +786,13 @@ class ZoteroEvents extends AddonBase { } else if (message.type === "insertTextUsingTemplate") { /* message.content = { - params: {templateName, copy} + params: {templateName, targetItemId} } */ const newLines: string[] = []; + const targetItem = Zotero.Items.get( + message.content.params.targetItemId + ) as Zotero.Item; const progressWindow = this._Addon.ZoteroViews.showProgressWindow( "Running Template", @@ -797,7 +809,7 @@ class ZoteroEvents extends AddonBase { newLines.push(renderredTemplate); newLines.push(""); const html = newLines.join("\n"); - if (message.content.params.copy) { + if (!targetItem) { console.log(html); new CopyHelper() .addText(html, "text/html") @@ -806,7 +818,12 @@ class ZoteroEvents extends AddonBase { progressWindow.changeHeadline("Template Copied"); } else { // End of line - await this._Addon.NoteUtils.addLineToNote(mainNote, html, -1, false); + await this._Addon.NoteUtils.addLineToNote( + targetItem, + html, + -1, + false + ); progressWindow.changeHeadline("Running Template Finished"); } } else { @@ -819,6 +836,10 @@ class ZoteroEvents extends AddonBase { params: {templateName} } */ + const targetItem = Zotero.Items.get( + message.content.params.targetItemId + ) as Zotero.Item; + const ids = await this._Addon.ZoteroViews.openSelectItemsWindow(); const items = (Zotero.Items.get(ids) as Zotero.Item[]).filter( (item: Zotero.Item) => item.isRegularItem() @@ -904,7 +925,7 @@ class ZoteroEvents extends AddonBase { if (newLines) { const html = newLines.join("\n"); - if (message.content.params.copy) { + if (!targetItem) { console.log(html); new CopyHelper() @@ -916,14 +937,14 @@ class ZoteroEvents extends AddonBase { const forceMetadata = toCopyImage.length > 0; console.log(toCopyImage); await this._Addon.NoteUtils.addLineToNote( - mainNote, + targetItem, html, -1, forceMetadata ); await Zotero.DB.executeTransaction(async () => { for (const subNote of toCopyImage) { - await Zotero.Notes.copyEmbeddedImages(subNote, mainNote); + await Zotero.Notes.copyEmbeddedImages(subNote, targetItem); } }); progressWindow.changeHeadline("Running Template Finished"); @@ -938,6 +959,9 @@ class ZoteroEvents extends AddonBase { params: {templateName} } */ + const targetItem = Zotero.Items.get( + message.content.params.targetItemId + ) as Zotero.Item; const ids = await this._Addon.ZoteroViews.openSelectItemsWindow(); const notes = (Zotero.Items.get(ids) as Zotero.Item[]).filter( (item: Zotero.Item) => item.isNote() @@ -1027,7 +1051,7 @@ class ZoteroEvents extends AddonBase { if (newLines) { const html = newLines.join("\n"); - if (message.content.params.copy) { + if (!targetItem) { console.log(html); new CopyHelper() @@ -1039,14 +1063,14 @@ class ZoteroEvents extends AddonBase { const forceMetadata = toCopyImage.length > 0; console.log(toCopyImage); await this._Addon.NoteUtils.addLineToNote( - mainNote, + targetItem, html, -1, forceMetadata ); await Zotero.DB.executeTransaction(async () => { for (const subNote of toCopyImage) { - await Zotero.Notes.copyEmbeddedImages(subNote, mainNote); + await Zotero.Notes.copyEmbeddedImages(subNote, targetItem); } }); progressWindow.changeHeadline("Running Template Finished"); diff --git a/src/zotero/views.ts b/src/zotero/views.ts index 5cfd29b..f901238 100644 --- a/src/zotero/views.ts +++ b/src/zotero/views.ts @@ -145,16 +145,24 @@ class ZoteroViews extends AddonBase { .children[0].before(treeRow); } - public updateTemplateMenu(type: "Note" | "Item" | "Text") { - const _window = this._Addon.WorkspaceMenu.getWorkspaceMenuWindow(); + public updateTemplateMenu( + type: "Note" | "Item" | "Text", + _document: Document, + prefix: string = "" + ) { + _document = + _document || this._Addon.WorkspaceMenu.getWorkspaceMenuWindow().document; - // If tab is open but not selected, we use copy mode - const copyMode = - Boolean( - this._Addon.WorkspaceWindow.workspaceTabId && - this._Addon.WorkspaceWindow.workspaceTabId !== "WINDOW" && - Zotero_Tabs.selectedID !== this._Addon.WorkspaceWindow.workspaceTabId - ) || !this._Addon.WorkspaceWindow.workspaceTabId; + // If no note is activated, use copy + const targetItemId = + this._Addon.EditorController.activeEditor && + Zotero.Notes._editorInstances.includes( + this._Addon.EditorController.activeEditor + ) + ? this._Addon.EditorController.activeEditor._item.id + : Zotero_Tabs.selectedID === this._Addon.WorkspaceWindow.workspaceTabId + ? this._Addon.WorkspaceWindow.getWorkspaceNote().id + : -1; Zotero.debug(`updateTemplateMenu`); let templates = this._Addon.TemplateController.getTemplateKeys() .filter((e) => e.name.indexOf(type) !== -1) @@ -162,8 +170,8 @@ class ZoteroViews extends AddonBase { (e) => !this._Addon.TemplateController._systemTemplateNames.includes(e.name) ); - const popup = _window.document.getElementById( - `menu_insert${type}TemplatePopup` + const popup = _document.getElementById( + `menu_insert${prefix}${type}TemplatePopup` ); popup.innerHTML = ""; if (templates.length === 0) { @@ -176,8 +184,8 @@ class ZoteroViews extends AddonBase { ]; } for (const template of templates) { - const menuitem = _window.document.createElement("menuitem"); - menuitem.setAttribute("id", template.name); + const menuitem = _document.createElement("menuitem"); + // menuitem.setAttribute("id", template.name); menuitem.setAttribute("label", template.name); menuitem.setAttribute( "oncommand", @@ -185,7 +193,7 @@ class ZoteroViews extends AddonBase { Zotero.Knowledge4Zotero.ZoteroEvents.onEditorEvent({ type: "insert${type}UsingTemplate", content: { - params: { templateName: "${template.name}", copy: ${copyMode} }, + params: { templateName: "${template.name}", targetItemId: ${targetItemId} }, }, });` );