diff --git a/addon/chrome/content/workspace.xul b/addon/chrome/content/workspace.xul index 05935a6..b03041b 100644 --- a/addon/chrome/content/workspace.xul +++ b/addon/chrome/content/workspace.xul @@ -46,9 +46,18 @@ -
-
-
+
+
+ Add Heading +
+
+
+ Raise the selected Heading level +
+
+
+ Decrease the selected Heading level +
diff --git a/addon/chrome/skin/default/Knowledge4Zotero/favicon.png b/addon/chrome/skin/default/Knowledge4Zotero/favicon.png index 8773692..f6232b3 100644 Binary files a/addon/chrome/skin/default/Knowledge4Zotero/favicon.png and b/addon/chrome/skin/default/Knowledge4Zotero/favicon.png differ diff --git a/addon/chrome/skin/default/Knowledge4Zotero/favicon@2x.png b/addon/chrome/skin/default/Knowledge4Zotero/favicon@2x.png index 9b993e9..72e8eea 100644 Binary files a/addon/chrome/skin/default/Knowledge4Zotero/favicon@2x.png and b/addon/chrome/skin/default/Knowledge4Zotero/favicon@2x.png differ diff --git a/addon/chrome/skin/default/Knowledge4Zotero/knowledge.png b/addon/chrome/skin/default/Knowledge4Zotero/knowledge.png new file mode 100644 index 0000000..8773692 Binary files /dev/null and b/addon/chrome/skin/default/Knowledge4Zotero/knowledge.png differ diff --git a/addon/chrome/skin/default/Knowledge4Zotero/favicon@0.5x.png b/addon/chrome/skin/default/Knowledge4Zotero/knowledge@0.5x.png similarity index 100% rename from addon/chrome/skin/default/Knowledge4Zotero/favicon@0.5x.png rename to addon/chrome/skin/default/Knowledge4Zotero/knowledge@0.5x.png diff --git a/addon/chrome/skin/default/Knowledge4Zotero/knowledge@2x.png b/addon/chrome/skin/default/Knowledge4Zotero/knowledge@2x.png new file mode 100644 index 0000000..9b993e9 Binary files /dev/null and b/addon/chrome/skin/default/Knowledge4Zotero/knowledge@2x.png differ diff --git a/addon/chrome/skin/default/Knowledge4Zotero/workspace.css b/addon/chrome/skin/default/Knowledge4Zotero/workspace.css index f31ad85..a031e5a 100644 --- a/addon/chrome/skin/default/Knowledge4Zotero/workspace.css +++ b/addon/chrome/skin/default/Knowledge4Zotero/workspace.css @@ -33,3 +33,29 @@ ul, li { display: list-item; } + +.tooltip { + position: relative; + display: inline-block; + border-bottom: 1px dotted black; +} + +.tooltip .tooltiptext { + visibility: hidden; + width: 120px; + background-color: black; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 5px 0; + + position: absolute; + z-index: 1; + bottom: 100%; + left: 50%; + margin-left: -60px; +} + +.tooltip:hover .tooltiptext { + visibility: visible; +} diff --git a/src/events.ts b/src/events.ts index 32ec7b3..53f608c 100644 --- a/src/events.ts +++ b/src/events.ts @@ -27,7 +27,7 @@ class AddonEvents extends AddonBase { (event === "add" && type === "item" && Zotero.Items.get(ids).filter((item) => { - item.isAnnotation(); + return item.isAnnotation(); }).length > 0) || (event === "close" && type === "tab") || (event === "open" && type === "file") @@ -45,6 +45,7 @@ class AddonEvents extends AddonBase { Zotero.debug("Knowledge4Zotero: init called"); await Zotero.uiReadyPromise; this._Addon.views.addOpenWorkspaceButton(); + this._Addon.views.addNewKnowledgeButton(); this.addEditorInstanceListener(); // Register the callback in Zotero as an item observer let notifierID = Zotero.Notifier.registerObserver(this.notifierCallback, [ @@ -114,6 +115,17 @@ class AddonEvents extends AddonBase { message.content = {} */ await this._Addon.knowledge.openWorkspaceWindow(); + } else if (message.type === "createWorkspace") { + /* + message.content = {} + */ + const noteID = await ZoteroPane_Local.newNote(); + await this.onEditorEvent( + new EditorMessage("setMainKnowledge", { + params: noteID, + }) + ); + await this._Addon.knowledge.openWorkspaceWindow(); } else if (message.type === "addNoteInstance") { /* message.content = { @@ -224,9 +236,9 @@ class AddonEvents extends AddonBase { // This is a preview knowledge, hide openWorkspace button add show close botton this._Addon.views.changeEditorButtonView( _window.document.getElementById("knowledge-start"), - "jumpAttachment", + "openAttachment", "Open Note Attachments", - "jumpAttachment" + "openAttachment" ); this._Addon.views.changeEditorButtonView( _window.document.getElementById("knowledge-end"), @@ -298,21 +310,6 @@ class AddonEvents extends AddonBase { } Zotero.Prefs.set("Knowledge4Zotero.mainKnowledgeID", itemID); await this._Addon.knowledge.setWorkspaceNote("main"); - for (let editor of Zotero.Notes._editorInstances) { - await editor._initPromise; - let isMainKnowledge = editor._item.id === mainKnowledgeID; - let button = - editor._iframeWindow.document.getElementById("knowledge-start"); - if (button) { - this._Addon.views.changeEditorButtonView( - button, - isMainKnowledge ? "isMainKnowledge" : "notMainKnowledge", - isMainKnowledge - ? "Edit the main knowledge in Workspace" - : "Open Workspace" - ); - } - } } } else if (message.type === "clickOutlineHeading") { /* @@ -441,7 +438,7 @@ class AddonEvents extends AddonBase { await this._Addon.knowledge.exportNoteToFile( message.content.editorInstance._item ); - } else if (message.type === "jumpAttachment") { + } else if (message.type === "openAttachment") { /* message.content = { editorInstance @@ -453,10 +450,17 @@ class AddonEvents extends AddonBase { if (note.parentItem) { for (const attchment of Zotero.Items.get( note.parentItem.getAttachments() - )) { + ).filter((item: ZoteroItem) => { + return item.isPDFAttachment(); + })) { Zotero.debug(attchment); try { - await Zotero.OpenPDF.openToPage(attchment, 0); + Zotero.debug("Launching PDF without page number"); + let zp = Zotero.getActiveZoteroPane(); + if (zp) { + zp.viewAttachment([attchment.id]); + } + Zotero.Notifier.trigger("open", "file", attchment.id); successCount += 1; } catch (e) { Zotero.debug("Knowledge4Zotero: Open attachment failed:"); @@ -492,15 +496,21 @@ class AddonEvents extends AddonBase { } else if (message.type === "addAnnotationNote") { /* message.content = { - params: annotations of Reader JSON type + params: { annotations: Reader JSON type, annotationItem } } */ - const annotations = message.content.params; + const annotations = message.content.params.annotations; + const annotationItem: ZoteroItem = message.content.params.annotationItem; const note: ZoteroItem = new Zotero.Item("note"); note.parentID = Zotero.Items.get( annotations[0].attachmentItemID ).parentID; + if (annotationItem.annotationComment) { + note.setNote( + `

${annotationItem.annotationComment}

\n
` + ); + } await note.saveTx(); ZoteroPane.openNoteWindow(note.id); let t = 0; @@ -518,9 +528,8 @@ class AddonEvents extends AddonBase { await Zotero.Promise.delay(10); } const editorInstance = noteEditor.getCurrentInstance(); - Zotero.debug(editorInstance); editorInstance.focus(); - editorInstance.insertAnnotations(annotations); + await editorInstance.insertAnnotations(annotations); } else { Zotero.debug(`Knowledge4Zotero: message not handled.`); } diff --git a/src/knowledge.ts b/src/knowledge.ts index a0902c4..e0e376b 100644 --- a/src/knowledge.ts +++ b/src/knowledge.ts @@ -143,10 +143,17 @@ class Knowledge extends AddonBase { } let noteText: string = note.getNote(); let containerIndex = noteText.search(/data-schema-version="8">/g); - let noteHead = noteText.substring(0, containerIndex); - note.setNote( - `${noteHead}data-schema-version="8">${noteLines.join("\n")}` - ); + if (containerIndex === -1) { + note.setNote( + `
${noteLines.join("\n")}
` + ); + } else { + let noteHead = noteText.substring(0, containerIndex); + note.setNote( + `${noteHead}data-schema-version="8">${noteLines.join("\n")}` + ); + } + note.saveTx(); } @@ -401,6 +408,9 @@ class Knowledge extends AddonBase { lineIndex: -1, endIndex: -1, }); + if (!metadataContainer) { + return root; + } let id = 0; let currentNode = root; let lastNode = undefined; diff --git a/src/views.ts b/src/views.ts index ebafeb9..c5e2fac 100644 --- a/src/views.ts +++ b/src/views.ts @@ -16,7 +16,7 @@ class AddonViews extends AddonBase { addToKnowledge: ``, notMainKnowledge: ``, isMainKnowledge: ``, - jumpAttachment: ``, + openAttachment: ``, addAnnotationNote: ``, export: ``, close: ``, @@ -167,6 +167,22 @@ class AddonViews extends AddonBase { editor.parentNode.scrollTo(0, editor.children[lineIndex].offsetTop); } + addNewKnowledgeButton() { + // Top toolbar button + let addNoteButton = document.getElementById("zotero-tb-note-add"); + let button = document.createElement("toolbarbutton"); + button.setAttribute("id", "zotero-tb-knowledge-openwindow"); + button.setAttribute("tooltiptext", "Create new Knowledge Workspace"); + button.addEventListener("click", (e) => { + this._Addon.events.onEditorEvent(new EditorMessage("createWorkspace", {})); + }); + button.setAttribute( + "style", + "list-style-image: url('chrome://Knowledge4Zotero/skin/knowledge.png');" + ); + addNoteButton.after(button); + } + addOpenWorkspaceButton() { // Left collection tree view button const treeRow = document.createElement("html:div"); @@ -184,7 +200,7 @@ class AddonViews extends AddonBase { span3.setAttribute("class", "icon icon-bg cell-icon"); span3.setAttribute( "style", - "background-image:url(chrome://Knowledge4Zotero/skin/favicon.png)" + "background-image:url(chrome://Knowledge4Zotero/skin/knowledge.png)" ); const span4 = document.createElement("span"); span4.setAttribute("class", "cell-text"); @@ -225,7 +241,7 @@ class AddonViews extends AddonBase { continue; } moreButton.setAttribute("knowledgeinit", "true"); - const addAnnotationNoteButton = _document.createElement("button"); + const addAnnotationNoteButton = _document.createElement("div"); addAnnotationNoteButton.innerHTML = this.editorIcon["addAnnotationNote"]; let annotationWrapper = moreButton; @@ -272,7 +288,7 @@ class AddonViews extends AddonBase { return { id, type, - attachmentItemID: Zotero.Reader._readers[0].itemID, + attachmentItemID: reader.itemID, text: text ? text.trim() : text, color, comment: comment ? comment.trim() : comment, @@ -286,7 +302,10 @@ class AddonViews extends AddonBase { addAnnotationNoteButton.addEventListener("click", (e) => { this._Addon.events.onEditorEvent( new EditorMessage("addAnnotationNote", { - params: annotations, + params: { + annotations: annotations, + annotationItem: annotationItem, + }, }) ); e.preventDefault(); @@ -349,14 +368,19 @@ class AddonViews extends AddonBase { }); this.$("#outline-addafter").dxButton({ icon: "plus", - hint: "Add Heading after the selected Heading's section", onClick: (e) => { - if (this._Addon.knowledge.currentNodeID < 0) { - return; - } - const text = prompt("Enter new Heading:"); + const text = prompt("Enter new heading:"); this._Addon.knowledge.openWorkspaceWindow(); if (text.trim()) { + if (this._Addon.knowledge.currentNodeID < 0) { + // Add a new H1 + this._Addon.knowledge.addSubLineToNote( + undefined, + `

${text}

`, + -1 + ); + return; + } let node = this._Addon.knowledge.getNoteTreeNodeById( undefined, this._Addon.knowledge.currentNodeID @@ -371,9 +395,9 @@ class AddonViews extends AddonBase { }); this.$("#outline-tab").dxButton({ icon: "increaseindent", - hint: "Raise the selected Heading level", onClick: (e) => { if (this._Addon.knowledge.currentNodeID < 0) { + this.showProgressWindow("Knowledge", "Please select a Heading."); return; } let node = this._Addon.knowledge.getNoteTreeNodeById( @@ -389,9 +413,9 @@ class AddonViews extends AddonBase { }); this.$("#outline-untab").dxButton({ icon: "decreaseindent", - hint: "Decrease the selected Heading level", onClick: (e) => { if (this._Addon.knowledge.currentNodeID < 0) { + this.showProgressWindow("Knowledge", "Please select a Heading."); return; } let node = this._Addon.knowledge.getNoteTreeNodeById( diff --git a/typing/global.d.ts b/typing/global.d.ts index 03ac687..b8c32d0 100644 --- a/typing/global.d.ts +++ b/typing/global.d.ts @@ -87,7 +87,8 @@ declare interface ZoteroItem { setNote: (string) => void; getNoteTitle: () => string; isAttachment: () => boolean; - isAnnotation?: () => boolean; + isAnnotation: () => boolean; + isPDFAttachment: () => boolean; itemTypeID: number; libraryID: number; parentID: number; @@ -145,6 +146,10 @@ declare const ZoteroPane: { getSelectedItems: () => Array; }; +declare const ZoteroPane_Local: { + newNote: () => Promise; +}; + declare class ZoteroCollection { getChildItems: (arg1: boolean, arg2: boolean) => Array; }