82 lines
2.4 KiB
JavaScript
82 lines
2.4 KiB
JavaScript
/**
|
||
* 标题行首序号:1 / 1.1 / 1.2.3 / 1. / 1) 等(不含 2024 这类四位年份)
|
||
*/
|
||
const HEADING_NUMBER_PREFIX_RE =
|
||
/^\s*(?:(?:\d+\.)+\d+|\d{1,2}[\.\)::]|\d{1,2}(?=\s+[^\d]))[\.\)::]?\s+/;
|
||
|
||
export function stripHeadingNumberPrefix(text) {
|
||
return String(text || '').replace(HEADING_NUMBER_PREFIX_RE, '');
|
||
}
|
||
|
||
export function hasHeadingNumberPrefix(text) {
|
||
return HEADING_NUMBER_PREFIX_RE.test(String(text || ''));
|
||
}
|
||
|
||
function htmlToPlainText(html) {
|
||
if (typeof document !== 'undefined') {
|
||
const node = document.createElement('div');
|
||
node.innerHTML = String(html || '');
|
||
return (node.textContent || node.innerText || '').replace(/\u00a0/g, ' ');
|
||
}
|
||
return String(html || '')
|
||
.replace(/<[^>]+>/g, '')
|
||
.replace(/ /g, ' ')
|
||
.replace(/\s+/g, ' ')
|
||
.trim();
|
||
}
|
||
|
||
export function headingHtmlHasNumberPrefix(html) {
|
||
return hasHeadingNumberPrefix(htmlToPlainText(html));
|
||
}
|
||
|
||
/** 去掉 HTML 标题内容中首个非空文本节点前的序号 */
|
||
export function stripHeadingNumberFromHtml(html) {
|
||
if (typeof document === 'undefined') {
|
||
const plain = htmlToPlainText(html);
|
||
if (!hasHeadingNumberPrefix(plain)) {
|
||
return html;
|
||
}
|
||
return String(html || '').replace(HEADING_NUMBER_PREFIX_RE, '');
|
||
}
|
||
|
||
const div = document.createElement('div');
|
||
div.innerHTML = html || '';
|
||
const walker = document.createTreeWalker(div, NodeFilter.SHOW_TEXT, null);
|
||
let node;
|
||
while ((node = walker.nextNode())) {
|
||
const raw = node.textContent || '';
|
||
if (!raw.trim()) {
|
||
continue;
|
||
}
|
||
const stripped = stripHeadingNumberPrefix(raw);
|
||
if (stripped !== raw) {
|
||
node.textContent = stripped;
|
||
}
|
||
break;
|
||
}
|
||
return div.innerHTML;
|
||
}
|
||
|
||
/** 从正文列表中收集需去掉序号的 H1/H2 标题 */
|
||
export function collectHeadingNumberStripUpdates(contentList) {
|
||
const list = contentList || [];
|
||
const updates = [];
|
||
|
||
list.forEach(function (item) {
|
||
if (!item || (item.is_h1 != 1 && item.is_h2 != 1)) {
|
||
return;
|
||
}
|
||
const original = item.content || '';
|
||
const next = stripHeadingNumberFromHtml(original);
|
||
if (next !== original) {
|
||
updates.push({
|
||
am_id: item.am_id,
|
||
content: next,
|
||
original: original
|
||
});
|
||
}
|
||
});
|
||
|
||
return updates;
|
||
}
|