Skip to content

Commit

Permalink
- 设置项可自定义每个标题级别的序号
Browse files Browse the repository at this point in the history
- 暂停更新,除非有bug
  • Loading branch information
dale0525 committed Dec 26, 2023
1 parent e78b319 commit 4f29001
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 27 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[中文](https://github.com/dale0525/siyuan-auto-seq-number/blob/main/README_zh_CN.md)

# SiYuan Auto Sequence Number Plugin
A SiYuan Plugin to auto generate sequence number for titles.
# SiYuan Auto Header Sequence Number Plugin
A SiYuan Plugin to auto generate sequence number for headers.

## Usage
Just turn on the plugin, and refresh the page.
Expand All @@ -10,6 +10,10 @@ Just turn on the plugin, and refresh the page.
- The sequence number is only rendered in SiYuan Note but will not change the original article, so the numbers will not be exported to other formats.

## Change Log
### 0.3.0
- add settings to customize the sequence number for each level of header
- future updates will be paused unless there are bugs

### 0.2.0
- change event bus to `loaded-protyle-static`( [#1](https://github.com/dale0525/siyuan-auto-seq-number/issues/1) )
- display seq number using `::befor` and cache result using SessionStorage, so that the seq number won't be reset when focusing on a block( [#2](https://github.com/dale0525/siyuan-auto-seq-number/issues/2), [#3](https://github.com/dale0525/siyuan-auto-seq-number/issues/3) )
7 changes: 6 additions & 1 deletion README_zh_CN.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[English](https://github.com/dale0525/siyuan-auto-seq-number//blob/main/README.md)

# 思源笔记序号插件
# 思源笔记标题序号插件
自动为标题生成序号的思源笔记插件。

## 使用方法
Expand All @@ -10,5 +10,10 @@
- 序号只在思源笔记中渲染,不会改变原文档,所以不会被导出到其他格式。

## 更新日志
### 0.3.0
- 设置项可自定义每个标题级别的序号
- 暂停更新,除非有bug

### 0.2.0
- 触发事件改为`loaded-protyle-static`( [#1](https://github.com/dale0525/siyuan-auto-seq-number/issues/1) )
- 改用::before伪元素实现序号,并使用SessionStorage缓存序号,避免聚焦时序号重置( [#2](https://github.com/dale0525/siyuan-auto-seq-number/issues/2), [#3](https://github.com/dale0525/siyuan-auto-seq-number/issues/3) )
Binary file modified icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "siyuan-auto-seq-number",
"version": "0.2.1",
"description": "A SiYuan Plugin to auto generate sequence number for titles",
"version": "0.3.0",
"description": "A SiYuan Plugin to auto generate sequence number for headers",
"main": ".src/index.js",
"scripts": {
"lint": "eslint . --fix --cache",
Expand Down
10 changes: 5 additions & 5 deletions plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "siyuan-auto-seq-number",
"author": "Logic Tan",
"url": "https://github.com/dale0525/siyuan-auto-seq-number",
"version": "0.2.1",
"version": "0.3.0",
"minAppVersion": "2.11.1",
"backends": [
"all"
Expand All @@ -11,11 +11,11 @@
"all"
],
"displayName": {
"default": "SiYuan Auto Sequence Number Plugin",
"zh_CN": "思源笔记序号插件"
"default": "Auto Header Sequence Number",
"zh_CN": "自动标题序号"
},
"description": {
"default": "A SiYuan Plugin to auto generate sequence number for titles",
"default": "A SiYuan Plugin to auto generate sequence number for headers",
"zh_CN": "自动为标题生成序号的思源笔记插件"
},
"readme": {
Expand All @@ -25,6 +25,6 @@
"keywords": [
"序号",
"标题",
"title"
"header"
]
}
12 changes: 12 additions & 0 deletions src/i18n/en_US.json
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
{
"seqNumSettingLevel1": "Level 1 Heading",
"seqNumSettingLevel2": "Level 2 Heading",
"seqNumSettingLevel3": "Level 3 Heading",
"seqNumSettingLevel4": "Level 4 Heading",
"seqNumSettingLevel5": "Level 5 Heading",
"seqNumSettingLevel6": "Level 6 Heading",
"seqNumLevel1Note": "If there is no h1, h2 will be used",
"seqNumSettingFormat": "Format",
"seqNumSettingNum2Chi": "Number to Chinese",
"resetConfig": "Reset Config",
"resetConfigDesc": "Reset all settings to default. The page will be reloaded.",
"resetBtn": "Reset"
}
12 changes: 12 additions & 0 deletions src/i18n/zh_CN.json
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
{
"seqNumSettingLevel1": "第一级标题",
"seqNumSettingLevel2": "第二级标题",
"seqNumSettingLevel3": "第三级标题",
"seqNumSettingLevel4": "第四级标题",
"seqNumSettingLevel5": "第五级标题",
"seqNumSettingLevel6": "第六级标题",
"seqNumLevel1Note": "如无h1,则h2为第一级标题;以此类推",
"seqNumSettingFormat": "格式",
"seqNumSettingNum2Chi": "数字转中文",
"resetConfig": "重置配置",
"resetConfigDesc": "重置后将恢复默认配置并重新加载页面",
"resetBtn": "重置"
}
2 changes: 1 addition & 1 deletion src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
{
display: block;
float: left;
content: attr(seq-num) "\00a0";
content: attr(seq-number);
}
166 changes: 150 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,91 @@
import {
Plugin,
Setting,
confirm,
} from "siyuan";
import "./index.scss";

const STORAGE_NAME = "seq-number";
const DEFAULT_CONFIG = {
seqNum: ["{1}. ", "{1}.{2} ", "{1}.{2}.{3} ", "{1}.{2}.{3}.{4} ", "{1}.{2}.{3}.{4}.{5} ", "{1}.{2}.{3}.{4}.{5}.{6} "],
num2Chi: [false, false, false, false, false, false],
};
const NUM_2_CHI = {
"1": "一",
"2": "二",
"3": "三",
"4": "四",
"5": "五",
"6": "六",
};

export default class AutoSeqNumPlugin extends Plugin {

private seq_num: Object = {};

onLoadedProtyleStaticBindThis = this.onLoadedProtyleStatic.bind(this);
onSwitchProtyleBindThis = this.onSwitchProtyle.bind(this);

onload() {
async onload() {
this.eventBus.on("loaded-protyle-static", this.onLoadedProtyleStaticBindThis);
this.eventBus.on("switch-protyle", this.onSwitchProtyleBindThis);

await this.loadData(STORAGE_NAME);
if (typeof this.data[STORAGE_NAME] !== "object" || this.data[STORAGE_NAME].hasOwnProperty("seqNum") === false || this.data[STORAGE_NAME].hasOwnProperty("num2Chi") === false) {
await this.saveData(STORAGE_NAME, DEFAULT_CONFIG);
}

// 增加设置项
const inputElements = [
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
];
const checkboxes = [
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
document.createElement("input"),
];
this.setting = new Setting({
confirmCallback: async () => {
await this.saveData(STORAGE_NAME, {
seqNum: [inputElements[0].value, inputElements[1].value, inputElements[2].value, inputElements[3].value, inputElements[4].value, inputElements[5].value],
num2Chi: [checkboxes[0].checked, checkboxes[1].checked, checkboxes[2].checked, checkboxes[3].checked, checkboxes[4].checked, checkboxes[5].checked],
});
globalThis.location.reload();
}
});
for (let i = 0; i < 6; i++) {
inputElements[i].placeholder = this.data[STORAGE_NAME].seqNum[i];
inputElements[i].value = this.data[STORAGE_NAME].seqNum[i];
checkboxes[i].checked = this.data[STORAGE_NAME].num2Chi[i];
this.setting.addItem(this.addSettingsItem(
this.i18n[`seqNumSettingLevel${i + 1}`],
i == 0 ? this.i18n.seqNumLevel1Note : null,
inputElements[i],
checkboxes[i],
));
}
// 重置设置按钮
this.setting.addItem({
title: this.i18n.resetConfig,
description: this.i18n.resetConfigDesc,
createActionElement: () => {
const btn = document.createElement("button");
btn.className = "b3-button b3-button--outline fn__flex-center fn__size200";
btn.textContent = this.i18n.resetConfig;
btn.addEventListener("click", () => {
this.resetOptions();
});
return btn;
},
});
}

onunload() {
Expand All @@ -21,22 +94,79 @@ export default class AutoSeqNumPlugin extends Plugin {
}

async onSwitchProtyle({detail}: any){
sessionStorage.removeItem('seq-num');
sessionStorage.removeItem(STORAGE_NAME);
}

async onLoadedProtyleStatic({detail}: any){
let pageHtml = detail.protyle.element;
this.addSeqNum(pageHtml);
}

async resetOptions(){
confirm(
this.i18n.resetConfig,
this.i18n.resetConfigDesc,
async () => {
await this.saveData(STORAGE_NAME, DEFAULT_CONFIG);
globalThis.location.reload();
}
);
}

// 每一级标题的单独设置项,包括序号格式和是否转中文
addSettingsItem(title: string, description: string, inputElement: any, checkbox: any) {
return {
title: title,
description: description,
createActionElement: () => {
const div = document.createElement("div");
div.className = "b3-label";

inputElement.className = "b3-text-field";
div.appendChild(this.createConfigElement(this.i18n.seqNumSettingFormat, inputElement));

div.appendChild(this.addConfigElementSeparator());

checkbox.className = "b3-switch";
checkbox.type = "checkbox";
div.appendChild(this.createConfigElement(this.i18n.seqNumSettingNum2Chi, checkbox));

return div;
},
};
}

// 每一个单独设置项目,包括标题、描述、留空、设置项
createConfigElement(text: string, element: any) {
const label = document.createElement("label");
label.className = "fn__flex config__item";
const div = document.createElement("div");
div.className = "fn__flex-center fn__flex-1 ft__on-surface";
const space = document.createElement("span");
space.className = "fn__space";
div.innerText = text;
label.appendChild(div);
label.appendChild(space);
label.appendChild(element);
return label;
}

// 设置标题和设置项中间的留空
addConfigElementSeparator() {
const span = document.createElement("span");
span.className = "fn__space";
return span;
}

addSeqNum(html: any) {
// 初始化计数器
let counters = [0, 0, 0, 0, 0, 0];
let trueCounters = [];

// 获取所有标题元素
let headers = html.querySelectorAll('.protyle-wysiwyg [data-node-id].h1, .protyle-wysiwyg [data-node-id].h2, .protyle-wysiwyg [data-node-id].h3, .protyle-wysiwyg [data-node-id].h4, .protyle-wysiwyg [data-node-id].h5, .protyle-wysiwyg [data-node-id].h6');

let seq_num_storage = sessionStorage.getItem('seq-num');
let seq_num_storage = sessionStorage.getItem(STORAGE_NAME);
if(seq_num_storage !== null) {
this.seq_num = JSON.parse(seq_num_storage);
}
Expand All @@ -48,7 +178,7 @@ export default class AutoSeqNumPlugin extends Plugin {
continue;
}
if (this.seq_num[element_id] !== undefined) {
headers[i].setAttribute('seq-num', this.seq_num[element_id]);
headers[i].setAttribute(STORAGE_NAME, this.seq_num[element_id]);
continue;
}

Expand All @@ -63,25 +193,29 @@ export default class AutoSeqNumPlugin extends Plugin {
// 增加当前级别的计数器
counters[level]++;

// 创建编号字符串
let number = '';
for (let k = 0; k <= level; k++) {
if (counters[k] > 0)
// 获取有效标题级别数量
let trueLevel = 0;
for (let j = 0; j <= level; j++) {
if (counters[j] > 0)
{
number += counters[k] + '.';
trueCounters.push(counters[j]);
trueLevel++;
}
}

// 获取number中句号的个数,如果大于1,则删除最后一个句号
let dotCount = number.split('.').length - 1;
if (dotCount > 1) {
number = number.substring(0, number.length - 1);
// 生成编号
let settingsNum = this.data[STORAGE_NAME].seqNum[trueLevel - 1];
let num2Chi = this.data[STORAGE_NAME].num2Chi[trueLevel - 1];
for (let j = 0; j < trueLevel; j++) {
settingsNum = settingsNum.replace(`{${j + 1}}`, num2Chi ? NUM_2_CHI[trueCounters[j].toString()] : trueCounters[j]).replace(" ", "\u00a0");
}

// 设置dom元素的编号属性,通过css伪类来显示编号
headers[i].setAttribute('seq-num', number);
this.seq_num[element_id] = number;
headers[i].setAttribute(STORAGE_NAME, settingsNum);
this.seq_num[element_id] = settingsNum;

trueCounters = [];
}
sessionStorage.setItem('seq-num', JSON.stringify(this.seq_num));
sessionStorage.setItem(STORAGE_NAME, JSON.stringify(this.seq_num));
}
}

0 comments on commit 4f29001

Please sign in to comment.