From 7859df48c0055d490eeab7248d0d4cf8ac2544ac Mon Sep 17 00:00:00 2001 From: windingwind <33902321+windingwind@users.noreply.github.com> Date: Sat, 9 Nov 2024 20:48:14 +0100 Subject: [PATCH] update: rework export window --- addon/chrome/content/exportNotes.xhtml | 102 +++++++++ addon/chrome/content/preferences.xhtml | 5 + addon/chrome/content/styles/exportNotes.css | 8 + addon/locale/en-US/addon.ftl | 2 - addon/locale/en-US/export.ftl | 25 --- addon/locale/en-US/exportNotes.ftl | 37 ++++ addon/locale/en-US/preferences.ftl | 2 + addon/locale/it-IT/addon.ftl | 2 - addon/locale/it-IT/export.ftl | 25 --- addon/locale/it-IT/exportNotes.ftl | 37 ++++ addon/locale/it-IT/preferences.ftl | 2 + addon/locale/ru-RU/addon.ftl | 2 - addon/locale/ru-RU/exportNotes.ftl | 37 ++++ addon/locale/ru-RU/preferences.ftl | 2 + addon/locale/tr-TR/addon.ftl | 2 - addon/locale/tr-TR/export.ftl | 25 --- addon/locale/tr-TR/exportNotes.ftl | 37 ++++ addon/locale/tr-TR/preferences.ftl | 2 + addon/locale/zh-CN/addon.ftl | 2 - addon/locale/zh-CN/export.ftl | 25 --- addon/locale/zh-CN/exportNotes.ftl | 37 ++++ addon/locale/zh-CN/preferences.ftl | 2 + addon/prefs.js | 1 + src/extras/exportNotes.ts | 185 ++++++++++++++++ src/hooks.ts | 5 +- src/modules/export/exportWindow.ts | 229 ++------------------ src/modules/exportItems.ts | 26 +++ src/modules/menu.ts | 13 -- src/modules/viewItems.ts | 2 +- src/utils/note.ts | 3 +- src/utils/relation.ts | 20 +- 31 files changed, 568 insertions(+), 336 deletions(-) create mode 100644 addon/chrome/content/exportNotes.xhtml create mode 100644 addon/chrome/content/styles/exportNotes.css delete mode 100644 addon/locale/en-US/export.ftl create mode 100644 addon/locale/en-US/exportNotes.ftl delete mode 100644 addon/locale/it-IT/export.ftl create mode 100644 addon/locale/it-IT/exportNotes.ftl create mode 100644 addon/locale/ru-RU/exportNotes.ftl delete mode 100644 addon/locale/tr-TR/export.ftl create mode 100644 addon/locale/tr-TR/exportNotes.ftl delete mode 100644 addon/locale/zh-CN/export.ftl create mode 100644 addon/locale/zh-CN/exportNotes.ftl create mode 100644 src/extras/exportNotes.ts create mode 100644 src/modules/exportItems.ts diff --git a/addon/chrome/content/exportNotes.xhtml b/addon/chrome/content/exportNotes.xhtml new file mode 100644 index 00000000..cc5e5b48 --- /dev/null +++ b/addon/chrome/content/exportNotes.xhtml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addon/chrome/content/preferences.xhtml b/addon/chrome/content/preferences.xhtml index de003179..5412d923 100644 --- a/addon/chrome/content/preferences.xhtml +++ b/addon/chrome/content/preferences.xhtml @@ -16,6 +16,11 @@ native="true" preference="__prefsPrefix__.openNote.defaultAsWindow" /> + diff --git a/addon/chrome/content/styles/exportNotes.css b/addon/chrome/content/styles/exportNotes.css new file mode 100644 index 00000000..8d1ff4aa --- /dev/null +++ b/addon/chrome/content/styles/exportNotes.css @@ -0,0 +1,8 @@ +dialog { + -moz-window-dragging: drag; +} + +#markdown-autoSync { + margin-inline-start: 18px; + margin-block-end: 24px; +} diff --git a/addon/locale/en-US/addon.ftl b/addon/locale/en-US/addon.ftl index 6df150e5..c9acf259 100644 --- a/addon/locale/en-US/addon.ftl +++ b/addon/locale/en-US/addon.ftl @@ -1,7 +1,5 @@ pref-title = Better Notes -menuItem-exportNote = Export Note - menuEdit-exportTemplate = Export Template to File... menuEdit-templateEditor = Template Editor menuEdit-importTemplate = New Template from Clipboard diff --git a/addon/locale/en-US/export.ftl b/addon/locale/en-US/export.ftl deleted file mode 100644 index 23482214..00000000 --- a/addon/locale/en-US/export.ftl +++ /dev/null @@ -1,25 +0,0 @@ -title = Export Notes -options-linkMode = Linked Notes Mode -options-MD = MarkDown(.md) -options-Docx = MS Word(.docx) -options-PDF = PDF(.pdf) -options-mm = Mind Map -options-note = Zotero Note -embedLink = All Embedded in One Export -standaloneLink = Each Converted to Standalone Exports -keepLink = Keep Zotero Links(zotero://note/) -exportMD = Export MD File(s) -setAutoSync = Set Auto-Sync - .title = Auto-Sync is available for "Each Converted to Standalone Exports" mode. -withYAMLHeader = With YAML Header -autoMDFileName = Auto Generate MD File Name -exportDocx = Export Docx File -exportPDF = Export PDF File -exportFreeMind = Export FreeMind File -exportNote = Export to New Zotero Note Item -confirm = Export -cancel = Close -target = Target: {$title}{ $left -> - [0]{ "" } - *[other] { " " }and {$left} more. - } \ No newline at end of file diff --git a/addon/locale/en-US/exportNotes.ftl b/addon/locale/en-US/exportNotes.ftl new file mode 100644 index 00000000..aba431ea --- /dev/null +++ b/addon/locale/en-US/exportNotes.ftl @@ -0,0 +1,37 @@ +title = + .title = Export Notes with Better Notes + +target = + .value = Target: {$title}{ $left -> + [0]{ "" } + *[other] { " " }and {$left} more. + } +format = + .value = Format: +format-markdown = + .label = MarkDown(.md) +format-msword = + .label = MS Word(.docx) +format-pdf = + .label = PDF(.pdf) +format-freemind = + .label = Mind Map +format-note = + .label = Zotero Note + +links-keep = + .label = Keep note links(zotero://note/) +links-embed = + .label = Embed linked notes in the content +links-standalone = + .label = Convert linked notes to standalone exports +links-remove = + .label = Remove note links + +markdown-autoSync = + .label = Set auto-sync for each note + .title = Auto-sync is available for "Convert linked notes to standalone exports" mode. +markdown-withYAMLHeader = + .label = With YAML header +markdown-autoFilename = + .label = Auto generate file name diff --git a/addon/locale/en-US/preferences.ftl b/addon/locale/en-US/preferences.ftl index f092161a..e2636846 100644 --- a/addon/locale/en-US/preferences.ftl +++ b/addon/locale/en-US/preferences.ftl @@ -3,6 +3,8 @@ basic-openNote-takeover = .label = Take over opening note basic-openNote-defaultAsWindow = .label = Open note as window by default +basic-exportNotes-takeover = + .label = Take over exporting notes editor-title = Note Editor editor-expandLevel-label = Outline expand to heading level diff --git a/addon/locale/it-IT/addon.ftl b/addon/locale/it-IT/addon.ftl index cf1e742a..00dde5d2 100644 --- a/addon/locale/it-IT/addon.ftl +++ b/addon/locale/it-IT/addon.ftl @@ -1,7 +1,5 @@ pref-title = Better Notes -menuItem-exportNote = Esporta nota - menuEdit-exportTemplate = Esporta il template su file... menuEdit-templateEditor = Editor dei template menuEdit-importTemplate = Nuovo template dagli appunti diff --git a/addon/locale/it-IT/export.ftl b/addon/locale/it-IT/export.ftl deleted file mode 100644 index 2e077e45..00000000 --- a/addon/locale/it-IT/export.ftl +++ /dev/null @@ -1,25 +0,0 @@ -title = Esporta note -options-linkMode = Modalità note collegate -options-MD = MarkDown(.md) -options-Docx = MS Word(.docx) -options-PDF = PDF(.pdf) -options-mm = Mappa mentale -options-note = Nota Zotero -embedLink = Tutte incorporate in un'unica esportazione -standaloneLink = Ciascuna convertita in esportazioni indipendenti -keepLink = Mantieni i link Zotero (zotero://note/) -exportMD = Esporta file MD -setAutoSync = Imposta sincronizzazione automatica - .title = La sincronizzazione automatica è disponibile per la modalità "Ciascuna convertita in esportazioni indipendenti". -withYAMLHeader = Con header YAML -autoMDFileName = Genera automaticamente il nome del file MD -exportDocx = Esporta file Docx -exportPDF = Esporta file PDF -exportFreeMind = Esporta file FreeMind -exportNote = Esporta in una nuova nota dell'elemento Zotero -confirm = Esporta -cancel = Chiudi -target = Oggetto: {$title}{ $left -> - [0]{ "" } - *[other] { " " }e {$left} altri - } \ No newline at end of file diff --git a/addon/locale/it-IT/exportNotes.ftl b/addon/locale/it-IT/exportNotes.ftl new file mode 100644 index 00000000..7a2680c6 --- /dev/null +++ b/addon/locale/it-IT/exportNotes.ftl @@ -0,0 +1,37 @@ +title = + .title = Esporta Note con Better Notes + +target = + .value = Destinazione: {$title}{ $left -> + [0]{ "" } + *[other] { " " }e {$left} in più. + } +format = + .value = Formato: +format-markdown = + .label = MarkDown(.md) +format-msword = + .label = MS Word(.docx) +format-pdf = + .label = PDF(.pdf) +format-freemind = + .label = Mappa Mentale +format-note = + .label = Nota Zotero + +links-keep = + .label = Mantieni collegamenti alle note(zotero://note/) +links-embed = + .label = Incorpora note collegate nel contenuto +links-standalone = + .label = Converti note collegate in esportazioni autonome +links-remove = + .label = Rimuovi collegamenti alle note + +markdown-autoSync = + .label = Imposta sincronizzazione automatica per ogni nota + .title = La sincronizzazione automatica è disponibile per la modalità "Converti note collegate in esportazioni autonome". +markdown-withYAMLHeader = + .label = Con intestazione YAML +markdown-autoFilename = + .label = Genera automaticamente il nome del file diff --git a/addon/locale/it-IT/preferences.ftl b/addon/locale/it-IT/preferences.ftl index d5a2f2d0..f7b674c0 100644 --- a/addon/locale/it-IT/preferences.ftl +++ b/addon/locale/it-IT/preferences.ftl @@ -3,6 +3,8 @@ basic-openNote-takeover = .label = Gestisci l'apertura delle note basic-openNote-defaultAsWindow = .label = Apri note come finestra per impostazione predefinita +basic-exportNotes-takeover = + .label = Take over exporting notes editor-title = Editor delle note editor-expandLevel-label = Espansione dello schema al livello delle intestazioni diff --git a/addon/locale/ru-RU/addon.ftl b/addon/locale/ru-RU/addon.ftl index c7580dd0..203df513 100644 --- a/addon/locale/ru-RU/addon.ftl +++ b/addon/locale/ru-RU/addon.ftl @@ -1,7 +1,5 @@ pref-title=Better Notes -menuItem-exportNote=Экспорт заметки - menuEdit-exportTemplate=Экспорт шаблона в файл... menuEdit-templateEditor=Редактор шаблонов menuEdit-importTemplate=Новый шаблон из буфера обмена diff --git a/addon/locale/ru-RU/exportNotes.ftl b/addon/locale/ru-RU/exportNotes.ftl new file mode 100644 index 00000000..0c98730b --- /dev/null +++ b/addon/locale/ru-RU/exportNotes.ftl @@ -0,0 +1,37 @@ +title = + .title = Экспорт заметок с Better Notes + +target = + .value = Цель: {$title}{ $left -> + [0]{ "" } + *[other] { " " }и еще {$left}. + } +format = + .value = Формат: +format-markdown = + .label = MarkDown(.md) +format-msword = + .label = MS Word(.docx) +format-pdf = + .label = PDF(.pdf) +format-freemind = + .label = Карта разума +format-note = + .label = Заметка Zotero + +links-keep = + .label = Сохранить ссылки на заметки(zotero://note/) +links-embed = + .label = Встроить связанные заметки в содержимое +links-standalone = + .label = Преобразовать связанные заметки в автономные экспорты +links-remove = + .label = Удалить ссылки на заметки + +markdown-autoSync = + .label = Установить авто-синхронизацию для каждой заметки + .title = Авто-синхронизация доступна в режиме "Преобразовать связанные заметки в автономные экспорты". +markdown-withYAMLHeader = + .label = С YAML заголовком +markdown-autoFilename = + .label = Автоматически генерировать имя файла diff --git a/addon/locale/ru-RU/preferences.ftl b/addon/locale/ru-RU/preferences.ftl index c590da75..bd9b3152 100644 --- a/addon/locale/ru-RU/preferences.ftl +++ b/addon/locale/ru-RU/preferences.ftl @@ -3,6 +3,8 @@ basic-openNote-takeover = .label = Take over opening note basic-openNote-defaultAsWindow = .label = Open note as window by default +basic-exportNotes-takeover = + .label = Take over exporting notes editor-title = Note Editor editor-expandLevel-label = Outline расширить до уровня заголовка diff --git a/addon/locale/tr-TR/addon.ftl b/addon/locale/tr-TR/addon.ftl index 99bd53c3..3a8a6010 100644 --- a/addon/locale/tr-TR/addon.ftl +++ b/addon/locale/tr-TR/addon.ftl @@ -1,7 +1,5 @@ pref-title = Better Notes -menuItem-exportNote = Notu Dışa Aktar - menuEdit-exportTemplate = Şablonu Dosya Olarak Dışa Aktar... menuEdit-templateEditor = Şablon Düzenleyici menuEdit-importTemplate = Panodan Yeni Şablon Al diff --git a/addon/locale/tr-TR/export.ftl b/addon/locale/tr-TR/export.ftl deleted file mode 100644 index 1fd9edd7..00000000 --- a/addon/locale/tr-TR/export.ftl +++ /dev/null @@ -1,25 +0,0 @@ -title = Notları Dışa Aktar -options-linkMode = Bağlantılı Notlar Modu -options-MD = MarkDown(.md) -options-Docx = MS Word(.docx) -options-PDF = PDF(.pdf) -options-mm = Zihin Haritası -options-note = Zotero Notu -embedLink = Hepsi Tek Bir Dışarı Aktarma İçerisinde -standaloneLink = Her Biri Bağımsız Olarak Dışa Aktarıldı -keepLink = Zotero Linkleri Kalsın (zotero://note/) -exportMD = MD Dosya(lar)sını Dışa Aktar -setAutoSync = Otomatik Eşitlemeye Ayarla - .title = Otomatik Eşitleme "Her Birini Bağımsız Dışa Aktar" seçeneği için kullanılabilir. -withYAMLHeader = YAML Başlığı İle -autoMDFileName = MD Dosya Adını Otomatik Oluştur -exportDocx = Docx Dosyası Olarak Dışa Aktar -exportPDF = PDF Dosyası Olarak Dışa Aktar -exportFreeMind = FreeMind Dosyası Olarak Dışa Aktar -exportNote = Yeni Zotero Notuna Aktar -confirm = Dışa Aktar -cancel = Kapat -target = Hedef: {$title}{ $left -> - [0]{ "" } - *[other] { " " }and {$left} more - } diff --git a/addon/locale/tr-TR/exportNotes.ftl b/addon/locale/tr-TR/exportNotes.ftl new file mode 100644 index 00000000..62df0b8c --- /dev/null +++ b/addon/locale/tr-TR/exportNotes.ftl @@ -0,0 +1,37 @@ +title = + .title = Notları Better Notes ile Dışa Aktar + +target = + .value = Hedef: {$title}{ $left -> + [0]{ "" } + *[other] { " " }ve {$left} daha. + } +format = + .value = Biçim: +format-markdown = + .label = MarkDown(.md) +format-msword = + .label = MS Word(.docx) +format-pdf = + .label = PDF(.pdf) +format-freemind = + .label = Zihin Haritası +format-note = + .label = Zotero Notu + +links-keep = + .label = Not bağlantılarını koru(zotero://note/) +links-embed = + .label = Bağlantılı notları içeriğe göm +links-standalone = + .label = Bağlantılı notları bağımsız dışa aktarımlara dönüştür +links-remove = + .label = Not bağlantılarını kaldır + +markdown-autoSync = + .label = Her not için otomatik senkronizasyon ayarla + .title = Otomatik senkronizasyon "Bağlantılı notları bağımsız dışa aktarımlara dönüştür" modu için kullanılabilir. +markdown-withYAMLHeader = + .label = YAML başlığı ile +markdown-autoFilename = + .label = Dosya adını otomatik oluştur diff --git a/addon/locale/tr-TR/preferences.ftl b/addon/locale/tr-TR/preferences.ftl index 1114d944..2ddc68ff 100644 --- a/addon/locale/tr-TR/preferences.ftl +++ b/addon/locale/tr-TR/preferences.ftl @@ -3,6 +3,8 @@ basic-openNote-takeover = .label = Notları açmayı devral basic-openNote-defaultAsWindow = .label = Notları her zaman pencere olarak aç +basic-exportNotes-takeover = + .label = Take over exporting notes editor-title = Not Düzenleyici editor-expandLevel-label = Anahatta gösterilecek başlık düzeyleri diff --git a/addon/locale/zh-CN/addon.ftl b/addon/locale/zh-CN/addon.ftl index 161ff0da..dfd8b43e 100644 --- a/addon/locale/zh-CN/addon.ftl +++ b/addon/locale/zh-CN/addon.ftl @@ -1,7 +1,5 @@ pref-title=Better Notes -menuItem-exportNote=导出笔记 - menuEdit-exportTemplate=运行模板并导出为文件... menuEdit-templateEditor=模板编辑器 menuEdit-importTemplate=从剪贴板导入笔记模板 diff --git a/addon/locale/zh-CN/export.ftl b/addon/locale/zh-CN/export.ftl deleted file mode 100644 index 4205890a..00000000 --- a/addon/locale/zh-CN/export.ftl +++ /dev/null @@ -1,25 +0,0 @@ -title=导出笔记 -options-linkMode=链接笔记模式 -options-MD=MarkDown(.md) -options-Docx=MS Word(.docx) -options-PDF=PDF(.pdf) -options-mm=思维导图 -options-note=Zotero笔记 -embedLink=全部嵌入为一个导出 -standaloneLink=分别单独导出 -keepLink=保留Zotero链接(zotero://note/) -exportMD=导出MD文件 -setAutoSync=设置自动同步 - .title=自动同步仅能在"分别单独导出模式"使用 -withYAMLHeader=带有YAML头 -autoMDFileName=自动生成MD文件名 -exportDocx=导出Word文件 -exportPDF=导出PDF文件 -exportFreeMind=导出FreeMind文件 -exportNote=导出为Zotero笔记条目 -confirm=导出 -cancel=关闭 -target=目标: {$title}{ $left -> - [0]{ "" } - *[other] { " " }和其他{$left}个 - } \ No newline at end of file diff --git a/addon/locale/zh-CN/exportNotes.ftl b/addon/locale/zh-CN/exportNotes.ftl new file mode 100644 index 00000000..c7114001 --- /dev/null +++ b/addon/locale/zh-CN/exportNotes.ftl @@ -0,0 +1,37 @@ +title = + .title = 使用 Better Notes 导出笔记 + +target = + .value = 目标: {$title}{ $left -> + [0]{ "" } + *[other] { " " } 以及其他 {$left} 个。 + } +format = + .value = 格式: +format-markdown = + .label = MarkDown(.md) +format-msword = + .label = MS Word(.docx) +format-pdf = + .label = PDF(.pdf) +format-freemind = + .label = 思维导图 +format-note = + .label = Zotero 笔记 + +links-keep = + .label = 保留笔记链接(zotero://note/) +links-embed = + .label = 嵌入链接的笔记内容 +links-standalone = + .label = 将链接的笔记分别导出 +links-remove = + .label = 移除笔记链接 + +markdown-autoSync = + .label = 为每个笔记设置自动同步 + .title = 自动同步适用于“将链接的笔记分别导出”模式。 +markdown-withYAMLHeader = + .label = 包含 YAML 头 +markdown-autoFilename = + .label = 自动生成文件名 diff --git a/addon/locale/zh-CN/preferences.ftl b/addon/locale/zh-CN/preferences.ftl index 2f3b1434..8c077c38 100644 --- a/addon/locale/zh-CN/preferences.ftl +++ b/addon/locale/zh-CN/preferences.ftl @@ -3,6 +3,8 @@ basic-openNote-takeover = .label = 接管打开笔记 basic-openNote-defaultAsWindow = .label = 默认在窗口打开笔记 +basic-exportNotes-takeover = + .label = 接管导出笔记 editor-title = 笔记编辑器 editor-expandLevel-label = 大纲展开至标题层级 diff --git a/addon/prefs.js b/addon/prefs.js index f9a51bba..f8fdc5d5 100644 --- a/addon/prefs.js +++ b/addon/prefs.js @@ -25,5 +25,6 @@ pref("__prefsPrefix__.editor.noteLinkPreviewType", "hover"); pref("__prefsPrefix__.openNote.takeover", true); pref("__prefsPrefix__.openNote.defaultAsWindow", false); +pref("__prefsPrefix__.exportNotes.takeover", true); pref("__prefsPrefix__.annotationNote.enableTagSync", true); diff --git a/src/extras/exportNotes.ts b/src/extras/exportNotes.ts new file mode 100644 index 00000000..47688153 --- /dev/null +++ b/src/extras/exportNotes.ts @@ -0,0 +1,185 @@ +import { getPref, setPref } from "../utils/prefs"; + +let io: { + targetData: { + left: number; + title: string; + }; + accepted: boolean; + useBuiltInExport: boolean; + deferred: _ZoteroTypes.DeferredPromise; + embedLink: boolean; + standaloneLink: boolean; + exportNote: boolean; + exportMD: boolean; + setAutoSync: boolean; + autoMDFileName: boolean; + withYAMLHeader: boolean; + exportDocx: boolean; + exportPDF: boolean; + exportFreeMind: boolean; +}; + +window.onload = async function () { + if (document.readyState === "complete") { + setTimeout(init, 0); + return; + } + document.addEventListener("DOMContentLoaded", init, { once: true }); +}; + +window.onunload = function () { + io.deferred && io.deferred.resolve(); +}; + +function init() { + const dialog = document.querySelector("dialog")!; + Zotero.UIProperties.registerRoot(dialog); + + io = window.arguments[0]; + + window.addEventListener("dialogaccept", doAccept); + window.addEventListener("dialogextra1", () => doUseBuiltInExport()); + + document + .querySelector("#format")! + .addEventListener("command", onFormatChange); + + document + .querySelector("#linkMode")! + .addEventListener("command", updateMarkdownOptions); + + document + .querySelector("#markdown-autoSync")! + .addEventListener("command", updateMarkdownOptions); + + (document.querySelector("#target") as XULElement).dataset.l10nArgs = + JSON.stringify(io.targetData); + + restore(); + + onFormatChange(); + updateMarkdownOptions(); +} + +function restore() { + let format = getPref("export.format") as string; + if (!["markdown", "msword", "pdf", "freemind", "note"].includes(format)) { + format = "markdown"; + } + (document.querySelector("#format") as XULMenuListElement).value = format; + + let linkMode = getPref("export.linkMode") as string; + if (!["keep", "embed", "standalone", "remove"].includes(linkMode)) { + linkMode = "keep"; + } + (document.querySelector("#linkMode") as XULRadioGroupElement).value = + linkMode; + + const markdownPrefs = ["autoSync", "withYAMLHeader", "autoFilename"]; + for (const pref of markdownPrefs) { + ( + document.querySelector(`#markdown-${pref}`) as XULCheckboxElement + ).checked = getPref(`export.markdown-${pref}`) as boolean; + } +} + +function cache() { + setPref( + "export.format", + (document.querySelector("#format") as XULMenuListElement).value, + ); + setPref( + "export.linkMode", + (document.querySelector("#linkMode") as XULRadioGroupElement).value, + ); + + const markdownPrefs = ["autoSync", "withYAMLHeader", "autoFilename"]; + for (const pref of markdownPrefs) { + setPref( + `export.markdown-${pref}`, + (document.querySelector(`#markdown-${pref}`) as XULCheckboxElement) + .checked, + ); + } +} + +function onFormatChange() { + const format = (document.querySelector("#format") as XULMenuListElement) + .value; + const isMD = format === "markdown"; + + (document.querySelector("#markdown-options") as XULBoxElement).hidden = !isMD; + + window.sizeToContent(); +} + +function updateMarkdownOptions() { + const linkModeRadio = document.querySelector( + "#linkMode", + ) as XULRadioGroupElement; + const autoSyncRadio = document.querySelector( + "#markdown-autoSync", + ) as XULCheckboxElement; + + if (linkModeRadio.value !== "standalone") { + autoSyncRadio.checked = false; + autoSyncRadio.disabled = true; + } else { + autoSyncRadio.disabled = false; + } + + const autoFilename = document.querySelector( + "#markdown-autoFilename", + ) as XULCheckboxElement; + const withYAMLHeader = document.querySelector( + "#markdown-withYAMLHeader", + ) as XULCheckboxElement; + + if (autoSyncRadio.checked) { + autoFilename.checked = true; + autoFilename.disabled = true; + withYAMLHeader.checked = true; + withYAMLHeader.disabled = true; + } else { + autoFilename.disabled = false; + withYAMLHeader.disabled = false; + } +} + +function doAccept() { + cache(); + + // Format + const format = (document.querySelector("#format") as XULMenuListElement) + .value; + io.exportMD = format === "markdown"; + io.exportDocx = format === "msword"; + io.exportPDF = format === "pdf"; + io.exportFreeMind = format === "freemind"; + io.exportNote = format === "note"; + + // Markdown options + io.autoMDFileName = ( + document.querySelector("#markdown-autoFilename") as XULCheckboxElement + ).checked; + io.withYAMLHeader = ( + document.querySelector("#markdown-withYAMLHeader") as XULCheckboxElement + ).checked; + io.setAutoSync = ( + document.querySelector("#markdown-autoSync") as XULCheckboxElement + ).checked; + + // Link mode + const linkMode = (document.querySelector("#linkMode") as XULRadioGroupElement) + .value; + io.embedLink = linkMode === "embed"; + io.standaloneLink = linkMode === "standalone"; + + io.accepted = true; +} + +function doUseBuiltInExport() { + io.useBuiltInExport = true; + window.close(); +} diff --git a/src/hooks.ts b/src/hooks.ts index 0412c278..eb57d3e8 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -47,6 +47,7 @@ import { registerNoteLinkSection } from "./modules/workspace/link"; import { showUserGuide } from "./modules/userGuide"; import { refreshTemplatesInNote } from "./modules/template/refresh"; import { closeParsingServer } from "./utils/parsing"; +import { patchExportItems } from "./modules/exportItems"; async function onStartup() { await Promise.all([ @@ -81,7 +82,7 @@ async function onStartup() { await onMainWindowLoad(Zotero.getMainWindow()); } -async function onMainWindowLoad(win: Window): Promise { +async function onMainWindowLoad(win: _ZoteroTypes.MainWindow): Promise { await waitUtilAsync(() => win.document.readyState === "complete"); Services.scriptloader.loadSubScript( @@ -99,6 +100,8 @@ async function onMainWindowLoad(win: Window): Promise { patchViewItems(win); + patchExportItems(win); + restoreNoteTabs(); showUserGuide(win); diff --git a/src/modules/export/exportWindow.ts b/src/modules/export/exportWindow.ts index 50ddd5f1..68e461c1 100644 --- a/src/modules/export/exportWindow.ts +++ b/src/modules/export/exportWindow.ts @@ -1,20 +1,6 @@ import { config } from "../../../package.json"; -import { getPref, setPref } from "../../utils/prefs"; import { fill, slice } from "../../utils/str"; -enum OPTIONS { - "embedLink", - "standaloneLink", - "keepLink", - "exportMD", - "setAutoSync", - "withYAMLHeader", - "exportDocx", - "exportPDF", - "exportFreeMind", - "exportNote", -} - export async function showExportNoteOptions( noteIds: number[], overwriteOptions: Record = {}, @@ -32,204 +18,37 @@ export async function showExportNoteOptions( if (noteItems.length === 0) { return; } - const dataKeys = Object.keys(OPTIONS).filter( - (value) => typeof value === "string", - ); - const data = dataKeys.reduce( - (acc, key) => { - acc[key] = getPref(`export.${key}`) as boolean; - return acc; - }, - {} as Record, - ); - data.loadCallback = () => { - const doc = dialog.window.document; - const standaloneLinkRadio = doc.querySelector( - "#standaloneLink", - ) as HTMLInputElement; - const autoSyncRadio = doc.querySelector("#setAutoSync") as HTMLInputElement; - function updateSyncCheckbox() { - const standaloneLinkEnabled = standaloneLinkRadio.checked; - if (!standaloneLinkEnabled) { - autoSyncRadio.checked = false; - autoSyncRadio.disabled = true; - } else { - autoSyncRadio.disabled = false; - } - } - Array.from(doc.querySelectorAll('input[name="linkMode"]')).forEach((elem) => - (elem as HTMLInputElement).addEventListener("change", updateSyncCheckbox), - ); - updateSyncCheckbox(); + const io = { + targetData: { + left: noteItems.length - 1, + title: fill(slice(noteItems[0].getNoteTitle(), 40), 40), + }, + deferred: Zotero.Promise.defer(), + accepted: false, + useBuiltInExport: false, }; - data.l10nFiles = `${config.addonRef}-export.ftl`; + Zotero.getMainWindow().openDialog( + `chrome://${config.addonRef}/content/exportNotes.xhtml`, + `${config.addonRef}-exportNotes`, + "chrome,centerscreen,resizable", + io, + ); - const dialog = new ztoolkit.Dialog(18, 1) - .setDialogData(data) - .addCell(0, 0, { - tag: "div", - styles: { - display: "grid", - gridTemplateColumns: "1fr 20px", - rowGap: "10px", - columnGap: "5px", - }, - children: [ - { - tag: "label", - attributes: { - "data-l10n-id": `${config.addonRef}-target`, - "data-l10n-args": JSON.stringify({ - left: noteItems.length - 1, - title: fill(slice(noteItems[0].getNoteTitle(), 40), 40), - }), - }, - }, - ], - }) - .addCell(1, 0, makeHeadingLine("options-linkMode")) - .addCell(2, 0, makeRadioLine("embedLink", "linkMode")) - .addCell(3, 0, makeRadioLine("standaloneLink", "linkMode")) - .addCell(4, 0, makeRadioLine("keepLink", "linkMode")) - .addCell(5, 0, makeHeadingLine("options-MD")) - .addCell(6, 0, makeCheckboxLine("exportMD")) - .addCell(7, 0, makeCheckboxLine("setAutoSync")) - .addCell(8, 0, makeCheckboxLine("withYAMLHeader")) - .addCell(9, 0, makeCheckboxLine("autoMDFileName")) - .addCell(10, 0, makeHeadingLine("options-Docx")) - .addCell(11, 0, makeCheckboxLine("exportDocx")) - .addCell(12, 0, makeHeadingLine("options-PDF")) - .addCell(13, 0, makeCheckboxLine("exportPDF")) - .addCell(14, 0, makeHeadingLine("options-mm")) - .addCell(15, 0, makeCheckboxLine("exportFreeMind")) - .addCell(16, 0, makeHeadingLine("options-note")) - .addCell(17, 0, makeCheckboxLine("exportNote")) - .addButton(`${config.addonRef}-confirm`, "confirm") - .addButton(`${config.addonRef}-cancel`, "cancel") - .open(`${config.addonRef}-title`, { - resizable: true, - centerscreen: true, - width: 350, - height: 600, - noDialogMode: true, - }); + await io.deferred.promise; - await data.unloadLock?.promise; - if (data._lastButtonId === "confirm") { + if (io.accepted) { await addon.api.$export.exportNotes( noteItems, - Object.assign(data as Record, overwriteOptions), + Object.assign(io as any, overwriteOptions), ); - dataKeys.forEach((key) => { - setPref(`export.${key}`, Boolean(data[key])); - }); } -} - -function makeHeadingLine(l10nID: string) { - return { - tag: "div", - styles: { - display: "grid", - gridTemplateColumns: "1fr 20px", - rowGap: "10px", - columnGap: "5px", - }, - children: [ - { - tag: "h3", - attributes: { - "data-l10n-id": `${config.addonRef}-${l10nID}`, - }, - }, - ], - }; -} - -function makeCheckboxLine(dataKey: string, callback?: (ev: Event) => void) { - return { - tag: "div", - styles: { - display: "grid", - gridTemplateColumns: "1fr 20px", - rowGap: "10px", - columnGap: "5px", - }, - children: [ - { - tag: "label", - attributes: { - for: dataKey, - "data-l10n-id": `${config.addonRef}-${dataKey}`, - }, - }, - { - tag: "input", - id: dataKey, - attributes: { - "data-bind": dataKey, - "data-prop": "checked", - }, - properties: { - type: "checkbox", - }, - listeners: callback - ? [ - { - type: "change", - listener: callback, - }, - ] - : [], - }, - ], - }; -} - -function makeRadioLine( - dataKey: string, - radioName: string, - callback?: (ev: Event) => void, -) { - return { - tag: "div", - styles: { - display: "grid", - gridTemplateColumns: "1fr 20px", - rowGap: "10px", - columnGap: "5px", - }, - children: [ - { - tag: "label", - attributes: { - for: dataKey, - "data-l10n-id": `${config.addonRef}-${dataKey}`, - }, - }, - { - tag: "input", - id: dataKey, - attributes: { - "data-bind": dataKey, - "data-prop": "checked", - }, - properties: { - type: "radio", - name: radioName, - value: dataKey, - }, - listeners: callback - ? [ - { - type: "change", - listener: callback, - }, - ] - : [], - }, - ], - }; + if (io.useBuiltInExport) { + const exporter = new (Zotero.getMainWindow().Zotero_File_Exporter)(); + exporter.items = Zotero.Items.get(noteIds); + if (!exporter.items || !exporter.items.length) + throw "no items currently selected"; + exporter.save(); + } } diff --git a/src/modules/exportItems.ts b/src/modules/exportItems.ts new file mode 100644 index 00000000..b9754c06 --- /dev/null +++ b/src/modules/exportItems.ts @@ -0,0 +1,26 @@ +import { PatchHelper } from "zotero-plugin-toolkit"; +import { getPref } from "../utils/prefs"; + +export function patchExportItems(win: _ZoteroTypes.MainWindow) { + const Zotero_File_Interface = win.Zotero_File_Interface; + new PatchHelper().setData({ + target: Zotero_File_Interface, + funcSign: "exportItems", + patcher: (origin) => + function () { + if (!getPref("exportNotes.takeover")) { + // @ts-ignore + return origin.apply(this); + } + const items = win.ZoteroPane.getSelectedItems(); + if (items.every((item) => item.isNote())) { + return addon.hooks.onShowExportNoteOptions( + items.map((item) => item.id), + ); + } + // @ts-ignore + return origin.apply(this); + }, + enabled: true, + }); +} diff --git a/src/modules/menu.ts b/src/modules/menu.ts index 0ccaf16f..808610b5 100644 --- a/src/modules/menu.ts +++ b/src/modules/menu.ts @@ -2,19 +2,6 @@ import { config } from "../../package.json"; import { getString } from "../utils/locale"; export function registerMenus(win: Window) { - // item - ztoolkit.Menu.register("item", { tag: "menuseparator" }); - ztoolkit.Menu.register("item", { - tag: "menuitem", - label: getString("menuItem.exportNote"), - icon: `chrome://${config.addonRef}/content/icons/favicon.png`, - commandListener: (ev) => { - addon.hooks.onShowExportNoteOptions( - ZoteroPane.getSelectedItems().map((item) => item.id), - ); - }, - }); - // menuTools ztoolkit.Menu.register("menuTools", { tag: "menuseparator" }); ztoolkit.Menu.register("menuTools", { diff --git a/src/modules/viewItems.ts b/src/modules/viewItems.ts index c82ee88f..9c13d9ff 100644 --- a/src/modules/viewItems.ts +++ b/src/modules/viewItems.ts @@ -1,7 +1,7 @@ import { PatchHelper } from "zotero-plugin-toolkit"; import { getPref } from "../utils/prefs"; -export function patchViewItems(win: Window) { +export function patchViewItems(win: _ZoteroTypes.MainWindow) { // @ts-ignore const ZoteroPane = win.ZoteroPane; new PatchHelper().setData({ diff --git a/src/utils/note.ts b/src/utils/note.ts index bf64596d..84d1a04f 100644 --- a/src/utils/note.ts +++ b/src/utils/note.ts @@ -58,7 +58,8 @@ async function setLinesToNote(note: Zotero.Item, lines: string[]) { } else { const noteHead = noteText.substring(0, containerIndex); note.setNote( - `${noteHead}data-schema-version="${config.dataSchemaVersion + `${noteHead}data-schema-version="${ + config.dataSchemaVersion }">${lines.join("\n")}`, ); } diff --git a/src/utils/relation.ts b/src/utils/relation.ts index 98369d5d..66c8613c 100644 --- a/src/utils/relation.ts +++ b/src/utils/relation.ts @@ -73,7 +73,9 @@ async function updateNoteLinkRelation(noteID: number) { } } } - const result = await (await getRelationServer()).proxy.rebuildLinkForNote(fromLibID, fromKey, linkToData); + const result = await ( + await getRelationServer() + ).proxy.rebuildLinkForNote(fromLibID, fromKey, linkToData); for (const link of result.oldOutboundLinks as LinkModel[]) { const item = Zotero.Items.getByLibraryAndKey(link.toLibID, link.toKey); @@ -96,14 +98,18 @@ async function getNoteLinkOutboundRelation(noteID: number) { const note = Zotero.Items.get(noteID); const fromLibID = note.libraryID; const fromKey = note.key; - return await (await getRelationServer()).proxy.getOutboundLinks(fromLibID, fromKey); + return await ( + await getRelationServer() + ).proxy.getOutboundLinks(fromLibID, fromKey); } async function getNoteLinkInboundRelation(noteID: number) { const note = Zotero.Items.get(noteID); const toLibID = note.libraryID; const toKey = note.key; - return await (await getRelationServer()).proxy.getInboundLinks(toLibID, toKey); + return await ( + await getRelationServer() + ).proxy.getInboundLinks(toLibID, toKey); } function decodeHTMLEntities(text: string) { @@ -129,11 +135,15 @@ async function linkAnnotationToTarget(model: AnnotationModel) { } async function getLinkTargetByAnnotation(fromLibID: number, fromKey: string) { - return await (await getRelationServer()).proxy.getLinkTargetByAnnotation(fromLibID, fromKey); + return await ( + await getRelationServer() + ).proxy.getLinkTargetByAnnotation(fromLibID, fromKey); } async function getAnnotationByLinkTarget(toLibID: number, toKey: string) { - return await (await getRelationServer()).proxy.getAnnotationByLinkTarget(toLibID, toKey); + return await ( + await getRelationServer() + ).proxy.getAnnotationByLinkTarget(toLibID, toKey); } interface AnnotationModel {