hexo-theme-essence
Version:
A Simple Clean Theme for Hexo with user-friendly Navigation System.
53 lines (43 loc) • 1.58 kB
JavaScript
;
const { DomHandler, DomUtils, Parser } = require('htmlparser2');
const { escapeHTML } = require('hexo-util');
const nonWord = /^\s*[^a-zA-Z0-9]\s*$/;
const parseHtml = html => {
const handler = new DomHandler(null, {});
new Parser(handler, {}).end(html);
return handler.dom;
};
const getId = ({ attribs, children }) => {
const el = DomUtils.find(({ tagName }) => tagName === 'a', children, false);
return (el && el[0] && el[0].attribs.id) || attribs.id || '';
};
function tocObj(str, options = {}) {
const { min_depth, max_depth } = Object.assign({
min_depth: 1,
max_depth: 6
}, options);
const headingsSelector = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].slice(min_depth - 1, max_depth);
const headings = DomUtils.find(({ tagName }) => headingsSelector.includes(tagName), parseHtml(str), true);
const headingsLen = headings.length;
if (!headingsLen) return [];
const result = [];
for (let i = 0; i < headingsLen; i++) {
const el = headings[i];
const level = +el.name[1];
const id = getId(el);
let text = '';
for (const element of el.children) {
const elText = DomUtils.getText(element);
// Skip permalink symbol wrapped in <a>
// permalink is a single non-word character, word = [a-Z0-9]
// permalink may be wrapped in whitespace(s)
if (element.name !== 'a' || !nonWord.test(elText)) {
text += escapeHTML(elText);
}
}
if (!text) text = escapeHTML(DomUtils.getText(el));
result.push({ text, id, level });
}
return result;
}
module.exports = tocObj;