Skip to content

Commit

Permalink
🔖v1.2.0 / 2024.12.01
Browse files Browse the repository at this point in the history
- ✨ 脚注内容模板支持编号${index}, 主要用于脚注编号
- 🔥 取消脚注启用编号对脚注内容块添加命名的操作

   ![](https://fastly.jsdelivr.net/gh/Achuan-2/PicBed/assets/脚注内容块支持编号变量-2024-12-01.gif)
  • Loading branch information
Achuan-2 committed Dec 1, 2024
1 parent aeb8afd commit df1904e
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 105 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
54 changes: 10 additions & 44 deletions README_zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

- ✨ 现在不勾选脚注自动编号时,添加脚注的弹窗可以使用思源富文本功能编辑脚注内容啦,但是勾选脚注自动编号,还是只能纯文本格式添加脚注内容
Expand Down Expand Up @@ -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语法设置脚注内容块的块样式。
* **脚注内容块的别名**:设置脚注内容块的别名,提示这个块是脚注内容,设置为空则不设置别名。默认为空。
* **自定义样式**:自定义脚注块引、添加脚注时选中文字的样式、脚注内容块的样式。
* **重置设置**:重置插件设置为默认值
Expand Down Expand Up @@ -96,7 +103,8 @@ v1.1.6 / 2024.11.30 脚注支持脚注数字编号啦!

*`${selection}`​代表选中文本的内容
*`${content}`​代表脚注内容占位
*`${refID}`​代表选中文本所在的块的ID。
*`${refID}`​代表选中文本所在的块的ID
* `${index}`脚注编号默认带原块链接,`${index:text}`脚注编号纯文本

下面列举一些用户可能用到的模板

Expand Down Expand Up @@ -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;
}
```

​​

## 🙏致谢
Expand Down
2 changes: 1 addition & 1 deletion public/i18n/zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
},
"template": {
"title": "脚注内容模版",
"description": "模板变量:<code>${selection}</code>选中文本的内容,<code>${content}</code>脚注内容占位,<code>${refID}</code>选中文本所在的块的ID<br/>使用<code>${{...}}</code>可以使用Sprig语法,例如插入当前时间<code>${{now | date \"20060102 15:04:05\"}}</code></br>可以使用kramdown语法设置块样式"
"description": "模板变量:<code>${selection}</code>选中文本的内容,<code>${content}</code>脚注内容占位,<code>${refID}</code>选中文本所在的块的ID,<code>${index}</code>脚注编号默认带原块链接,<code>${index:text}</code>脚注编号纯文本</br>使用<code>${{...}}</code>可以使用Sprig语法,例如插入当前时间<code>${{now | date \"20060102 15:04:05\"}}</code></br>可以使用kramdown语法设置块样式"
},
"footnoteAlias": {
"title": "脚注内容块的别名",
Expand Down
155 changes: 95 additions & 60 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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, `<span data-type="custom-footnote-index a" data-href="siyuan://blocks/${currentBlockId}">[注]</span>`); // 支持添加脚注编号
templates = templates.replace(/\$\{index:text\}/g, `<span data-type="custom-footnote-index">[注]</span>`); // 支持添加脚注编号
templates = await renderTemplates(templates);

async function renderTemplates(templates: string): Promise<string> {
Expand Down Expand Up @@ -1057,14 +1051,30 @@ 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(/<span data-type=".*?custom-footnote-index[^>]*>\[(\d+)\]<\/span>/);
if (match) {
number = parseInt(match[1]);
}
}

//
// 把content的多余空行去除
content = content.replace(/(\r\n|\n|\r){2,}/g, '\n');

// Update the footnote content
const templates = this.settingUtils.get("templates")
.replace(/\$\{selection\}/g, cleanSelection)
.replace(/\$\{content\}/g, content)
.replace(/\$\{refID\}/g, currentBlockId);
.replace(/\$\{refID\}/g, currentBlockId)
.replace(/\$\{index\}/g, `<span data-type="custom-footnote-index a" data-href="siyuan://blocks/${currentBlockId}">[${number}]</span>`) // 支持添加脚注编号
.replace(/\$\{index:text\}/g, `<span data-type="custom-footnote-index">[${number}]</span>`); // 支持添加脚注编号

const renderedTemplate = await renderTemplates(templates);

Expand All @@ -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"]
});
}
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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(/(<span data-type=".*?custom-footnote-index[^>]*>)\[\d+\](<\/span>)/g, '$1[注]$2');
}
updateBlock("dom", footnoteBlock, footnoteId);
// return setBlockAttrs(footnoteId, { "name": "" });
})
);
}

}


Expand Down

0 comments on commit df1904e

Please sign in to comment.