From 1f2ea0111bd378952c8e659d35989bb9d3b4ac44 Mon Sep 17 00:00:00 2001 From: xiangyu <3170102889@zju.edu.cn> Date: Wed, 4 May 2022 14:25:29 +0800 Subject: [PATCH] add: annotation to note --- .gitattributes | 2 +- src/events.ts | 79 +++++++++++++++++++++++++++++++++++++-- src/views.ts | 92 ++++++++++++++++++++++++++++++++++++++++++++++ typing/global.d.ts | 1 + 4 files changed, 169 insertions(+), 5 deletions(-) diff --git a/.gitattributes b/.gitattributes index 4fc5e01..ac7645d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -addon/chrome/content/lib/* linguist-vendored +addon/chrome/content/lib linguist-vendored diff --git a/src/events.ts b/src/events.ts index a42e5bc..32ec7b3 100644 --- a/src/events.ts +++ b/src/events.ts @@ -11,9 +11,31 @@ class AddonEvents extends AddonBase { ids: Array, extraData: object ) => { - if (event == "modify") { - Zotero.debug("Knowledge4Zotero: main knowledge midified."); - this._Addon.views.buildOutline(); + if (event === "modify" && type === "item") { + if ( + ids.indexOf(Zotero.Prefs.get("Knowledge4Zotero.mainKnowledgeID")) >= + 0 + ) { + Zotero.debug("Knowledge4Zotero: main knowledge modify check."); + this._Addon.views.buildOutline(); + } + } + if ( + (event == "select" && + type == "tab" && + extraData[ids[0]].type == "reader") || + (event === "add" && + type === "item" && + Zotero.Items.get(ids).filter((item) => { + item.isAnnotation(); + }).length > 0) || + (event === "close" && type === "tab") || + (event === "open" && type === "file") + ) { + Zotero.debug("Knowledge4Zotero: buildReaderAnnotationButton"); + this.onEditorEvent( + new EditorMessage("buildReaderAnnotationButton", {}) + ); } }, }; @@ -27,6 +49,8 @@ class AddonEvents extends AddonBase { // Register the callback in Zotero as an item observer let notifierID = Zotero.Notifier.registerObserver(this.notifierCallback, [ "item", + "tab", + "file", ]); // Unregister callback when the window closes (important to avoid a memory leak) @@ -432,7 +456,7 @@ class AddonEvents extends AddonBase { )) { Zotero.debug(attchment); try { - await Zotero.OpenPDF.openToPage(attchment); + await Zotero.OpenPDF.openToPage(attchment, 0); successCount += 1; } catch (e) { Zotero.debug("Knowledge4Zotero: Open attachment failed:"); @@ -450,6 +474,53 @@ class AddonEvents extends AddonBase { "fail" ); } + } else if (message.type === "buildReaderAnnotationButton") { + /* + message.content = {} + */ + for (const reader of Zotero.Reader._readers) { + Zotero.debug("reader found"); + let t = 0; + while ( + t < 100 && + !(await this._Addon.views.addReaderAnnotationButton(reader)) + ) { + await Zotero.Promise.delay(50); + t += 1; + } + } + } else if (message.type === "addAnnotationNote") { + /* + message.content = { + params: annotations of Reader JSON type + } + */ + const annotations = message.content.params; + + const note: ZoteroItem = new Zotero.Item("note"); + note.parentID = Zotero.Items.get( + annotations[0].attachmentItemID + ).parentID; + await note.saveTx(); + ZoteroPane.openNoteWindow(note.id); + let t = 0; + while (t < 100 && !ZoteroPane.findNoteWindow(note.id)) { + await Zotero.Promise.delay(50); + t += 1; + } + const _window = ZoteroPane.findNoteWindow(note.id); + + const noteEditor = _window.document.getElementById("zotero-note-editor"); + + t = 0; + while (!noteEditor.getCurrentInstance() && t < 500) { + t += 1; + await Zotero.Promise.delay(10); + } + const editorInstance = noteEditor.getCurrentInstance(); + Zotero.debug(editorInstance); + editorInstance.focus(); + editorInstance.insertAnnotations(annotations); } else { Zotero.debug(`Knowledge4Zotero: message not handled.`); } diff --git a/src/views.ts b/src/views.ts index c4a53f5..ebafeb9 100644 --- a/src/views.ts +++ b/src/views.ts @@ -17,6 +17,7 @@ class AddonViews extends AddonBase { notMainKnowledge: ``, isMainKnowledge: ``, jumpAttachment: ``, + addAnnotationNote: ``, export: ``, close: ``, openWorkspaceCollectionView: ``, @@ -211,6 +212,97 @@ class AddonViews extends AddonBase { .children[0].before(treeRow); } + async addReaderAnnotationButton(reader: ReaderObj) { + if (!reader) { + return false; + } + await reader._initPromise; + let updateCount = 0; + const _document = reader._iframeWindow.document; + for (const moreButton of _document.getElementsByClassName("more")) { + if (moreButton.getAttribute("knowledgeinit") === "true") { + updateCount += 1; + continue; + } + moreButton.setAttribute("knowledgeinit", "true"); + const addAnnotationNoteButton = _document.createElement("button"); + addAnnotationNoteButton.innerHTML = this.editorIcon["addAnnotationNote"]; + + let annotationWrapper = moreButton; + while (!annotationWrapper.getAttribute("data-sidebar-annotation-id")) { + annotationWrapper = annotationWrapper.parentElement; + } + const itemKey = annotationWrapper.getAttribute( + "data-sidebar-annotation-id" + ); + const libraryID = Zotero.Items.get(reader.itemID).libraryID; + const annotationItem = await Zotero.Items.getByLibraryAndKeyAsync( + libraryID, + itemKey + ); + + const annotations = [await reader._getAnnotation(annotationItem)].map( + ({ + id, + type, + text, + color, + comment, + image, + position, + pageLabel, + tags, + }) => { + if (image) { + let img = _document.querySelector( + `[data-sidebar-annotation-id="${id}"] img` + ); + if (img) { + function getImageDataURL(img) { + var canvas = _document.createElement("canvas"); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight); + return canvas.toDataURL("image/png"); + } + image = getImageDataURL(img); + } + } + return { + id, + type, + attachmentItemID: Zotero.Reader._readers[0].itemID, + text: text ? text.trim() : text, + color, + comment: comment ? comment.trim() : comment, + image, + position, + pageLabel, + tags, + }; + } + ); + addAnnotationNoteButton.addEventListener("click", (e) => { + this._Addon.events.onEditorEvent( + new EditorMessage("addAnnotationNote", { + params: annotations, + }) + ); + e.preventDefault(); + }); + addAnnotationNoteButton.addEventListener("mouseover", (e: XULEvent) => { + e.target.setAttribute("style", "background: #F0F0F0;"); + }); + addAnnotationNoteButton.addEventListener("mouseout", (e: XULEvent) => { + e.target.removeAttribute("style"); + }); + moreButton.before(addAnnotationNoteButton); + updateCount += 1; + } + return reader.annotationItemIDs.length === updateCount; + } + async buildOutline(note: ZoteroItem) { this._Addon.knowledge.currentNodeID = -1; let treeList = this._Addon.knowledge.getNoteTreeAsList(note); diff --git a/typing/global.d.ts b/typing/global.d.ts index 269666a..03ac687 100644 --- a/typing/global.d.ts +++ b/typing/global.d.ts @@ -167,6 +167,7 @@ declare class ReaderObj { [attr: string]: any; itemID: number; _iframeWindow: XULWindow; + _initPromise: Promise; } declare class EditorInstance {