markdown-it-toc-better
Version:
Generate plug-ins for directories written by markdownit
144 lines (135 loc) • 5.25 kB
JavaScript
/**
* markdown-it-toc-better
*
* @param {Object} md - markdownit Object(库传入对象) required
* @param {Object} options - config object(配置对象) required
* @param {Array} options.includeLevel - Set directory level(设定目录级别)
* @param {Function} options.slugify - Function used to custom directory anchor href rule(自定义目录锚点href规则函数)
* @param {Function} options.getTocTree - Function used to acquire directory tree object,the function argument is a directory tree object(用于获取目录树对象的函数,函数入参为目录树对象)
* @param {Function} options.getTocHTML - Function used to acquire directory DOM,the function argument is a DOM(用于获取目录DOM的函数,函数入参为DOM对象)
*/
export default function(md,options) {
// Add anchor when generating the title
// 生成标题时加入锚点
md.renderer.rules.heading_open = function(tokens, index) {
let slugify = typeof options.slugify === "function" ? options.slugify : function (s) { return s; };
let level = tokens[index].tag;
let label = tokens[index + 1];
let link = slugify(label.content)
if (label.type === 'inline') {
return `<${level}><a id="#${link}"></a>`;
} else {
return '</h1>';
}
};
// Get the title node
// 获取标题节点
function findHeadings(tokens, option) {
let _a, _b, _c;
let headings = [];
let size = tokens.length;
let slugify = typeof option.slugify === "function" ? option.slugify : function (s) { return s; };
let includeLevel = option.includeLevel || [1, 2, 3, 4];
let index = 0;
while (index < size) {
let token = tokens[index];
let level = (_c = +((_b = (_a = token === null || token === void 0 ? void 0 : token.tag) === null || _a === void 0 ? void 0 : _a.substr) === null || _b === void 0 ? void 0 : _b.call(_a, 1, 1))) !== null && _c !== void 0 ? _c : -1;
if (token.type === "heading_open" && includeLevel.indexOf(level) !== -1) {
let content = tokens[index + 1].content;
let h = {
level: level,
content: content,
parent: null,
children: [],
link: "#" + slugify(content),
};
headings.push(h);
index += 3;
}
else {
index++;
}
}
return headings;
}
// Generate node tree
// 生成节点树
function flat2Tree(headings) {
let current = null;
let root = [];
for (let i = 0; i < headings.length; i++) {
let h = headings[i];
if (h.level === 1) {
root.push(h);
current = null;
}
if (current === null) {
current = h;
}
else {
while (h.level !== current.level + 1) {
if (h.level > current.level && current.children.length !== 0) {
current = current.children[current.children.length - 1];
}
else if (h.level <= current.level && current.parent !== null) {
current = current.parent;
}
else {
break;
}
}
if (h.level === current.level + 1) {
h.parent = current;
current.children.push(h);
current = h;
}
}
}
return root;
}
// Remove redundant branches
// 去除冗余分支
function removeUselessProperties(hsd) {
for (let i = 0; i < hsd.length; i++) {
delete hsd[i].parent;
removeUselessProperties(hsd[i].children);
}
}
// Generate directory elements
// 生成目录元素
function renderToc(tree) {
let TocContainer = document.createElement('ul')
let levelInner = 0
let tocHTML = tree.reduce((pre,cur) => {
let headerContainer = document.createElement('li')
let link = document.createElement('a')
link.href = cur.link
link.className = `leave_${cur.level} idx_${levelInner}`
levelInner ++
link.innerText = cur.content
headerContainer.append(link)
if(cur.children.length > 0){
let childrenDOM = cur.children
headerContainer.append(renderToc(childrenDOM))
pre.append(headerContainer)
}else{
pre.append(headerContainer)
}
return TocContainer
},TocContainer)
return tocHTML
}
// Generate and return the title node tree
// 生成并返回标题节点树
md.core.ruler.push("toc_desc", function (state) {
const o = options
let _a,_c;
let _b = (o === null || o === void 0) ? void 0 : (typeof o.render === 'function' ? void 0 : o.render);
let headings = findHeadings(state.tokens, o);
let tree = flat2Tree(headings);
removeUselessProperties(tree);
(_a = o === null || o === void 0 ? void 0 : (typeof o.getTocTree === 'function' ? o.getTocTree : void 0)) === null || _a === void 0 ? void 0 : _a.call(o, tree);
(_c = (o === null || o === void 0) ? void 0 : (typeof o.getTocHTML === 'function' ? o.getTocHTML : void 0)) === null || _c === void 0 ? void 0 : _b === void 0 ? _c.call(o, renderToc(tree)) :_c.call(o, _b.call(o,tree));
return true;
});
}