2025-04-20 23:22:14 +08:00

371 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var cheerio = require('cheerio');
var slug = require('github-slugid');
var Config = require('./config.js');
/**
* 处理toc相关同时处理标题和id
* @param $
* @param option
* @param page
* @returns {Array} 返回处理好的tocs合集
*/
function handlerTocs($, page, modifyHeader) {
var config = Config.config;
var tocs = [];
var count = {
h1: 0,
h2: 0,
h3: 0
};
var titleCountMap = {}; // 用来记录标题出现的次数
var h1 = 0, h2 = 0, h3 = 0;
$(':header').each(function (i, elem) {
var header = $(elem);
var id = addId(header, titleCountMap);
if (id) {
switch (elem.tagName) {
case "h1":
handlerH1Toc(config, count, header, tocs, page.level, modifyHeader);
break;
case "h2":
handlerH2Toc(config, count, header, tocs, page.level, modifyHeader);
break;
case "h3":
handlerH3Toc(config, count, header, tocs, page.level, modifyHeader);
break;
default:
titleAddAnchor(header, id);
break;
}
}
});
// 不然标题重写就没有效果,如果在外面不调用这句话的话
page.content = $.html();
return tocs;
}
/**
* 处理锚点
* @param header
* @param titleCountMap 用来记录标题出现的次数
* @returns {string}
*/
function addId(header, titleCountMap) {
var id = header.attr('id') || slug(header.text());
var titleCount = titleCountMap[id] || 0;
titleCountMap[id] = titleCount + 1;
// console.log('id:', id, 'n:', titleCount, 'hashmap:', titleCountMap)
if (titleCount) {//此标题已经存在 null/undefined/0/NaN/ 表达式时统统被解释为false
id = id + '_' + titleCount;
}
header.attr("id", id);
return id;
}
/**
* 标题增加锚点效果
* @param header
* @param id
*/
function titleAddAnchor(header, id) {
header.prepend('<a name="' + id + '" class="anchor-navigation-ex-anchor" '
+ 'href="#' + id + '">'
+ '<i class="fa fa-link" aria-hidden="true"></i>'
+ '</a>');
}
/**
* 处理h1
* @param count 计数器
* @param header
* @param tocs 根节点
*/
function handlerH1Toc(config, count, header, tocs, pageLevel, modifyHeader) {
var title = header.text();
var id = header.attr('id');
var level = ''; //层级
if (config.showLevel) {
//层级显示仅在需要的时候处理
count.h1 += 1;
count.h2 = 0;
count.h3 = 0;
if (config.multipleH1) {
level = count.h1 + '. ';
} else {
level = ' ';
}
// 是否与官网默认主题层级序号相关联
if (config.associatedWithSummary && config.themeDefault.showLevel) {
level = pageLevel + '.' + level;
}
if (!modifyHeader) {
level = '';
}
header.text(level + title); //重写标题
}
titleAddAnchor(header, id);
tocs.push({
name: title,
level: level,
url: id,
children: []
});
}
/**
* 处理h2
* @param count 计数器
* @param header
*/
function handlerH2Toc(config, count, header, tocs, pageLevel, modifyHeader) {
var title = header.text();
var id = header.attr('id');
var level = ''; //层级
if (tocs.length <= 0) {
//一级节点为空时,生成一个空的一级节点,让二级节点附带在这个上面
// 在显示层级的时候不乱
if (config.showLevel) {
count.h1 += 1;
}
tocs.push({
name: "",
level: "",
url: "",
children: []
});
}
var h1Index = tocs.length - 1;
var h1Toc = tocs[h1Index];
if (config.showLevel) {
count.h2 += 1;
count.h3 = 0;
if (config.multipleH1) {
level = (count.h1 + '.' + count.h2 + '. ');
} else {
level = (count.h2 + '. ');
}
if (config.associatedWithSummary && config.themeDefault.showLevel) {
level = pageLevel + '.' + level;
}
if (!modifyHeader) {
level = '';
}
header.text(level + title); //重写标题
}
titleAddAnchor(header, id);
h1Toc.children.push({
name: title,
level: level,
url: id,
children: []
});
}
/**
* 处理h3
* @param count 计数器
* @param header
*/
function handlerH3Toc(config, count, header, tocs, pageLevel, modifyHeader) {
var title = header.text();
var id = header.attr('id');
var level = ''; //层级
if (tocs.length <= 0) {
//一级节点为空时,生成一个空的一级节点,让二级节点附带在这个上面
if (config.showLevel) {
count.h1 += 1;
}
tocs.push({
name: "",
level: "",
url: "",
children: []
});
}
var h1Index = tocs.length - 1;
var h1Toc = tocs[h1Index];
var h2Tocs = h1Toc.children;
if (h2Tocs.length <= 0) {
//二级节点为空时,生成一个空的二级节点,让三级节点附带在这个上面
if (config.showLevel) {
count.h2 += 1;
}
h2Tocs.push({
name: "",
level: "",
url: "",
children: []
});
}
var h2Toc = h1Toc.children[h2Tocs.length - 1];
if (config.showLevel) {
count.h3 += 1;
if (config.multipleH1) {
level = (count.h1 + '.' + count.h2 + '.' + count.h3 + '. ');
} else {
level = (count.h2 + '.' + count.h3 + '. ');
}
if (config.associatedWithSummary && config.themeDefault.showLevel) {
level = pageLevel + "." + level;
}
if (!modifyHeader) {
level = '';
}
header.text(level + title); //重写标题
}
titleAddAnchor(header, id);
h2Toc.children.push({
name: title,
level: level,
url: id,
children: []
});
}
/**
* 处理浮动导航拼接锚点导航html并添加到html末尾利用css 悬浮
* @param tocs
* @returns {string}
*/
function handlerFloatNavbar($, tocs) {
var config = Config.config;
var float = config.float;
var floatIcon = float.floatIcon;
var level1Icon = '';
var level2Icon = '';
var level3Icon = '';
if (float.showLevelIcon) {
level1Icon = float.level1Icon;
level2Icon = float.level2Icon;
level3Icon = float.level3Icon;
}
var html = "<div id='anchor-navigation-ex-navbar'><i class='" + floatIcon + "'></i><ul>";
for (var i = 0; i < tocs.length; i++) {
var h1Toc = tocs[i];
if (h1Toc.name){
html += "<li><span class='title-icon " + level1Icon + "'></span><a href='#" + h1Toc.url + "'><b>" + h1Toc.level + "</b>" + h1Toc.name + "</a></li>";
}
if (h1Toc.children.length > 0) {
html += "<ul>"
for (var j = 0; j < h1Toc.children.length; j++) {
var h2Toc = h1Toc.children[j];
if(h2Toc.name){
html += "<li><span class='title-icon " + level2Icon + "'></span><a href='#" + h2Toc.url + "'><b>" + h2Toc.level + "</b>" + h2Toc.name + "</a></li>";
}
if (h2Toc.children.length > 0) {
html += "<ul>";
for (var k = 0; k < h2Toc.children.length; k++) {
var h3Toc = h2Toc.children[k];
html += "<li><span class='title-icon " + level3Icon + "'></span><a href='#" + h3Toc.url + "'><b>" + h3Toc.level + "</b>" + h3Toc.name + "</a></li>";
}
html += "</ul>";
}
}
html += "</ul>"
}
}
html += "</ul></div>";
return html;
}
function handlerPageTopNavbar($, tocs) {
return buildTopNavbar($, tocs)
}
function buildTopNavbar($, tocs) {
var config = Config.config;
var pageTop = config.pageTop;
var level1Icon = '';
var level2Icon = '';
var level3Icon = '';
if (pageTop.showLevelIcon) {
level1Icon = pageTop.level1Icon;
level2Icon = pageTop.level2Icon;
level3Icon = pageTop.level3Icon;
}
var html = "<div id='anchor-navigation-ex-pagetop-navbar'><ul>";
for (var i = 0; i < tocs.length; i++) {
var h1Toc = tocs[i];
if(h1Toc.name){
html += "<li><span class='title-icon " + level1Icon + "'></span><a href='#" + h1Toc.url + "'><b>" + h1Toc.level + "</b>" + h1Toc.name + "</a></li>";
}
if (h1Toc.children.length > 0) {
html += "<ul>"
for (var j = 0; j < h1Toc.children.length; j++) {
var h2Toc = h1Toc.children[j];
if(h2Toc.name){
html += "<li><span class='title-icon " + level2Icon + "'></span><a href='#" + h2Toc.url + "'><b>" + h2Toc.level + "</b>" + h2Toc.name + "</a></li>";
}
if (h2Toc.children.length > 0) {
html += "<ul>";
for (var k = 0; k < h2Toc.children.length; k++) {
var h3Toc = h2Toc.children[k];
html += "<li><span class='title-icon " + level3Icon + "'></span><a href='#" + h3Toc.url + "'><b>" + h3Toc.level + "</b>" + h3Toc.name + "</a></li>";
}
html += "</ul>";
}
}
html += "</ul>"
}
}
html += "</ul></div>";
return html;
}
/**
* 添加返回顶部按钮
* @param tocs
* @returns {string}
*/
function buildGoTop(tocs) {
var config = Config.config;
var html = "";
if (config.showGoTop && tocs && tocs.length > 0) {
html = "<a href='#" + tocs[0].url + "' id='anchorNavigationExGoTop'><i class='fa fa-arrow-up'></i></a>";
}
return html;
}
function start(bookIns, page) {
var $ = cheerio.load(page.content);
var modifyHeader = !/<!--[ \t]*ex_nolevel[ \t]*-->/.test(page.content)
// 处理toc相关同时处理标题和id
var tocs = handlerTocs($, page, modifyHeader);
// 设置处理之后的内容
if (tocs.length == 0) {
page.content = $.html();
return;
}
var html = "";
if (!/<!--[ \t]*ex_nonav[ \t]*-->/.test(page.content)) {
var config = Config.config;
var mode = config.mode;
if (mode == 'float') {
html = handlerFloatNavbar($, tocs);
} else if (mode == 'pageTop') {
html = handlerPageTopNavbar($, tocs);
}
}
html += buildGoTop(tocs);
page.content = html + $.html();
var $x = cheerio.load(page.content);
$x('extoc').replaceWith($x(buildTopNavbar($, tocs, page)));
page.content = $x.html();
}
module.exports = start;