add: batch export

This commit is contained in:
xiangyu 2022-06-10 16:45:56 +08:00
parent 6ec4ba1e31
commit 5b29479186
5 changed files with 141 additions and 3 deletions

View File

@ -43,7 +43,9 @@
<popup id="zotero-itemmenu">
<menuseparator />
<menuitem id="zotero-itemmenu-__addonRef__-setMainKnowledge" label="&zotero.__addonRef__.itemmenu.setMainKnowledge.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'setMainKnowledge', content: {params: {itemID: ZoteroPane.getSelectedItems()[0].id}}})" class="menuitem-iconic" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
<menuitem id="zotero-itemmenu-__addonRef__-setMainKnowledge" class="menuitem-iconic popup-type-single-note" label="&zotero.__addonRef__.itemmenu.setMainKnowledge.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'setMainKnowledge', content: {params: {itemID: ZoteroPane.getSelectedItems()[0].id}}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
<menuitem id="zotero-itemmenu-__addonRef__-exportNote" class="menuitem-iconic popup-type-single" label="&zotero.__addonRef__.itemmenu.exportNote.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'exportNotes', content: {}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
<menuitem id="zotero-itemmenu-__addonRef__-exportNotes" class="menuitem-iconic popup-type-multiple" label="&zotero.__addonRef__.itemmenu.exportNotes.label;" oncommand="Zotero.Knowledge4Zotero.events.onEditorEvent.bind(Zotero.Knowledge4Zotero.events)({type: 'exportNotes', content: {}})" style="list-style-image: url('chrome://__addonRef__/skin/favicon.png');" />
</popup>
<menupopup id="menu_FilePopup">

View File

@ -19,6 +19,8 @@
<!ENTITY zotero.__addonRef__.workspace.menu.about "About Better Notes">
<!ENTITY zotero.__addonRef__.itemmenu.setMainKnowledge.label "Set Main Note">
<!ENTITY zotero.__addonRef__.itemmenu.exportNote.label "Export Note and SubNotes">
<!ENTITY zotero.__addonRef__.itemmenu.exportNotes.label "Export Notes and SubNotes to Markdown">
<!ENTITY zotero.__addonRef__.export.title "Export">
<!ENTITY zotero.__addonRef__.export.option.label "General">

View File

@ -19,6 +19,8 @@
<!ENTITY zotero.__addonRef__.workspace.menu.about "关于Better Notes">
<!ENTITY zotero.__addonRef__.itemmenu.setMainKnowledge.label "设置为主笔记">
<!ENTITY zotero.__addonRef__.itemmenu.exportNote.label "导出笔记及条目子笔记">
<!ENTITY zotero.__addonRef__.itemmenu.exportNotes.label "导出笔记及条目子笔记为Markdown">
<!ENTITY zotero.__addonRef__.export.title "导出笔记">
<!ENTITY zotero.__addonRef__.export.option.label "通用">

View File

@ -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 = {

View File

@ -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("<img");
if (hasImage && !attachmentCreated) {
await Zotero.File.createDirectoryIfMissingAsync(
OS.Path.join(...this._exportPath.split(/\//))
);
attachmentCreated = true;
}
let filename = `${Zotero.File.pathToFile(filepath).path}/${newNote
.getNoteTitle()
.replace(/[/\\?%*:|"<>]/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[],