diff --git a/addon/chrome/content/overlay.xul b/addon/chrome/content/overlay.xul index 4b4d561..f20f33a 100644 --- a/addon/chrome/content/overlay.xul +++ b/addon/chrome/content/overlay.xul @@ -43,7 +43,9 @@ - + + + diff --git a/addon/chrome/locale/en-US/overlay.dtd b/addon/chrome/locale/en-US/overlay.dtd index 32d6add..31128f1 100644 --- a/addon/chrome/locale/en-US/overlay.dtd +++ b/addon/chrome/locale/en-US/overlay.dtd @@ -19,6 +19,8 @@ + + diff --git a/addon/chrome/locale/zh-CN/overlay.dtd b/addon/chrome/locale/zh-CN/overlay.dtd index 4fa9bc0..e28f90f 100644 --- a/addon/chrome/locale/zh-CN/overlay.dtd +++ b/addon/chrome/locale/zh-CN/overlay.dtd @@ -19,6 +19,8 @@ + + diff --git a/src/events.ts b/src/events.ts index 3d29c56..6b51729 100644 --- a/src/events.ts +++ b/src/events.ts @@ -115,6 +115,8 @@ class AddonEvents extends AddonBase { this.initWorkspaceTab(); this._Addon.views.switchRealMenuBar(true); this._Addon.views.switchKey(true); + + this.initItemSelectListener(); } private async initWorkspaceTab() { @@ -148,6 +150,25 @@ class AddonEvents extends AddonBase { } } + private initItemSelectListener() { + ZoteroPane.itemsView.onSelect.addListener(() => { + const items = ZoteroPane.getSelectedItems(); + const hasNote = items.filter((i) => i.isNote()).length > 0; + const singleItem = items.length === 1; + document + .querySelectorAll(".popup-type-single") + .forEach((el) => ((el as HTMLElement).hidden = !singleItem)); + document + .querySelectorAll(".popup-type-multiple") + .forEach((el) => ((el as HTMLElement).hidden = singleItem)); + document + .querySelectorAll(".popup-type-single-note") + .forEach( + (el) => ((el as HTMLElement).hidden = !(singleItem && hasNote)) + ); + }); + } + public addEditorInstanceListener() { if (!Zotero.Notes._knowledgeInit) { Zotero.Notes._knowledgeInit = true; @@ -1135,9 +1156,12 @@ class AddonEvents extends AddonBase { } else if (message.type === "export") { /* message.content = { - editorInstance + editorInstance?, params?: {item} } */ + const item = message.content.editorInstance + ? message.content.editorInstance._item + : message.content.params.item; const io = { dataIn: null, dataOut: null, @@ -1154,12 +1178,40 @@ class AddonEvents extends AddonBase { const options = io.dataOut; await this._Addon.knowledge.exportNoteToFile( - message.content.editorInstance._item, + item, options.embedLink, options.exportFile, options.exportNote, options.exportCopy ); + } else if (message.type === "exportNotes") { + /* + message.content = { + editorInstance + } + */ + const items = ZoteroPane.getSelectedItems(); + const noteItems = []; + items.forEach((item) => { + if (item.isNote()) { + noteItems.push(item); + } + if (item.isRegularItem()) { + noteItems.splice(0, 0, Zotero.Items.get(item.getNotes())); + } + }); + if (noteItems.length === 0) { + this._Addon.views.showProgressWindow( + "Better Notes", + "No standalone/item note selected." + ); + } else if (noteItems.length === 1) { + this.onEditorEvent( + new EditorMessage("export", { params: { item: noteItems[0] } }) + ); + } else { + await this._Addon.knowledge.exportNotesToFile(noteItems); + } } else if (message.type === "openAttachment") { /* message.content = { diff --git a/src/knowledge.ts b/src/knowledge.ts index 0988d44..ed772ca 100644 --- a/src/knowledge.ts +++ b/src/knowledge.ts @@ -804,6 +804,86 @@ class Knowledge extends AddonBase { } } + async exportNotesToFile(notes: ZoteroItem[]) { + Components.utils.import("resource://gre/modules/osfile.jsm"); + const filepath = await pick( + Zotero.getString("fileInterface.export"), + "folder" + ); + + if (!filepath) { + return; + } + + await loadTranslator(TRANSLATOR_ID_BETTER_MARKDOWN); + + this._exportPath = Zotero.File.pathToFile(filepath).path + "/attachments"; + // Convert to unix format + this._exportPath = this._exportPath.replace(/\\/g, "/"); + + let attachmentCreated = false; + + for (const note of notes) { + let newNote: ZoteroItem; + if (this.getLinkFromText(note.getNote())) { + const noteID = await ZoteroPane_Local.newNote(); + newNote = Zotero.Items.get(noteID); + const rootNoteIds = [note.id]; + + const convertResult = await this.convertNoteLines( + note, + rootNoteIds, + true + ); + + this.setLinesToNote(newNote, convertResult.lines); + Zotero.debug(convertResult.subNotes); + + await Zotero.DB.executeTransaction(async () => { + await Zotero.Notes.copyEmbeddedImages(note, newNote); + for (const subNote of convertResult.subNotes) { + await Zotero.Notes.copyEmbeddedImages(subNote, newNote); + } + }); + } else { + newNote = note; + } + + this._exportNote = newNote; + + const hasImage = newNote.getNote().includes("]/g, "-")}-${note.key}.md`; + filename = filename.replace(/\\/g, "/"); + const translator = new Zotero.Translate.Export(); + translator.setItems([newNote]); + translator.setLocation( + Zotero.File.pathToFile(OS.Path.join(...filename.split(/\//))) + ); + translator.setTranslator(TRANSLATOR_ID_BETTER_MARKDOWN); + translator.translate(); + this._Addon.views.showProgressWindow( + "Better Notes", + `Note Saved to ${filename}` + ); + if (newNote.id !== note.id) { + const _w: Window = ZoteroPane.findNoteWindow(newNote.id); + if (_w) { + _w.close(); + } + await Zotero.Items.erase(newNote.id); + } + } + } + async convertNoteLines( currentNote: ZoteroItem, rootNoteIds: number[],