2021-03-23 16:45:06 +08:00
|
|
|
export function setup(helper) {
|
2021-04-14 15:27:07 +08:00
|
|
|
if (helper.getOptions().previewing) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-23 16:45:06 +08:00
|
|
|
helper.registerPlugin((md) => {
|
|
|
|
md.core.ruler.push("anchor", (state) => {
|
2021-04-16 15:54:19 +08:00
|
|
|
for (
|
|
|
|
let idx = 0, lvl = 0, headingId = 0;
|
|
|
|
idx < state.tokens.length;
|
|
|
|
idx++
|
|
|
|
) {
|
2021-04-14 15:27:07 +08:00
|
|
|
if (
|
|
|
|
state.tokens[idx].type === "blockquote_open" ||
|
|
|
|
(state.tokens[idx].type === "bbcode_open" &&
|
|
|
|
state.tokens[idx].tag === "aside")
|
|
|
|
) {
|
|
|
|
++lvl;
|
|
|
|
} else if (
|
|
|
|
state.tokens[idx].type === "blockquote_close" ||
|
|
|
|
(state.tokens[idx].type === "bbcode_close" &&
|
|
|
|
state.tokens[idx].tag === "aside")
|
|
|
|
) {
|
|
|
|
--lvl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lvl > 0 || state.tokens[idx].type !== "heading_open") {
|
2021-03-23 16:45:06 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const linkOpen = new state.Token("link_open", "a", 1);
|
|
|
|
const linkClose = new state.Token("link_close", "a", -1);
|
|
|
|
|
2021-04-14 15:27:07 +08:00
|
|
|
let slug = state.tokens[idx + 1].content
|
2021-03-23 16:45:06 +08:00
|
|
|
.toLowerCase()
|
|
|
|
.replace(/\s+/g, "-")
|
|
|
|
.replace(/[^\w\-]+/g, "")
|
|
|
|
.replace(/\-\-+/g, "-")
|
|
|
|
.replace(/^-+/, "")
|
|
|
|
.replace(/-+$/, "");
|
|
|
|
|
2021-11-09 02:44:46 +08:00
|
|
|
if (slug.match(/^[^a-z]/)) {
|
|
|
|
slug = `h-${slug}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
slug = `${slug || "h"}-${++headingId}`;
|
2021-04-14 15:27:07 +08:00
|
|
|
|
2021-03-23 16:45:06 +08:00
|
|
|
linkOpen.attrSet("name", slug);
|
|
|
|
linkOpen.attrSet("class", "anchor");
|
|
|
|
linkOpen.attrSet("href", "#" + slug);
|
|
|
|
|
|
|
|
state.tokens[idx + 1].children.unshift(linkClose);
|
|
|
|
state.tokens[idx + 1].children.unshift(linkOpen);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|