From df1904edae85530fe162a53588cb6ee33ff9d7fa Mon Sep 17 00:00:00 2001 From: Tron Date: Sun, 1 Dec 2024 22:10:36 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=96v1.2.0=20/=202024.12.01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ✨ 脚注内容模板支持编号${index}, 主要用于脚注编号 - 🔥 取消脚注启用编号对脚注内容块添加命名的操作 ![](https://fastly.jsdelivr.net/gh/Achuan-2/PicBed/assets/脚注内容块支持编号变量-2024-12-01.gif) --- CHANGELOG.md | 8 +++ README_zh_CN.md | 54 +++----------- public/i18n/zh_CN.json | 2 +- src/index.ts | 155 +++++++++++++++++++++++++---------------- 4 files changed, 114 insertions(+), 105 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12887bb..388418e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ + +## v1.2.0 / 2024.12.01 + +- ✨ 脚注内容模板支持编号${index}, 主要用于脚注编号 +- 🔥 取消脚注启用编号对脚注内容块添加命名的操作 + + ![](https://fastly.jsdelivr.net/gh/Achuan-2/PicBed/assets/脚注内容块支持编号变量-2024-12-01.gif) + ## v1.1.9 / 2024.12.01 - 📝README 补充插件的命令介绍 - ✨ 命令面板添加取消脚注自动编号命令 #17 diff --git a/README_zh_CN.md b/README_zh_CN.md index 02306a6..80cd0cc 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -8,6 +8,13 @@ ## 📝更新日志 +v1.2.0 / 2024.12.01 + +- ✨ 脚注内容模板支持编号${index}, 主要用于脚注编号 +- 🔥 取消脚注启用编号对脚注内容块添加命名的操作 + + ![](https://fastly.jsdelivr.net/gh/Achuan-2/PicBed/assets/脚注内容块支持编号变量-2024-12-01.gif) + v1.1.7 - ✨ 现在不勾选脚注自动编号时,添加脚注的弹窗可以使用思源富文本功能编辑脚注内容啦,但是勾选脚注自动编号,还是只能纯文本格式添加脚注内容 @@ -55,7 +62,7 @@ v1.1.6 / 2024.11.30 脚注支持脚注数字编号啦! * **选中文本的样式**:选择无样式或自定义样式。默认:`无样式`​。 * **脚注自动数字编号**:使用数字编号(如[1], [2]等)替代自定义锚文本。开启后每次新建和删除脚注会自动对所有脚注重新排序编号。 注意:目前开启此项,当脚注数量越多,排序耗时越长,介意请勿开启。 - * **脚注内容模板**:设置生成脚注内容的样式,推荐使用嵌套引述块或超级块来存放脚注内容,保证脚注内容属于同一个块,`${selection}`​代表选中文本的内容,`${content}`​代表脚注内容占位,`${refID}`​代表选中文本所在的块的ID。另外可以使用kramdown语法设置脚注内容块的块样式。 + * **脚注内容模板**:设置生成脚注内容的样式,推荐使用嵌套引述块或超级块来存放脚注内容,保证脚注内容属于同一个块,`${selection}`​代表选中文本的内容,`${content}`​代表脚注内容占位,`${refID}`​代表选中文本所在的块的ID,`${index}`脚注编号默认带原块链接,`${index:text}`脚注编号纯文本。另外可以使用kramdown语法设置脚注内容块的块样式。 * **脚注内容块的别名**:设置脚注内容块的别名,提示这个块是脚注内容,设置为空则不设置别名。默认为空。 * **自定义样式**:自定义脚注块引、添加脚注时选中文字的样式、脚注内容块的样式。 * **重置设置**:重置插件设置为默认值 @@ -96,7 +103,8 @@ v1.1.6 / 2024.11.30 脚注支持脚注数字编号啦! * ​`${selection}`​代表选中文本的内容 * ​`${content}`​代表脚注内容占位 -* ​`${refID}`​代表选中文本所在的块的ID。 +* ​`${refID}`​代表选中文本所在的块的ID +* `${index}`脚注编号默认带原块链接,`${index:text}`脚注编号纯文本 下面列举一些用户可能用到的模板 @@ -206,48 +214,6 @@ ${content} color: var(--b3-font-color5); } ``` - -### 如何模拟传统的脚注编号样式 - -​![](https://fastly.jsdelivr.net/gh/Achuan-2/PicBed/assets/PixPin_2024-11-30_19-31-33-2024-11-30.png)​ - -如果你想让脚注插件生成的脚注模拟传统的脚注编号样式,可以这样设置 - -1. 开启【脚注自动数字编号】功能 -2. 插件设置中脚注内容模板设置为 - - ```markdown - ${content} - ``` -3. 插件设置中的自定义样式可以设置为 - - ```css - /* 为脚注内容块添加相对定位,作为编号定位的参考 */ - .protyle-wysiwyg [data-node-id][custom-plugin-footnote-content] { - position: relative; - padding-left: 2em; /* 为编号预留空间 */ - font-size: 0.8em; /* 设置字体大小 */ - } - - /* 编号使用绝对定位,实现悬挂效果 */ - .protyle-wysiwyg [data-node-id][custom-plugin-footnote-content]:before { - content: '[' attr(name) ']'; - position: absolute; - left: 0; /* 编号靠左对齐 */ - top: 2px; /* 与内容顶部对齐 */ - } - - /* 脚注内容块保持块级显示,确保换行正确 */ - .protyle-wysiwyg [data-node-id][custom-plugin-footnote-content]>div:first-child { - display: block; - } - - /* 隐藏脚注内容块命名 */ - .protyle-wysiwyg [data-node-id][custom-plugin-footnote-content]>div:nth-child(2)>.protyle-attr--name { - display: none; - } - ``` - ​​ ## 🙏致谢 diff --git a/public/i18n/zh_CN.json b/public/i18n/zh_CN.json index 2c16700..99ebcc6 100644 --- a/public/i18n/zh_CN.json +++ b/public/i18n/zh_CN.json @@ -69,7 +69,7 @@ }, "template": { "title": "脚注内容模版", - "description": "模板变量:${selection}选中文本的内容,${content}脚注内容占位,${refID}选中文本所在的块的ID
使用${{...}}可以使用Sprig语法,例如插入当前时间${{now | date \"20060102 15:04:05\"}}
可以使用kramdown语法设置块样式" + "description": "模板变量:${selection}选中文本的内容,${content}脚注内容占位,${refID}选中文本所在的块的ID,${index}脚注编号默认带原块链接,${index:text}脚注编号纯文本
使用${{...}}可以使用Sprig语法,例如插入当前时间${{now | date \"20060102 15:04:05\"}}
可以使用kramdown语法设置块样式" }, "footnoteAlias": { "title": "脚注内容块的别名", diff --git a/src/index.ts b/src/index.ts index ec40262..26ddb48 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ import { import "@/index.scss"; import { IMenuItem } from "siyuan/types"; -import { appendBlock, deleteBlock, setBlockAttrs, getBlockAttrs, pushMsg, pushErrMsg, sql, renderSprig, getChildBlocks, insertBlock, renameDocByID, prependBlock, updateBlock, createDocWithMd, getDoc, getBlockKramdown } from "./api"; +import { appendBlock, deleteBlock, setBlockAttrs, getBlockAttrs, pushMsg, pushErrMsg, sql, renderSprig, getChildBlocks, insertBlock, renameDocByID, prependBlock, updateBlock, createDocWithMd, getDoc, getBlockKramdown, getBlockDOM } from "./api"; import { SettingUtils } from "./libs/setting-utils"; const STORAGE_NAME = "config"; @@ -327,11 +327,8 @@ export default class PluginFootnote extends Plugin { footnoteBlockref: this.i18n.settings.footnoteBlockref.value, selectFontStyle: '1', templates: `{{{row -> \${selection} [[↩️]](siyuan://blocks/\${refID}) - -\${content} -}}} -{: style="border: 2px dashed var(--b3-border-color);"}}`, +\${index} \${content} +}}}`, enableOrderedFootnotes: false, // Add new setting footnoteAlias: '', css: this.STYLES @@ -399,7 +396,7 @@ export default class PluginFootnote extends Plugin { }, editorCallback: async (protyle: any) => { if (protyle.block?.rootID) { - await this.reorderFootnotes(protyle.block.rootID, true); + await this.reorderFootnotes(protyle.block.rootID, true); await pushMsg(this.i18n.cancelReorderFootnotes + " ..."); await pushMsg(this.i18n.cancelReorderFootnotes + " Finished"); } @@ -544,12 +541,7 @@ export default class PluginFootnote extends Plugin { this.settingUtils.addItem({ key: "templates", - value: `{{{row -> \${selection} [[↩️]](siyuan://blocks/\${refID}) - -\${content} -}}} -{: style="border: 2px dashed var(--b3-border-color);"}}`, + value: this.getDefaultSettings().templates, type: "textarea", title: this.i18n.settings.template.title, description: this.i18n.settings.template.description, @@ -865,6 +857,8 @@ export default class PluginFootnote extends Plugin { templates = templates.replace(/\$\{selection\}/g, cleanSelection); templates = templates.replace(/\$\{content\}/g, zeroWhite); templates = templates.replace(/\$\{refID\}/g, currentBlockId); + templates = templates.replace(/\$\{index\}/g, `[注]`); // 支持添加脚注编号 + templates = templates.replace(/\$\{index:text\}/g, `[注]`); // 支持添加脚注编号 templates = await renderTemplates(templates); async function renderTemplates(templates: string): Promise { @@ -1057,6 +1051,20 @@ export default class PluginFootnote extends Plugin { async (content) => { // Get existing block attributes before update const existingAttrs = await getBlockAttrs(newBlockId); + // 获取脚注内容块的内容 + const originDOM = (await getBlockDOM(newBlockId)).dom; + + // DOM是string,使用正则表达式检测是否span[data - type*= "custom-footnote-index"]节点,如果有则提取其[number]中的数字 + let number = 0; + if (originDOM) { + // 使用 .*? 来匹配 data-type 中任意的前缀值 + const match = originDOM.match(/[${number}]`) // 支持添加脚注编号 + .replace(/\$\{index:text\}/g, `[${number}]`); // 支持添加脚注编号 const renderedTemplate = await renderTemplates(templates); @@ -1075,7 +1085,7 @@ export default class PluginFootnote extends Plugin { if (existingAttrs) { await setBlockAttrs(newBlockId, { "custom-plugin-footnote-content": existingAttrs["custom-plugin-footnote-content"], - "name": existingAttrs["name"], + // "name": existingAttrs["name"], "alias": existingAttrs["alias"] }); } @@ -1167,33 +1177,52 @@ export default class PluginFootnote extends Plugin { }); // Reorder footnote blocks if needed + // 获取脚注块并更新编号 const footnoteBlocks = Array.from(footnoteContainerDom.querySelectorAll(`[custom-plugin-footnote-content="${docID}"]`)); - if (footnoteBlocks.length > 0 && reorderBlocks) { - const parent = footnoteBlocks[0].parentNode; - if (parent) { - let referenceNode = footnoteBlocks[0].previousSibling; - footnoteBlocks.forEach(block => block.remove()); - - // Sort and reinsert blocks - footnoteBlocks - .sort((a, b) => { - const aId = a.getAttribute('data-node-id'); - const bId = b.getAttribute('data-node-id'); - const aOrder = footnoteOrder.get(aId) || Infinity; - const bOrder = footnoteOrder.get(bId) || Infinity; - return aOrder - bOrder; - }) - .forEach(block => { - if (referenceNode) { - referenceNode.after(block); - referenceNode = block; - } else { - parent.insertBefore(block, parent.firstChild); + if (footnoteBlocks.length > 0) { + footnoteBlocks.forEach(block => { + // 获取脚注块的ID + const blockId = block.getAttribute('data-node-id'); + if (blockId) { + // 获取该块对应的编号 + const number = footnoteOrder.get(blockId); + if (number) { + // 查找并更新块内的索引编号元素 + const indexSpan = block.querySelector('span[data-type*="custom-footnote-index"]'); + if (indexSpan) { + indexSpan.textContent = `[${number}]`; } - }); + } + } + }); + + // 如果需要重排序 + if (reorderBlocks) { + const parent = footnoteBlocks[0].parentNode; + if (parent) { + let referenceNode = footnoteBlocks[0].previousSibling; + footnoteBlocks.forEach(block => block.remove()); + + // 排序并重新插入块 + footnoteBlocks + .sort((a, b) => { + const aId = a.getAttribute('data-node-id'); + const bId = b.getAttribute('data-node-id'); + const aOrder = footnoteOrder.get(aId) || Infinity; + const bOrder = footnoteOrder.get(bId) || Infinity; + return aOrder - bOrder; + }) + .forEach(block => { + if (referenceNode) { + referenceNode.after(block); + referenceNode = block; + } else { + parent.insertBefore(block, parent.firstChild); + } + }); + } } } - // Save changes if (protyle) { // 应该获取protyle.wysiwyg.element.innerHTML @@ -1204,31 +1233,31 @@ export default class PluginFootnote extends Plugin { await updateBlock("dom", currentDom.body.innerHTML, docID); } if (footnoteContainerDocID !== docID) { - console.log("不一样") await updateBlock("dom", footnoteContainerDom.body.innerHTML, footnoteContainerDocID); } // Update footnote block attributes - await Promise.all( - Array.from(blockRefs).map(async ref => { - const blockId = ref.getAttribute('custom-footnote'); - const number = footnoteOrder.get(blockId); - - // Improved block existence check - if (blockId && number) { - // Query the database to check if block exists - const blockExists = await sql( - `SELECT id FROM blocks WHERE id = '${blockId}' LIMIT 1` - ); - - if (blockExists && blockExists.length > 0) { - return setBlockAttrs(blockId, { "name": number.toString() }); - } - } - }).filter(Boolean) - ); + // await Promise.all( + // Array.from(blockRefs).map(async ref => { + // const blockId = ref.getAttribute('custom-footnote'); + // const number = footnoteOrder.get(blockId); + + // // Improved block existence check + // if (blockId && number) { + // // Query the database to check if block exists + // const blockExists = await sql( + // `SELECT id FROM blocks WHERE id = '${blockId}' LIMIT 1` + // ); + + // if (blockExists && blockExists.length > 0) { + // return setBlockAttrs(blockId, { "name": number.toString() }); + // } + // } + // }).filter(Boolean) + // ); } + // TODO: 脚注内容块改为用(await getBlockDOM(footnoteId)).dom获取dom,然后使用正则表达式将span[data-type*="custom-footnote-index"]的textContent替换[注] private async cancelReorderFootnotes(docID: string, reorderBlocks: boolean) { // Get current document DOM const doc = await getDoc(docID); @@ -1245,19 +1274,25 @@ export default class PluginFootnote extends Plugin { ref.textContent = defaultAnchor; const footnoteId = ref.getAttribute('custom-footnote'); if (footnoteId && !footnoteIds.has(footnoteId)) { - footnoteIds.add(footnoteId); + footnoteIds.add(footnoteId); } }); // update dom await updateBlock("dom", currentDom.body.innerHTML, docID); - // Update footnote block attributes + // Update footnote blocks await Promise.all( Array.from(footnoteIds).map(async footnoteId => { - return setBlockAttrs(footnoteId, { "name": "" }); + let footnoteBlock = (await getBlockDOM(footnoteId)).dom; + if (footnoteBlock) { + footnoteBlock = footnoteBlock.replace(/(