diff --git a/README.md b/README.md index 8c5cd242..6a7264cd 100644 --- a/README.md +++ b/README.md @@ -15,21 +15,22 @@ | 5 | md_padding | 中英文混排优化 | √ | | 6 | fence_enhance | 一键复制代码,折叠代码 | √ | | 7 | commander | 命令行环境 | √ | -| 8 | read_only | 只读模式 | √ | -| 9 | file_counter | 显示目录下的文件数 | √ | -| 10 | datatables | 表格增强(搜索、过滤、分页、排序等) | √ | -| 11 | resize_table | 调整表格行高列宽 | √ | -| 12 | resize_image | 调整图片显示大小 | √ | -| 13 | auto_number | 章节、表格、图片、代码块等自动编号 | √ | -| 14 | outline | 以表格、图片、代码块形式的大纲 | √ | -| 15 | mindmap | 根据文档大纲一键生成思维导图 | √ | -| 16 | export_enhance | 导出 html 时避免图片丢失 | √ | -| 17 | go_top | 一键到文章顶部 | √ | -| 18 | truncate_text | 暂时隐藏内容,提高大文件渲染性能 | √ | -| 19 | custom | 用户自定义命令(高级) | √ | -| 20 | right_click_menu | 右键菜单统一管理、调用插件 | √ | -| 21 | mermaid_replace | 替换 mermaid 组件 | × | -| 22 | old_window_tab | 标签页管理(已废弃) | × | +| 8 | templater | 文件模板 | √ | +| 9 | read_only | 只读模式 | √ | +| 10 | file_counter | 显示目录下的文件数 | √ | +| 11 | datatables | 表格增强(搜索、过滤、分页、排序等) | √ | +| 12 | resize_table | 调整表格行高列宽 | √ | +| 13 | resize_image | 调整图片显示大小 | √ | +| 14 | auto_number | 章节、表格、图片、代码块等自动编号 | √ | +| 15 | outline | 以表格、图片、代码块形式的大纲 | √ | +| 16 | mindmap | 根据文档大纲一键生成思维导图 | √ | +| 17 | export_enhance | 导出 html 时避免图片丢失 | √ | +| 18 | go_top | 一键到文章顶部 | √ | +| 19 | truncate_text | 暂时隐藏内容,提高大文件渲染性能 | √ | +| 20 | custom | 用户自定义命令(高级) | √ | +| 21 | right_click_menu | 右键菜单统一管理、调用插件 | √ | +| 22 | mermaid_replace | 替换 mermaid 组件 | × | +| 23 | old_window_tab | 标签页管理(已废弃) | × | > 如果各位有其他的需求,或发现 BUG,欢迎提 issue。如果能给我颗 star ⭐ 就更好了 : ) @@ -497,7 +498,7 @@ module.exports = { plugin: fullPathCopy }; ![custom](assets/custom.png) - +--- ### read_only:只读模式 @@ -509,6 +510,31 @@ module.exports = { plugin: fullPathCopy }; +### templater:文件模板功能 + +类似于 obsidian 的文件模板功能,根据模板快速创建文件。 + +使用方式:右键菜单 -> 启用插件 -> 自定义插件 -> 文件模板。 + +支持的模板变量: + +- `{{date}}`: 当前日期 +- `{{time}}`:当前时间 +- `{{weekday}}`:当前周几 +- `{{datetime}}`:当前日期时间 +- `{{yesterday}}`:昨天日期 +- `{{tomorrow}}`:明天日期 +- `{{random}}`:随机数 +- `{{title}}`:新建文件的标题 +- `{{folder}}`:当前文件的目录 +- `{{filepath}}`:新建文件的路径 +- `{{range}}`:当前选取的文字 +- `{{uuid}}`:uuid + +> 模板列表可以在 `custom_plugin.toml` 中配置。 + + + ### export_enhance:导出增强 导出 html 时,将图片转为 base64,避免图片丢失。 diff --git a/plugin/custom/custom_plugin.toml b/plugin/custom/custom_plugin.toml index 64ba9dc6..3051f835 100644 --- a/plugin/custom/custom_plugin.toml +++ b/plugin/custom/custom_plugin.toml @@ -3,6 +3,7 @@ # enable: 是否启用此自定义插件 # plugin: 自定义插件 # config: 插件配置 + [[plugins]] name = "复制标题路径" enable = true @@ -17,4 +18,28 @@ name = "提取选区文字到新文件" enable = true plugin = "extractRangeToNewFile" [plugins.config] -show_modal = true \ No newline at end of file +show_modal = true + +[[plugins]] +name = "文件模板" +enable = true +plugin = "templater" +[[plugins.template]] +name = "标准模板" +text = """ +--- +title: {{title}} +tags: +date: {{date}} +--- + +""" +[[plugins.template]] +name = "日记" +text = """ +--- +title: {{title}} +date: {{date}} {{weekday}} +--- + +""" \ No newline at end of file diff --git a/plugin/custom/plugins/extractRangeToNewFile.js b/plugin/custom/plugins/extractRangeToNewFile.js index 4b145158..58966d25 100644 --- a/plugin/custom/plugins/extractRangeToNewFile.js +++ b/plugin/custom/plugins/extractRangeToNewFile.js @@ -41,32 +41,9 @@ class extractRangeToNewFile extends BaseCustomPlugin { } extract = filepath => { - const path = this.utils.Package.Path; - if (filepath) { - filepath = path.join(path.dirname(this.utils.getFilePath()), filepath); - } else { - filepath = this.utils.getFilePath(); - } - - if (this.existPath(filepath)) { - const ext = path.extname(filepath); - if (ext) { - const regex = new RegExp(`${ext}$`); - filepath = filepath.replace(regex, `--copy${ext}`); - } else { - filepath = filepath + "--copy.md"; - } - } + filepath = this.utils.newFilePath(filepath); this.promise.then(text => this.utils.Package.Fs.writeFileSync(filepath, text, "utf8")); } - - existPath = filepath => { - try { - this.utils.Package.Fs.accessSync(filepath, this.utils.Package.Fs.constants.F_OK); - return true - } catch (err) { - } - } } module.exports = { diff --git a/plugin/custom/plugins/templater.js b/plugin/custom/plugins/templater.js new file mode 100644 index 00000000..65376314 --- /dev/null +++ b/plugin/custom/plugins/templater.js @@ -0,0 +1,113 @@ +class templater extends BaseCustomPlugin { + selector = () => "" + + callback = anchorNode => { + if (!File.editor.selection.getRangy().collapsed) { + ClientCommand.copyAsMarkdown(); + window.parent.navigator.clipboard.readText().then(text => this.rangeText = text); + } + + const options = this.info.template.map(template => template.name); + this.modal({ + id: "newTemplateFile", + title: "新文件", + components: [ + { + label: "文件名", + type: "input", + value: "", + placeholder: "请输入新文件名,为空则创建副本", + }, + { + label: "模板", + type: "select", + selected: "option2", + list: options, + } + ] + }) + } + + onEvent = (eventType, payload) => { + if (eventType !== "submit" + || !payload + || !payload.id + || payload.id !== "newTemplateFile" + || !payload.components + ) return; + + let filepath = payload.components[0].submit; + filepath = this.utils.newFilePath(filepath); + const filename = this.utils.Package.Path.basename(filepath); + + const option = payload.components[1].submit; + const template = this.info.template.filter(template => template.name === option)[0]; + if (!template) return; + + const helper = new templateHelper(filename, this.rangeText, this.utils); + const content = helper.convert(template.text); + this.utils.Package.Fs.writeFileSync(filepath, content, "utf8"); + this.rangeText = ""; + } +} + +class templateHelper { + constructor(title, rangeText, utils) { + this._title = title; + this.rangeText = rangeText || ""; + this.utils = utils; + this.templateVarMap = { + date: "{{date}}", + time: "{{time}}", + weekday: "{{weekday}}", + datetime: "{{datetime}}", + yesterday: "{{yesterday}}", + tomorrow: "{{tomorrow}}", + random: "{{random}}", + title: "{{title}}", + folder: "{{folder}}", + filepath: "{{filepath}}", + range: "{{range}}", + uuid: "{{uuid}}", + } + } + + convert = text => { + for (let varName in this.templateVarMap) { + const template = this.templateVarMap[varName]; + const regex = new RegExp(template, "g"); + text = text.replace(regex, this[varName](template)); + } + return text + } + + uuid = () => this.utils.getUUID(); + range = () => this.rangeText; + random = () => Math.random(); + weekday = () => "周" + '日一二三四五六'.charAt(new Date().getDay()) + datetime = () => new Date().toLocaleString('chinese', {hour12: false}) + date = () => { + const today = new Date(); + return `${today.getFullYear()}/${today.getMonth()}/${today.getDate()}` + } + time = () => { + const today = new Date(); + return `${today.getHours()}:${today.getMinutes()}:${today.getSeconds()}` + } + yesterday = () => { + const yesterday = new Date(new Date().getTime() - (24 * 60 * 60 * 1000)); + return `${yesterday.getFullYear()}/${yesterday.getMonth()}/${yesterday.getDate()}` + } + tomorrow = () => { + const tomorrow = new Date(new Date().getTime() + (24 * 60 * 60 * 1000)); + return `${tomorrow.getFullYear()}/${tomorrow.getMonth()}/${tomorrow.getDate()}` + } + title = () => this._title + folder = () => this.utils.Package.Path.dirname(this.utils.getFilePath()) + filepath = () => this.utils.Package.Path.join(this.folder(), this.title()) +} + + +module.exports = { + plugin: templater, +}; \ No newline at end of file diff --git a/plugin/global/core/plugin.js b/plugin/global/core/plugin.js index 0d4d8647..c7615728 100644 --- a/plugin/global/core/plugin.js +++ b/plugin/global/core/plugin.js @@ -37,6 +37,14 @@ class utils { $.getScript(`file:///${jsFilepath}`).then(then); } + static getUUID() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + let r = (Math.random() * 16) | 0 + let v = c === 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); + } + static metaKeyPressed = ev => File.isMac ? ev.metaKey : ev.ctrlKey static shiftKeyPressed = ev => !!ev.shiftKey static altKeyPressed = ev => !!ev.altKey @@ -51,6 +59,33 @@ class utils { return reqnode(filepath) } + static existPath = filepath => { + try { + this.Package.Fs.accessSync(filepath, this.Package.Fs.constants.F_OK); + return true + } catch (err) { + } + } + + static newFilePath = filepath => { + if (filepath) { + filepath = this.Package.Path.join(this.Package.Path.dirname(this.getFilePath()), filepath); + } else { + filepath = this.getFilePath(); + } + + if (this.existPath(filepath)) { + const ext = this.Package.Path.extname(filepath); + if (ext) { + const regex = new RegExp(`${ext}$`); + filepath = filepath.replace(regex, `-copy${ext}`); + } else { + filepath = filepath + "-copy.md"; + } + } + return filepath + } + static readFileSync = filepath => { filepath = this.joinPath(filepath); return this.Package.Fs.readFileSync(filepath, 'utf8'); diff --git a/plugin/window_tab/index.js b/plugin/window_tab/index.js index b8718937..5f31e1b5 100644 --- a/plugin/window_tab/index.js +++ b/plugin/window_tab/index.js @@ -609,11 +609,7 @@ class windowTabBarPlugin extends global._basePlugin { exitTabFile = () => { const filepath = this.getTabFile(); - try { - this.utils.Package.Fs.accessSync(filepath, this.utils.Package.Fs.constants.F_OK); - return true - } catch (err) { - } + return this.utils.existPath(filepath) } saveTabs = () => {