mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-19 09:52:21 +08:00
@@ -0,0 +1,126 @@
|
||||
// A fork of https://github.com/valeriangalliat/markdown-it-anchor
|
||||
const slugify = (s) => encodeURIComponent(String(s).trim().toLowerCase().replace(/\s+/g, '-'));
|
||||
|
||||
const position = {
|
||||
false: 'push',
|
||||
true: 'unshift',
|
||||
};
|
||||
|
||||
const hasProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
const permalinkHref = (slug) => `#${slug}`;
|
||||
const permalinkAttrs = (slug) => ({});
|
||||
|
||||
const renderPermalink = (slug, opts, state, idx) => {
|
||||
const space = () => Object.assign(new state.Token('text', '', 0), { content: ' ' });
|
||||
|
||||
const linkTokens = [
|
||||
Object.assign(new state.Token('link_open', 'a', 1), {
|
||||
attrs: [['class', opts.permalinkClass], ['href', opts.permalinkHref(slug, state)], ...Object.entries(opts.permalinkAttrs(slug, state))],
|
||||
}),
|
||||
Object.assign(new state.Token('html_block', '', 0), {
|
||||
content: opts.permalinkSymbol,
|
||||
}),
|
||||
new state.Token('link_close', 'a', -1),
|
||||
];
|
||||
|
||||
// `push` or `unshift` according to position option.
|
||||
// Space is at the opposite side.
|
||||
if (opts.permalinkSpace) {
|
||||
linkTokens[position[!opts.permalinkBefore]](space());
|
||||
}
|
||||
state.tokens[idx + 1].children[position[opts.permalinkBefore]](...linkTokens);
|
||||
};
|
||||
|
||||
const uniqueSlug = (slug, slugs, failOnNonUnique) => {
|
||||
let uniq = slug;
|
||||
let i = 2;
|
||||
if (failOnNonUnique && hasProp.call(slugs, uniq)) {
|
||||
throw Error(`User defined id attribute '${slug}' is NOT unique. Please fix it in your markdown to continue.`);
|
||||
} else {
|
||||
while (hasProp.call(slugs, uniq)) uniq = `${slug}-${i++}`;
|
||||
}
|
||||
slugs[uniq] = true;
|
||||
return uniq;
|
||||
};
|
||||
|
||||
const isLevelSelectedNumber = (selection) => (level) => level >= selection;
|
||||
const isLevelSelectedArray = (selection) => (level) => selection.includes(level);
|
||||
|
||||
const getTitle = (children) => children.filter((token) => token.type === 'text' || token.type === 'code_inline').reduce((acc, t) => acc + t.content, '');
|
||||
|
||||
const anchor = (md, opts) => {
|
||||
opts = Object.assign({}, anchor.defaults, opts);
|
||||
|
||||
md.core.ruler.push('anchor', (state) => {
|
||||
const slugs = {};
|
||||
const tokens = state.tokens;
|
||||
|
||||
const isLevelSelected = Array.isArray(opts.level) ? isLevelSelectedArray(opts.level) : isLevelSelectedNumber(opts.level);
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
const currentLevel = tokens[i].markup.length;
|
||||
if (tokens[i].type === 'heading_open' && isLevelSelected(currentLevel)) {
|
||||
const titleIndex = i + 1;
|
||||
const currentTitle = getTitle(tokens[titleIndex].children);
|
||||
let prevTitle = tokens[i].attrGet('id');
|
||||
let constructedTitle = prevTitle;
|
||||
|
||||
// Skip if user has defined a id
|
||||
if (typeof prevTitle !== 'string') {
|
||||
if (prevTitle === null) {
|
||||
prevTitle = [];
|
||||
}
|
||||
|
||||
let recurIndex = i + 2;
|
||||
while (recurIndex < tokens.length && (tokens[recurIndex].type !== 'heading_open' || tokens[recurIndex].markup.length > currentLevel)) {
|
||||
if (tokens[recurIndex].type === 'heading_open') {
|
||||
let recurPrevTitle = tokens[recurIndex].attrGet('id');
|
||||
if (typeof recurPrevTitle !== 'string') {
|
||||
if (recurPrevTitle === null) {
|
||||
recurPrevTitle = [];
|
||||
}
|
||||
recurPrevTitle = [...recurPrevTitle, currentTitle];
|
||||
tokens[recurIndex].attrSet('id', recurPrevTitle);
|
||||
}
|
||||
}
|
||||
recurIndex += 1;
|
||||
}
|
||||
|
||||
prevTitle.push(currentTitle);
|
||||
//console.log(prevTitle);
|
||||
|
||||
// @TODO maybe use previous slugified title so we don't need to calculate that much?
|
||||
constructedTitle = prevTitle.join('-');
|
||||
//console.log(constructedTitle);
|
||||
}
|
||||
|
||||
const slug = uniqueSlug(opts.slugify(constructedTitle), slugs, true);
|
||||
tokens[i].attrSet('id', slug);
|
||||
|
||||
if (opts.permalink) {
|
||||
opts.renderPermalink(slug, opts, state, i);
|
||||
}
|
||||
|
||||
if (opts.callback) {
|
||||
opts.callback(tokens[i], { slug, constructedTitle });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
anchor.defaults = {
|
||||
level: 1,
|
||||
slugify,
|
||||
permalink: false,
|
||||
renderPermalink,
|
||||
permalinkClass: 'header-anchor',
|
||||
permalinkSpace: true,
|
||||
permalinkSymbol: '¶',
|
||||
permalinkBefore: false,
|
||||
permalinkHref,
|
||||
permalinkAttrs,
|
||||
};
|
||||
|
||||
module.exports = anchor;
|
||||
+21
-14
@@ -34,24 +34,31 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
markdown: {
|
||||
slugify: function (s) {
|
||||
return _slugify(
|
||||
pinyin(s, {
|
||||
style: pinyin.STYLE_NORMAL,
|
||||
heteronym: true,
|
||||
segment: true,
|
||||
})
|
||||
.map((item) => item[0])
|
||||
.join('-')
|
||||
);
|
||||
},
|
||||
anchor: {
|
||||
permalink: true,
|
||||
permalinkBefore: true,
|
||||
permalinkSymbol: '#',
|
||||
level: 999, // Disable original Plugin
|
||||
},
|
||||
extendMarkdown: (md) => {
|
||||
md.use(require('../.format/md/hierarchySlug'), {
|
||||
slugify: function (s) {
|
||||
return _slugify(
|
||||
pinyin(s, {
|
||||
style: pinyin.STYLE_NORMAL,
|
||||
heteronym: true,
|
||||
segment: true,
|
||||
})
|
||||
.map((item) => item[0])
|
||||
.join('-')
|
||||
);
|
||||
},
|
||||
level: 2,
|
||||
permalink: true,
|
||||
permalinkBefore: true,
|
||||
permalinkSymbol: '#',
|
||||
});
|
||||
},
|
||||
},
|
||||
head: [
|
||||
['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1.0' }],
|
||||
['link', { rel: 'icon', href: '/logo.png' }],
|
||||
['link', { rel: 'manifest', href: '/manifest.json' }],
|
||||
['meta', { name: 'theme-color', content: '#fff' }],
|
||||
|
||||
@@ -46,6 +46,7 @@ pageClass: routes
|
||||
<Route author="maple3142" example="/anime1/anime/2018年秋季/哥布林殺手" path="/anime1/anime/:time/:name" :paramsDesc="['时间', '动画名称']" radar="1">
|
||||
|
||||
时间和动画名称请自己从网址取得: `https://anime1.me/category/2018年秋季/刀劍神域-alicization`
|
||||
|
||||
</Route>
|
||||
|
||||
### 搜尋
|
||||
|
||||
@@ -178,7 +178,7 @@ Category 列表:
|
||||
|
||||
### 端传媒
|
||||
|
||||
<Route author="prnake" example="/initium/feature/zh-hans" path="/initium/:type?/:language?" :paramsDesc="['栏目,缺省为深度','语言,简体`zh-hans`,繁体`zh-hant`,缺省为简体']">
|
||||
<Route author="prnake" example="/initium/feature/zh-hans" path="/initium/:type?/:language?" :paramsDesc="['栏目,缺省为深度', '语言,简体`zh-hans`,繁体`zh-hant`,缺省为简体']"/>
|
||||
|
||||
::: warning 注意
|
||||
|
||||
|
||||
Reference in New Issue
Block a user