60 lines
1.8 KiB
JavaScript
60 lines
1.8 KiB
JavaScript
export const getHeaders = ({ selector = [...new Array(6)].map((_, i) => `#vp-content h${i + 1}`).join(','), levels = 2, ignore = [], } = {}) => {
|
|
const headers = Array.from(document.querySelectorAll(selector))
|
|
.filter((el) => el.id && el.hasChildNodes())
|
|
.map((el) => {
|
|
const level = Number(el.tagName[1]);
|
|
return {
|
|
element: el,
|
|
title: serializeHeader(el, ignore),
|
|
link: '#' + el.id,
|
|
slug: el.id,
|
|
level,
|
|
};
|
|
});
|
|
return resolveHeaders(headers, levels);
|
|
};
|
|
const serializeHeader = (h, ignore = []) => {
|
|
let text = '';
|
|
if (ignore.length) {
|
|
const clone = h.cloneNode(true);
|
|
clone.querySelectorAll(ignore.join(',')).forEach((el) => el.remove());
|
|
text = clone.textContent || '';
|
|
}
|
|
else {
|
|
text = h.textContent || '';
|
|
}
|
|
return text.trim();
|
|
};
|
|
export const resolveHeaders = (headers, levels = 2) => {
|
|
if (levels === false) {
|
|
return [];
|
|
}
|
|
const [high, low] = typeof levels === 'number'
|
|
? [levels, levels]
|
|
: levels === 'deep'
|
|
? [2, 6]
|
|
: levels;
|
|
headers = headers.filter((h) => h.level >= high && h.level <= low);
|
|
const res = [];
|
|
// eslint-disable-next-line no-labels
|
|
outer: for (let i = 0; i < headers.length; i++) {
|
|
const cur = headers[i];
|
|
if (i === 0) {
|
|
res.push(cur);
|
|
}
|
|
else {
|
|
for (let j = i - 1; j >= 0; j--) {
|
|
const prev = headers[j];
|
|
if (prev.level < cur.level) {
|
|
;
|
|
(prev.children ??= []).push(cur);
|
|
// eslint-disable-next-line no-labels
|
|
continue outer;
|
|
}
|
|
}
|
|
res.push(cur);
|
|
}
|
|
}
|
|
return res;
|
|
};
|