From eb2ef66e91f597725f96a840f9fbfc75e8ca30b1 Mon Sep 17 00:00:00 2001 From: YISH Date: Thu, 12 May 2022 20:46:18 +0800 Subject: [PATCH] :bug: fix Can't edit custom command. --- manifest.json | 2 +- package.json | 2 +- src/export_command_templates.ts | 30 ++- src/lua.ts | 2 +- src/main.ts | 12 +- src/settings.ts | 11 +- src/shims-lua.d.ts | 2 +- src/ui/add_new_modal.ts | 36 ++- src/ui/export_modal.ts | 399 +++++++++++++++++++------------- src/ui/message_box.ts | 91 ++++++-- src/ui/rename_modal.ts | 29 ++- src/ui/setting_tab.ts | 267 +++++++++++++-------- src/utils.ts | 44 +++- versions.json | 3 +- 14 files changed, 595 insertions(+), 335 deletions(-) diff --git a/manifest.json b/manifest.json index f9c6019..8ffcc8e 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-enhancing-export", "name": "Obsidian Enhancing Export", - "version": "1.0.4", + "version": "1.0.5", "minAppVersion": "0.12.0", "description": "This is a enhancing export plugin for Obsidian. It allows to export to formats like Html, DOCX, ePub and PDF or Markdown(Hugo) etc.", "author": "YISH", diff --git a/package.json b/package.json index 6e9c6ca..4a4af4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-enhancing-export", - "version": "1.0.4", + "version": "1.0.5", "description": "This is a enhancing export plugin for Obsidian. It allows to export to formats like Html, DOCX, ePub and PDF or Markdown(Hugo) etc.", "main": "main.js", "scripts": { diff --git a/src/export_command_templates.ts b/src/export_command_templates.ts index 19d144e..6471ec2 100644 --- a/src/export_command_templates.ts +++ b/src/export_command_templates.ts @@ -35,7 +35,8 @@ export default { type: 'pandoc', arguments: '-f markdown --resource-path="${currentDir}" --self-contained --metadata title="${currentFileName}" -s -o "${outputPath}" -t html', - customArguments: '--mathjax="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg-full.js"', + customArguments: + '--mathjax="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg-full.js"', extension: '.html', }, 'PDF': { @@ -48,55 +49,64 @@ export default { 'Word (.docx)': { name: 'Word (.docx)', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t docx', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t docx', extension: '.docx', }, 'OpenOffice': { name: 'OpenOffice', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t odt', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t odt', extension: '.odt', }, 'RTF': { name: 'RTF', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t rtf', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t rtf', extension: '.rtf', }, 'Epub': { name: 'Epub', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t epub', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t epub', extension: '.epub', }, 'Latex': { name: 'Latex', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t latex', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t latex', extension: '.latex', }, 'Media Wiki': { name: 'Media Wiki', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t mediawiki', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t mediawiki', extension: '.mediawiki', }, 'reStructuredText': { name: 'reStructuredText', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t rst', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t rst', extension: '.rst', }, 'Textile': { name: 'Textile', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t textile', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t textile', extension: '.textile', }, 'OPML': { name: 'OPML', type: 'pandoc', - arguments: '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t opml', + arguments: + '-f markdown --resource-path="${currentDir}" -s -o "${outputPath}" -t opml', extension: '.opml', }, 'Custom': { diff --git a/src/lua.ts b/src/lua.ts index 2e1b503..5dbdd97 100644 --- a/src/lua.ts +++ b/src/lua.ts @@ -9,7 +9,7 @@ const files = { 'url.lua': url, 'polyfill.lua': polyfill, 'markdown.lua': markdown, - 'markdown+hugo.lua': markdown_hugo + 'markdown+hugo.lua': markdown_hugo, }; export default files; diff --git a/src/main.ts b/src/main.ts index c6bc42e..f5effa1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,10 @@ import luaScripts from './lua'; -import * as fsp from 'fs/promises'; import { App, Menu, Plugin, PluginManifest, TFile } from 'obsidian'; import { UniversalExportPluginSettings, DEFAULT_SETTINGS } from './settings'; import { ExportDialog } from './ui/export_modal'; import { ExportSettingTab } from './ui/setting_tab'; import lang, { Lang } from './lang'; - export default class UniversalExportPlugin extends Plugin { settings: UniversalExportPluginSettings; lang: Lang; @@ -49,7 +47,11 @@ export default class UniversalExportPlugin extends Plugin { } public async loadSettings(): Promise { - this.settings = Object.assign({}, JSON.parse(JSON.stringify(DEFAULT_SETTINGS)), await this.loadData()); + this.settings = Object.assign( + {}, + JSON.parse(JSON.stringify(DEFAULT_SETTINGS)), + await this.loadData() + ); if (this.settings.version !== this.manifest.version) { await this.saveLuaScripts(); this.settings.version = this.manifest.version; @@ -66,7 +68,9 @@ export default class UniversalExportPlugin extends Plugin { const { adapter } = this.app.vault; const luaDir = `${this.manifest.dir}/lua`; await adapter.mkdir(luaDir); - for (const luaScript of Object.keys(luaScripts) as Array) { + for (const luaScript of Object.keys(luaScripts) as Array< + keyof typeof luaScripts + >) { const luaFile = `${luaDir}/${luaScript}`; await adapter.writeBinary(luaFile, luaScripts[luaScript]); } diff --git a/src/settings.ts b/src/settings.ts index 381e4b4..4781d16 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -32,7 +32,10 @@ export interface Variables { export type PlatformValue = { [k in typeof platform]?: T }; -export function setPlatformValue(obj: { [k in typeof platform]?: T }, value: T): { [k in typeof platform]?: T } { +export function setPlatformValue( + obj: { [k in typeof platform]?: T }, + value: T +): { [k in typeof platform]?: T } { if (typeof value === 'string' && value.trim() === '') { value = undefined; } @@ -47,7 +50,7 @@ export function getPlatformValue(obj: { [k in typeof platform]?: T }): T { } export interface UniversalExportPluginSettings { - version?: string, + version?: string; pandocPath?: PlatformValue; showOverwriteConfirmation?: boolean; defaultExportDirectoryMode: 'Auto' | 'Same' | 'Custom'; @@ -90,7 +93,9 @@ export interface CustomExportSetting extends CommonExportSetting { export type ExportSetting = PandocExportSetting | CustomExportSetting; export const DEFAULT_SETTINGS: UniversalExportPluginSettings = { - items: Object.values(export_command_templates).filter(o => o.type !== 'custom'), + items: Object.values(export_command_templates).filter( + o => o.type !== 'custom' + ), pandocPath: undefined, defaultExportDirectoryMode: 'Auto', openExportedFile: true, diff --git a/src/shims-lua.d.ts b/src/shims-lua.d.ts index 4f67968..44434bd 100644 --- a/src/shims-lua.d.ts +++ b/src/shims-lua.d.ts @@ -1,4 +1,4 @@ declare module '*.lua' { const lua: Uint8Array; export default lua; -} \ No newline at end of file +} diff --git a/src/ui/add_new_modal.ts b/src/ui/add_new_modal.ts index 38aa66f..7e2ed56 100644 --- a/src/ui/add_new_modal.ts +++ b/src/ui/add_new_modal.ts @@ -9,7 +9,11 @@ export class AddNewModal extends Modal { get lang() { return this.settingTab.lang; } - constructor(app: App, settingTab: ExportSettingTab, callback: (setting: ExportSetting) => void) { + constructor( + app: App, + settingTab: ExportSettingTab, + callback: (setting: ExportSetting) => void + ) { super(app); this.settingTab = settingTab; this.callback = callback; @@ -26,7 +30,11 @@ export class AddNewModal extends Modal { let nameSetting: Setting; new Setting(contentEl).setName(lang.template).addDropdown(cb => { - cb.addOptions(Object.fromEntries(Object.values(export_command_templates).map(o => [o.name, o.name]))) + cb.addOptions( + Object.fromEntries( + Object.values(export_command_templates).map(o => [o.name, o.name]) + ) + ) .setValue(tplName) .onChange(v => { tplName = v; @@ -40,14 +48,22 @@ export class AddNewModal extends Modal { cb.setValue(name).onChange(v => (name = v)); }); - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: lang.add, cls: ['mod-cta'], parent: el }).onclick = async () => { - tpl = JSON.parse(JSON.stringify(export_command_templates[tplName])); - tpl.name = name; - callback(tpl); - this.close(); - }; - }); + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: lang.add, + cls: ['mod-cta'], + parent: el, + }).onclick = async () => { + tpl = JSON.parse(JSON.stringify(export_command_templates[tplName])); + tpl.name = name; + callback(tpl); + this.close(); + }; + } + ); } onClose() { diff --git a/src/ui/export_modal.ts b/src/ui/export_modal.ts index 72f4730..5962730 100644 --- a/src/ui/export_modal.ts +++ b/src/ui/export_modal.ts @@ -1,6 +1,11 @@ import { App, Modal, Setting, TFile, TextComponent, Notice } from 'obsidian'; import * as ct from 'electron'; -import { extractDefaultExtension as extractExtension, getPlatformValue, setPlatformValue, Variables } from '../settings'; +import { + extractDefaultExtension as extractExtension, + getPlatformValue, + setPlatformValue, + Variables, +} from '../settings'; import type UniversalExportPlugin from '../main'; import { exec } from 'child_process'; @@ -8,7 +13,11 @@ import { MessageBox } from './message_box'; import * as fs from 'fs'; import { setTooltip, setVisible } from '../utils'; -export const executeCommand = (cmd: string, successCallback?: (msg: string) => void, errorCallback?: (msg: string) => void) => { +export const executeCommand = ( + cmd: string, + successCallback?: (msg: string) => void, + errorCallback?: (msg: string) => void +) => { let options; if (ct.remote.process.platform === 'win32') { options = {}; @@ -66,17 +75,27 @@ export class ExportDialog extends Modal { let extension = extractExtension(setting); let showOverwriteConfirmation = common.showOverwriteConfirmation; - let candidateOutputDirectory = `${getPlatformValue(common.lastExportDirectory) ?? ct.remote.app.getPath('documents')}`; + let candidateOutputDirectory = `${ + getPlatformValue(common.lastExportDirectory) ?? + ct.remote.app.getPath('documents') + }`; let candidateOutputFileName = `${currentFile.basename}${extension}`; // eslint-disable-next-line prefer-const let candidateOutputFileNameSetting: Setting; if (exportDirectoryMode === 'Same') { - const fullPath: string = this.app.vault.adapter.getFullPath(currentFile.path); - candidateOutputDirectory = fullPath.substring(0, fullPath.length - currentFile.name.length - 1); + const fullPath: string = this.app.vault.adapter.getFullPath( + currentFile.path + ); + candidateOutputDirectory = fullPath.substring( + 0, + fullPath.length - currentFile.name.length - 1 + ); } else if (exportDirectoryMode === 'Custom') { - candidateOutputDirectory = getPlatformValue(common.customDefaultExportDirectory); + candidateOutputDirectory = getPlatformValue( + common.customDefaultExportDirectory + ); } titleEl.setText(lang.exportDialog.title(setting.name)); @@ -90,7 +109,11 @@ export class ExportDialog extends Modal { extension = extractExtension(setting); if (candidateOutputFileName.includes('.')) { - candidateOutputFileName = candidateOutputFileName.substring(0, candidateOutputFileName.lastIndexOf('.')) + extension; + candidateOutputFileName = + candidateOutputFileName.substring( + 0, + candidateOutputFileName.lastIndexOf('.') + ) + extension; } else { candidateOutputFileName = candidateOutputFileName + extension; } @@ -101,14 +124,16 @@ export class ExportDialog extends Modal { .setValue(exportType); }); - candidateOutputFileNameSetting = new Setting(contentEl).setName(lang.fileName).addText(cb => { - cb.setValue(candidateOutputFileName) - .onChange(v => { - candidateOutputFileName = v; - setTooltip(cb.inputEl, v); - }) - .inputEl.setAttribute('title', candidateOutputFileName); - }); + candidateOutputFileNameSetting = new Setting(contentEl) + .setName(lang.fileName) + .addText(cb => { + cb.setValue(candidateOutputFileName) + .onChange(v => { + candidateOutputFileName = v; + setTooltip(cb.inputEl, v); + }) + .inputEl.setAttribute('title', candidateOutputFileName); + }); const candidateOutputDirectorySetting = new Setting(contentEl) .setName(lang.exportTo) @@ -129,7 +154,9 @@ export class ExportDialog extends Modal { }); if (!retval.canceled && retval.filePaths?.length > 0) { candidateOutputDirectory = retval.filePaths[0]; - (candidateOutputDirectorySetting.components.first() as TextComponent) + ( + candidateOutputDirectorySetting.components.first() as TextComponent + ) ?.setValue(candidateOutputDirectory) .inputEl.setAttribute('title', candidateOutputDirectory); } @@ -137,163 +164,209 @@ export class ExportDialog extends Modal { }); new Setting(contentEl).setName(lang.overwriteConfirmation).addToggle(cb => { - cb.setValue(showOverwriteConfirmation).onChange(v => (showOverwriteConfirmation = v)); + cb.setValue(showOverwriteConfirmation).onChange( + v => (showOverwriteConfirmation = v) + ); }); - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: lang.exportDialog.export, cls: ['mod-cta'], parent: el }).onclick = async () => { - /* Variables - * /User/aaa/Documents/test.pdf - * - ${outputDir} --> /User/aaa/Documents/ - * - ${outputPath} --> /User/aaa/Documents/test.pdf - * - ${outputFileName} --> test - * - ${outputFileFullName} --> test.pdf - * - * /User/aaa/Documents/test.pdf - * - ${currentDir} --> /User/aaa/Documents/ - * - ${currentPath} --> /User/aaa/Documents/test.pdf - * - ${CurrentFileName} --> test - * - ${CurrentFileFullName} --> test.pdf - */ - - const pluginDir = `${this.app.vault.adapter.getBasePath()}/${this.plugin.manifest.dir}`; - const outputDir = candidateOutputDirectory; - const outputPath = `${outputDir}/${candidateOutputFileName}`; - const outputFileName = candidateOutputFileName.substring(0, candidateOutputFileName.lastIndexOf('.')); - const outputFileFullName = candidateOutputFileName; - - const currentPath = this.app.vault.adapter.getFullPath(currentFile.path); - const currentDir = currentPath.substring(0, currentPath.length - currentFile.name.length - 1); - const currentFileName = currentFile.basename; - const currentFileFullName = currentFile.name; - - const variables: Variables = { - pluginDir, - outputDir, - outputPath, - outputFileName, - outputFileFullName, - currentDir, - currentPath, - currentFileName, - currentFileFullName, - // date: new Date(currentFile.stat.ctime), - // lastMod: new Date(currentFile.stat.mtime), - // now: new Date() - }; + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: lang.exportDialog.export, + cls: ['mod-cta'], + parent: el, + }).onclick = async () => { + /* Variables + * /User/aaa/Documents/test.pdf + * - ${outputDir} --> /User/aaa/Documents/ + * - ${outputPath} --> /User/aaa/Documents/test.pdf + * - ${outputFileName} --> test + * - ${outputFileFullName} --> test.pdf + * + * /User/aaa/Documents/test.pdf + * - ${currentDir} --> /User/aaa/Documents/ + * - ${currentPath} --> /User/aaa/Documents/test.pdf + * - ${CurrentFileName} --> test + * - ${CurrentFileFullName} --> test.pdf + */ + + const pluginDir = `${this.app.vault.adapter.getBasePath()}/${ + this.plugin.manifest.dir + }`; + const outputDir = candidateOutputDirectory; + const outputPath = `${outputDir}/${candidateOutputFileName}`; + const outputFileName = candidateOutputFileName.substring( + 0, + candidateOutputFileName.lastIndexOf('.') + ); + const outputFileFullName = candidateOutputFileName; - switch (ct.remote.process.platform) { - case 'darwin': { - let envPath = ct.remote.process.env['PATH']; - const brewBin = '/usr/local/bin'; - if (!envPath.includes(brewBin)) { - envPath = `${brewBin}:${envPath}`; - ct.remote.process.env['PATH'] = envPath; + const currentPath = this.app.vault.adapter.getFullPath( + currentFile.path + ); + const currentDir = currentPath.substring( + 0, + currentPath.length - currentFile.name.length - 1 + ); + const currentFileName = currentFile.basename; + const currentFileFullName = currentFile.name; + + const variables: Variables = { + pluginDir, + outputDir, + outputPath, + outputFileName, + outputFileFullName, + currentDir, + currentPath, + currentFileName, + currentFileFullName, + // date: new Date(currentFile.stat.ctime), + // lastMod: new Date(currentFile.stat.mtime), + // now: new Date() + }; + + switch (ct.remote.process.platform) { + case 'darwin': { + let envPath = ct.remote.process.env['PATH']; + const brewBin = '/usr/local/bin'; + if (!envPath.includes(brewBin)) { + envPath = `${brewBin}:${envPath}`; + ct.remote.process.env['PATH'] = envPath; + } + break; } - break; - } - default: - break; - } - - const showCommandLineOutput = setting.type === 'custom' && setting.showCommandOutput; - const openExportedFileLocation = setting.openExportedFileLocation ?? common.openExportedFileLocation; - const openExportedFile = setting.openExportedFile ?? common.openExportedFile; - - const onExportSuccess = async () => { - if (openExportedFileLocation) { - setTimeout(() => { - ct.remote.shell.showItemInFolder(outputPath); - }, 1000); - } - if (openExportedFile) { - await ct.remote.shell.openPath(outputPath); + default: + break; } - // success - this.plugin.settings.showOverwriteConfirmation = showOverwriteConfirmation; - this.plugin.settings.lastExportDirectory = setPlatformValue(this.plugin.settings.lastExportDirectory, candidateOutputDirectory); - - this.plugin.settings.lastExportType = exportType; - await this.plugin.saveSettings(); - this.close(); - }; - - const doExport = () => { - // show progress - const progress = this.app.loadProgress; - progress.setMessage(lang.preparing(outputFileFullName)); - setVisible(this.containerEl, false); - progress.show(); - const pandocPath = getPlatformValue(common.pandocPath) ?? 'pandoc'; - - const cmdTpl = - setting.type === 'pandoc' - ? `${pandocPath} ${setting.arguments ?? ''} ${setting.customArguments ?? ''} "${currentPath}"` - : setting.command; - - const cmd = cmdTpl.replace(/\${(.*?)}/g, (_, p1: string) => { - return variables[p1 as keyof typeof variables]; - }); - - // console.log('export command:' + cmd); - - executeCommand( - cmd, - () => { - progress.hide(); - if (showCommandLineOutput) { - const box = new MessageBox(this.app, lang.exportCommandOutputMessage(cmd)); - box.onClose = onExportSuccess; - box.open(); - } else { - new Notice(lang.exportSuccessNotice(outputFileFullName), 1500); - onExportSuccess(); + const showCommandLineOutput = + setting.type === 'custom' && setting.showCommandOutput; + const openExportedFileLocation = + setting.openExportedFileLocation ?? common.openExportedFileLocation; + const openExportedFile = + setting.openExportedFile ?? common.openExportedFile; + + const onExportSuccess = async () => { + if (openExportedFileLocation) { + setTimeout(() => { + ct.remote.shell.showItemInFolder(outputPath); + }, 1000); + } + if (openExportedFile) { + await ct.remote.shell.openPath(outputPath); + } + // success + this.plugin.settings.showOverwriteConfirmation = + showOverwriteConfirmation; + this.plugin.settings.lastExportDirectory = setPlatformValue( + this.plugin.settings.lastExportDirectory, + candidateOutputDirectory + ); + + this.plugin.settings.lastExportType = exportType; + await this.plugin.saveSettings(); + this.close(); + }; + + const doExport = () => { + // show progress + const progress = this.app.loadProgress; + progress.setMessage(lang.preparing(outputFileFullName)); + setVisible(this.containerEl, false); + progress.show(); + + const pandocPath = getPlatformValue(common.pandocPath) ?? 'pandoc'; + + const cmdTpl = + setting.type === 'pandoc' + ? `${pandocPath} ${setting.arguments ?? ''} ${ + setting.customArguments ?? '' + } "${currentPath}"` + : setting.command; + + const cmd = cmdTpl.replace(/\${(.*?)}/g, (_, p1: string) => { + return variables[p1 as keyof typeof variables]; + }); + + // console.log('export command:' + cmd); + + executeCommand( + cmd, + () => { + progress.hide(); + if (showCommandLineOutput) { + const box = new MessageBox( + this.app, + lang.exportCommandOutputMessage(cmd) + ); + box.onClose = onExportSuccess; + box.open(); + } else { + new Notice( + lang.exportSuccessNotice(outputFileFullName), + 1500 + ); + onExportSuccess(); + } + }, + err => { + progress.hide(); + new MessageBox( + this.app, + lang.exportErrorOutputMessage(cmd, err) + ).open(); + setVisible(this.containerEl, true); } - }, - err => { - progress.hide(); - new MessageBox(this.app, lang.exportErrorOutputMessage(cmd, err)).open(); - setVisible(this.containerEl, true); + ); + }; + + if (showOverwriteConfirmation && fs.existsSync(outputPath)) { + // const msgBox = new MessageBox(this.app, { + // message: lang.overwriteConfirmationDialog.message(outputDir), + // title: lang.overwriteConfirmationDialog.title(outputFileFullName), + // buttons: 'OkCancel', + // buttonsLabel: { + // ok: lang.overwriteConfirmationDialog.replace, + // }, + // buttonsClass: { + // ok: 'mod-warning' + // }, + // callback: { + // ok: () => doExport() + // } + // }); + // msgBox.open(); + + const result = await ct.remote.dialog.showSaveDialog({ + title: lang.overwriteConfirmationDialog.title(outputFileFullName), + defaultPath: outputPath, + properties: ['showOverwriteConfirmation', 'createDirectory'], + }); + + if (!result.canceled) { + variables.outputPath = result.filePath; + variables.outputDir = variables.outputPath.substring( + 0, + variables.outputPath.lastIndexOf('/') + ); + variables.outputFileFullName = variables.outputPath.substring( + variables.outputDir.length + 1 + ); + variables.outputFileName = variables.outputFileFullName.substring( + 0, + variables.outputFileFullName.lastIndexOf('.') + ); + doExport(); } - ); - }; - - if (showOverwriteConfirmation && fs.existsSync(outputPath)) { - // const msgBox = new MessageBox(this.app, { - // message: lang.overwriteConfirmationDialog.message(outputDir), - // title: lang.overwriteConfirmationDialog.title(outputFileFullName), - // buttons: 'OkCancel', - // buttonsLabel: { - // ok: lang.overwriteConfirmationDialog.replace, - // }, - // buttonsClass: { - // ok: 'mod-warning' - // }, - // callback: { - // ok: () => doExport() - // } - // }); - // msgBox.open(); - - const result = await ct.remote.dialog.showSaveDialog({ - title: lang.overwriteConfirmationDialog.title(outputFileFullName), - defaultPath: outputPath, - properties: ['showOverwriteConfirmation', 'createDirectory'], - }); - - if (!result.canceled) { - variables.outputPath = result.filePath; - variables.outputDir = variables.outputPath.substring(0, variables.outputPath.lastIndexOf('/')); - variables.outputFileFullName = variables.outputPath.substring(variables.outputDir.length + 1); - variables.outputFileName = variables.outputFileFullName.substring(0, variables.outputFileFullName.lastIndexOf('.')); + } else { doExport(); } - } else { - doExport(); - } - }; - }); + }; + } + ); } onClose() { diff --git a/src/ui/message_box.ts b/src/ui/message_box.ts index 1001288..814c298 100644 --- a/src/ui/message_box.ts +++ b/src/ui/message_box.ts @@ -34,7 +34,10 @@ export class MessageBox extends Modal { constructor(app: App, options: MessageBoxOptions); constructor(app: App, options: MessageBoxOptions | string, title?: string) { super(app); - this.options = typeof options === 'string' ? { message: options, buttons: 'Ok', title } : options; + this.options = + typeof options === 'string' + ? { message: options, buttons: 'Ok', title } + : options; this.lang = lang.current; } onOpen(): void { @@ -42,7 +45,14 @@ export class MessageBox extends Modal { titleEl, contentEl, lang, - options: { message, title, buttons, callback, buttonsLabel: label, buttonsClass }, + options: { + message, + title, + buttons, + callback, + buttonsLabel: label, + buttonsClass, + }, } = this; if (title) { titleEl.setText(title); @@ -50,35 +60,66 @@ export class MessageBox extends Modal { contentEl.createDiv({ text: message }); switch (buttons) { case 'Yes': - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: label?.yes ?? lang.messageBox.yes, cls: ['mod-cta', buttonsClass?.yes], parent: el }).onclick = - () => this.call(callback?.yes); - }); + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: label?.yes ?? lang.messageBox.yes, + cls: ['mod-cta', buttonsClass?.yes], + parent: el, + }).onclick = () => this.call(callback?.yes); + } + ); break; case 'YesNo': - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: label?.yes ?? lang.messageBox.yes, cls: ['mod-cta', buttonsClass?.yes], parent: el }).onclick = - () => this.call(callback?.yes); - el.createEl('button', { text: label?.no ?? lang.messageBox.no, cls: ['mod-cta', buttonsClass?.no], parent: el }).onclick = () => - this.call(callback?.no); - }); + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: label?.yes ?? lang.messageBox.yes, + cls: ['mod-cta', buttonsClass?.yes], + parent: el, + }).onclick = () => this.call(callback?.yes); + el.createEl('button', { + text: label?.no ?? lang.messageBox.no, + cls: ['mod-cta', buttonsClass?.no], + parent: el, + }).onclick = () => this.call(callback?.no); + } + ); break; case 'Ok': - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: label?.ok ?? lang.messageBox.ok, cls: ['mod-cta', buttonsClass?.no], parent: el }).onclick = () => - this.call(callback?.ok); - }); + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: label?.ok ?? lang.messageBox.ok, + cls: ['mod-cta', buttonsClass?.no], + parent: el, + }).onclick = () => this.call(callback?.ok); + } + ); break; case 'OkCancel': - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: label?.ok ?? lang.messageBox.ok, cls: ['mod-cta', buttonsClass?.ok], parent: el }).onclick = () => - this.call(callback?.ok); - el.createEl('button', { - text: label?.cancel ?? lang.messageBox.cancel, - cls: ['mod-cta', buttonsClass?.cancel], - parent: el, - }).onclick = () => this.call(callback?.cancel); - }); + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: label?.ok ?? lang.messageBox.ok, + cls: ['mod-cta', buttonsClass?.ok], + parent: el, + }).onclick = () => this.call(callback?.ok); + el.createEl('button', { + text: label?.cancel ?? lang.messageBox.cancel, + cls: ['mod-cta', buttonsClass?.cancel], + parent: el, + }).onclick = () => this.call(callback?.cancel); + } + ); break; } } diff --git a/src/ui/rename_modal.ts b/src/ui/rename_modal.ts index 8c2e56d..69ce70c 100644 --- a/src/ui/rename_modal.ts +++ b/src/ui/rename_modal.ts @@ -9,7 +9,12 @@ export class RenemeModal extends Modal { get lang() { return this.settingTab.lang; } - constructor(app: App, settingTab: ExportSettingTab, setting: ExportSetting, callback: (name: string) => void) { + constructor( + app: App, + settingTab: ExportSettingTab, + setting: ExportSetting, + callback: (name: string) => void + ) { super(app); this.settingTab = settingTab; this.setting = setting; @@ -26,13 +31,21 @@ export class RenemeModal extends Modal { cb.setValue(setting.name).onChange(v => (name = v)); }); - contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => { - el.createEl('button', { text: lang.save, cls: ['mod-cta'], parent: el }).onclick = async () => { - // success - this.callback(name); - this.close(); - }; - }); + contentEl.createEl( + 'div', + { cls: ['modal-button-container'], parent: contentEl }, + el => { + el.createEl('button', { + text: lang.save, + cls: ['mod-cta'], + parent: el, + }).onclick = async () => { + // success + this.callback(name); + this.close(); + }; + } + ); } onClose() { diff --git a/src/ui/setting_tab.ts b/src/ui/setting_tab.ts index 7f58cf3..5604c65 100644 --- a/src/ui/setting_tab.ts +++ b/src/ui/setting_tab.ts @@ -33,18 +33,30 @@ export class ExportSettingTab extends PluginSettingTab { display(): void { const { containerEl, lang, plugin } = this; containerEl.empty(); - const validateCallback = (v: unknown, k: keyof typeof t, t: unknown): boolean => { + const validateCallback = ( + v: unknown, + k: keyof typeof t, + t: unknown + ): boolean => { const sv = t[k]; if (v === sv) { return false; } // noinspection RedundantIfStatementJS - if (k !== 'lastEditName' && sv === undefined && (v === false || v === '')) { + if ( + k !== 'lastEditName' && + sv === undefined && + (v === false || v === '') + ) { return false; } return true; }; - const changedCallback = async (v: unknown, k: keyof typeof t, t: unknown) => { + const changedCallback = async ( + v: unknown, + k: keyof typeof t, + t: unknown + ) => { if (v !== undefined) { if (v === false || (typeof v === 'string' && v.trim() === '')) { delete t[k]; @@ -58,18 +70,24 @@ export class ExportSettingTab extends PluginSettingTab { onChangedCallback: changedCallback, }); - const settingWatcher = new Watcher({ onChangingCallback: validateCallback, onChangedCallback: changedCallback }); + const settingWatcher = new Watcher({ + onChangingCallback: validateCallback, + onChangedCallback: changedCallback, + }); const pandocSettingWatcher = settingWatcher.as(); const customSettingWatcher = settingWatcher.as(); let globalSetting = new Proxy(plugin.settings, globalSettingWatcher); let current = new Proxy( - globalSetting.items.find(v => v.name === globalSetting.lastEditName) ?? globalSetting.items.first(), + globalSetting.items.find(v => v.name === globalSetting.lastEditName) ?? + globalSetting.items.first(), settingWatcher ); const changeEditExportSetting = (name: string) => { - const newSetting = globalSetting.items.find(v => v.name === name) ?? globalSetting.items.first(); + const newSetting = + globalSetting.items.find(v => v.name === name) ?? + globalSetting.items.first(); if (globalSetting.lastEditName !== newSetting.name) { globalSetting.lastEditName = newSetting.name; } @@ -101,7 +119,10 @@ export class ExportSettingTab extends PluginSettingTab { new Setting(containerEl).setName(lang.pandocPath).addText(cb => { cb.setPlaceholder(lang.pandocPathPlaceholder).onChange(v => { if (globalSetting.pandocPath !== v) { - globalSetting.pandocPath = setPlatformValue(globalSetting.pandocPath, v); + globalSetting.pandocPath = setPlatformValue( + globalSetting.pandocPath, + v + ); } }); @@ -110,62 +131,84 @@ export class ExportSettingTab extends PluginSettingTab { }); }); - new Setting(containerEl).setName(lang.defaultFolderForExportedFile).addDropdown(cb => { - cb.addOptions({ - 'Auto': lang.auto, - 'Same': lang.sameFolderWithCurrentFile, - 'Custom': lang.customLocation, - }).onChange((v: 'Auto' | 'Same' | 'Custom') => { - if (globalSetting.defaultExportDirectoryMode !== v) { - globalSetting.defaultExportDirectoryMode = v; - } - }); - globalSettingWatcher.watchOnChanged('defaultExportDirectoryMode', (value: 'Auto' | 'Same' | 'Custom') => { - cb.setValue(value); + new Setting(containerEl) + .setName(lang.defaultFolderForExportedFile) + .addDropdown(cb => { + cb.addOptions({ + 'Auto': lang.auto, + 'Same': lang.sameFolderWithCurrentFile, + 'Custom': lang.customLocation, + }).onChange((v: 'Auto' | 'Same' | 'Custom') => { + if (globalSetting.defaultExportDirectoryMode !== v) { + globalSetting.defaultExportDirectoryMode = v; + } + }); + globalSettingWatcher.watchOnChanged( + 'defaultExportDirectoryMode', + (value: 'Auto' | 'Same' | 'Custom') => { + cb.setValue(value); + } + ); }); - }); const customDefaultExportDirectorySetting = new Setting(containerEl) .addText(cb => { - globalSettingWatcher.watchOnChanged('customDefaultExportDirectory', (value?) => { - const val = getPlatformValue(value); - cb.setValue(val ?? ''); - setTooltip(cb.inputEl, val); - }); + globalSettingWatcher.watchOnChanged( + 'customDefaultExportDirectory', + (value?) => { + const val = getPlatformValue(value); + cb.setValue(val ?? ''); + setTooltip(cb.inputEl, val); + } + ); }) .setClass('ex-setting-item') .addExtraButton(cb => { cb.setIcon('folder').onClick(async () => { const retval = await ct.remote.dialog.showOpenDialog({ - defaultPath: getPlatformValue(globalSetting.customDefaultExportDirectory) ?? ct.remote.app.getPath('documents'), + defaultPath: + getPlatformValue(globalSetting.customDefaultExportDirectory) ?? + ct.remote.app.getPath('documents'), properties: ['createDirectory', 'openDirectory'], }); if (!retval.canceled && retval.filePaths.length > 0) { - globalSetting.customDefaultExportDirectory = setPlatformValue(globalSetting.customDefaultExportDirectory, retval.filePaths[0]); + globalSetting.customDefaultExportDirectory = setPlatformValue( + globalSetting.customDefaultExportDirectory, + retval.filePaths[0] + ); } }); - globalSettingWatcher.watchOnChanged('customDefaultExportDirectory', value => { - const text = customDefaultExportDirectorySetting.components.first() as TextComponent; - const val = getPlatformValue(value); - text.setValue(val ?? ''); - setTooltip(text.inputEl, val); - }); + globalSettingWatcher.watchOnChanged( + 'customDefaultExportDirectory', + value => { + const text = + customDefaultExportDirectorySetting.components.first() as TextComponent; + const val = getPlatformValue(value); + text.setValue(val ?? ''); + setTooltip(text.inputEl, val); + } + ); }); globalSettingWatcher.watchOnChanged('defaultExportDirectoryMode', value => { - setVisible(customDefaultExportDirectorySetting.settingEl, value === 'Custom'); + setVisible( + customDefaultExportDirectorySetting.settingEl, + value === 'Custom' + ); }); - new Setting(containerEl).setName(lang.openExportedFileLocation).addToggle(cb => { - cb.onChange(v => { - if (globalSetting.openExportedFileLocation !== v) { - globalSetting.openExportedFileLocation = v; - } - }); - globalSettingWatcher.watchOnChanged('openExportedFileLocation', v => { - cb.setValue(v); + new Setting(containerEl) + .setName(lang.openExportedFileLocation) + .addToggle(cb => { + cb.onChange(v => { + if (globalSetting.openExportedFileLocation !== v) { + globalSetting.openExportedFileLocation = v; + } + }); + globalSettingWatcher.watchOnChanged('openExportedFileLocation', v => { + cb.setValue(v); + }); }); - }); new Setting(containerEl).setName(lang.openExportedFile).addToggle(cb => { cb.onChange(v => { @@ -190,11 +233,16 @@ export class ExportSettingTab extends PluginSettingTab { changeEditExportSetting(v); } }); - globalSettingWatcher.watchOnChanged('items', (value: ExportSetting[]) => { - cb.selectEl.empty(); - cb.addOptions(Object.fromEntries(value.map(o => [o.name, o.name]))); - cb.setValue(globalSetting.lastEditName ?? globalSetting.items.first()?.name); - }); + globalSettingWatcher.watchOnChanged( + 'items', + (value: ExportSetting[]) => { + cb.selectEl.empty(); + cb.addOptions(Object.fromEntries(value.map(o => [o.name, o.name]))); + cb.setValue( + globalSetting.lastEditName ?? globalSetting.items.first()?.name + ); + } + ); globalSettingWatcher.watchOnChanged('lastEditName', value => { cb.setValue(value); }); @@ -224,85 +272,103 @@ export class ExportSettingTab extends PluginSettingTab { button.setTooltip(lang.remove); button.setIcon('trash'); button.onClick(() => { - globalSetting.items = globalSetting.items.filter(o => o.name != current.name); + globalSetting.items = globalSetting.items.filter( + o => o.name != current.name + ); changeEditExportSetting(globalSetting.items.first()?.name); }); }); - const commandSetting = new Setting(containerEl).setName(lang.command).addText(cb => { - cb.setDisabled(true); - cb.onChange(v => { - if (current.type === 'custom' && current.command !== v) { - current.command = v; - } - }); - customSettingWatcher.watchOnChanged('command', value => { - cb.setValue(value); + const commandSetting = new Setting(containerEl) + .setName(lang.command) + .addText(cb => { + cb.setDisabled(true); + cb.onChange(v => { + if (current.type === 'custom' && current.command !== v) { + current.command = v; + } + }); + customSettingWatcher.watchOnChanged('command', value => { + cb.setValue(value); + }); + settingWatcher.watchOnChanged('type', value => { + cb.setDisabled(value !== 'custom'); + }); }); - }); settingWatcher.watchOnChanged('type', value => { setVisible(commandSetting.settingEl, value === 'custom'); }); - const argumentsSetting = new Setting(containerEl).setName(lang.arguments).addText(cb => { - cb.setDisabled(true); - cb.onChange(v => { - if (current.type === 'pandoc' && current.arguments !== v) { - current.arguments = v; - setTooltip(cb.inputEl, current.arguments); - } - }); - pandocSettingWatcher.watchOnChanged('arguments', value => { - cb.setValue(value ?? ''); - setTooltip(cb.inputEl, value); + const argumentsSetting = new Setting(containerEl) + .setName(lang.arguments) + .addText(cb => { + cb.setDisabled(true); + cb.onChange(v => { + if (current.type === 'pandoc' && current.arguments !== v) { + current.arguments = v; + setTooltip(cb.inputEl, current.arguments); + } + }); + pandocSettingWatcher.watchOnChanged('arguments', value => { + cb.setValue(value ?? ''); + setTooltip(cb.inputEl, value); + }); + settingWatcher.watchOnChanged('type', value => { + cb.setDisabled(value !== 'custom'); + }); }); - }); settingWatcher.watchOnChanged('type', value => { setVisible(argumentsSetting.settingEl, value === 'pandoc'); }); - const customArgumentsSetting = new Setting(containerEl).setName(lang.extraArguments).addText(cb => { - cb.onChange(v => { - if (current.type === 'pandoc' && current.customArguments !== v) { - current.customArguments = v; - } - }); - pandocSettingWatcher.watchOnChanged('customArguments', value => { - cb.setValue(value ?? ''); - setTooltip(cb.inputEl, value); + const customArgumentsSetting = new Setting(containerEl) + .setName(lang.extraArguments) + .addText(cb => { + cb.onChange(v => { + if (current.type === 'pandoc' && current.customArguments !== v) { + current.customArguments = v; + } + }); + pandocSettingWatcher.watchOnChanged('customArguments', value => { + cb.setValue(value ?? ''); + setTooltip(cb.inputEl, value); + }); }); - }); settingWatcher.watchOnChanged('type', value => { setVisible(customArgumentsSetting.settingEl, value === 'pandoc'); }); new Setting(containerEl).setName(lang.afterExport).setHeading(); - const showCommandOutputSetting = new Setting(containerEl).setName(lang.showCommandOutput).addToggle(cb => { - if (current.type === 'custom') { - cb.setValue(current.showCommandOutput); - } - cb.onChange(v => { - if (current.type === 'custom' && current.showCommandOutput !== v) { - current.showCommandOutput = v; + const showCommandOutputSetting = new Setting(containerEl) + .setName(lang.showCommandOutput) + .addToggle(cb => { + if (current.type === 'custom') { + cb.setValue(current.showCommandOutput); } + cb.onChange(v => { + if (current.type === 'custom' && current.showCommandOutput !== v) { + current.showCommandOutput = v; + } + }); }); - }); settingWatcher.watchOnChanged('type', value => { setVisible(showCommandOutputSetting.settingEl, value === 'custom'); }); - new Setting(containerEl).setName(lang.openExportedFileLocation).addToggle(cb => { - cb.onChange(v => { - if (current.openExportedFileLocation !== v) { - current.openExportedFileLocation = v; - } - }); + new Setting(containerEl) + .setName(lang.openExportedFileLocation) + .addToggle(cb => { + cb.onChange(v => { + if (current.openExportedFileLocation !== v) { + current.openExportedFileLocation = v; + } + }); - settingWatcher.watchOnChanged('openExportedFileLocation', value => { - cb.setValue(value); + settingWatcher.watchOnChanged('openExportedFileLocation', value => { + cb.setValue(value); + }); }); - }); new Setting(containerEl).setName(lang.runCommand).addToggle(cb => { cb.onChange(v => { @@ -327,7 +393,10 @@ export class ExportSettingTab extends PluginSettingTab { }); pandocSettingWatcher.watchOnChanged('runCommand', (value, _, target) => { - setVisible(commandAfterExportSetting.settingEl, target.type === 'pandoc' && value); + setVisible( + commandAfterExportSetting.settingEl, + target.type === 'pandoc' && value + ); cb.setValue(current.command); }); }); diff --git a/src/utils.ts b/src/utils.ts index 5c0bd07..8bad8fc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,7 @@ -export function strTpl(strings: TemplateStringsArray, ...keys: number[]): (...values: any[]) => string { +export function strTpl( + strings: TemplateStringsArray, + ...keys: number[] +): (...values: any[]) => string { return function (...values) { const dict = values[values.length - 1] || {}; const result = [strings[0]]; @@ -34,15 +37,26 @@ export const nameofFactory = (name: keyof T) => name; -type TOnChangingHandler = (value: T[K], key: K, target: T) => boolean; -type TOnChangedHandler = (value: T[K], key: K, target: T) => void; +type TOnChangingHandler = ( + value: T[K], + key: K, + target: T +) => boolean; +type TOnChangedHandler = ( + value: T[K], + key: K, + target: T +) => void; export class Watcher { onChanging: { [k in keyof T]?: TOnChangingHandler[] }; onChanged: { [k in keyof T]?: TOnChangedHandler[] }; private readonly _onChangingCallback: TOnChangingHandler; private readonly _onChangedCallback: TOnChangedHandler; - constructor(options?: { onChangingCallback?: TOnChangingHandler; onChangedCallback?: TOnChangedHandler }) { + constructor(options?: { + onChangingCallback?: TOnChangingHandler; + onChangedCallback?: TOnChangedHandler; + }) { this.onChanging = {}; this.onChanged = {}; this._onChangingCallback = options?.onChangingCallback ?? (() => true); @@ -51,15 +65,29 @@ export class Watcher { as(): Watcher { return this as unknown as Watcher; } - watchOnChanging(key: K, handler: TOnChangingHandler): void { + watchOnChanging( + key: K, + handler: TOnChangingHandler + ): void { (this.onChanging[key] ?? (this.onChanging[key] = [])).push(handler); } - watchOnChanged(key: K, handler: TOnChangedHandler): void { + watchOnChanged( + key: K, + handler: TOnChangedHandler + ): void { (this.onChanged[key] ?? (this.onChanged[key] = [])).push(handler); } - set(target: T, key: K, value: T[K], _receiver: T): boolean { - if (this._onChangingCallback && this._onChangingCallback(value, key, target) === false) { + set( + target: T, + key: K, + value: T[K], + _receiver: T + ): boolean { + if ( + this._onChangingCallback && + this._onChangingCallback(value, key, target) === false + ) { return false; } const onChangingHandlers = this.onChanging[key]; diff --git a/versions.json b/versions.json index 39946bd..fcfd035 100644 --- a/versions.json +++ b/versions.json @@ -1,3 +1,4 @@ { - "1.0.4": "0.12.0" + "1.0.4": "0.12.0", + "1.0.5": "0.12.0" } \ No newline at end of file