Doc: Auto-generate anchors

This commit is contained in:
Laurent Cozic
2019-05-02 23:54:31 +01:00
parent da69d6b2c9
commit 49c998de83
+106
View File
@@ -184,6 +184,24 @@ const headerHtml = `<!doctype html>
color: gray;
font-size: .9em;
}
a.heading-anchor {
display: inline-block;
opacity: 0;
width: 1.3em;
font-size: 0.7em;
margin-left: -1.3em;
line-height: 1em;
text-decoration: none;
}
a.heading-anchor:hover,
h1:hover a.heading-anchor,
h2:hover a.heading-anchor,
h3:hover a.heading-anchor,
h4:hover a.heading-anchor,
h5:hover a.heading-anchor,
h6:hover a.heading-anchor {
opacity: 1;
}
@media all and (min-width: 400px) {
.nav-right .share-btn {
display: inline-block;
@@ -312,6 +330,94 @@ function markdownToHtml(md) {
html: true,
});
markdownIt.core.ruler.push('checkbox', state => {
const tokens = state.tokens;
const Token = state.Token;
const doneNames = [];
const headingTextToAnchorName = (text, doneNames) => {
const allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let lastWasDash = true;
let output = '';
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (allowed.indexOf(c) < 0) {
if (lastWasDash) continue;
lastWasDash = true;
output += '-';
} else {
lastWasDash = false;
output += c;
}
}
output = output.toLowerCase();
let temp = output;
let index = 1;
while (doneNames.indexOf(temp) >= 0) {
temp = output + '-' + index;
index++;
}
output = temp;
return output;
}
const createAnchorTokens = anchorName => {
const output = [];
{
const token = new Token('heading_anchor_open', 'a', 1);
token.attrs = [
['name', anchorName],
['href', '#' + anchorName],
['class', 'heading-anchor'],
];
output.push(token);
}
{
const token = new Token('text', '', 0);
token.content = '🔗';
output.push(token);
}
{
const token = new Token('heading_anchor_close', 'a', -1);
output.push(token);
}
return output;
}
let insideHeading = false;
let processedFirstInline = false;
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token.type === 'heading_open') {
insideHeading = true;
processedFirstInline = false;
continue;
}
if (token.type === 'heading_close') {
insideHeading = false;
processedFirstInline = false;
continue;
}
if (insideHeading && token.type === 'inline') {
processedFirstInline = true;
const anchorName = headingTextToAnchorName(token.content, doneNames);
doneNames.push(anchorName);
const anchorTokens = createAnchorTokens(anchorName);
token.children = anchorTokens.concat(token.children);
}
}
});
return headerHtml + markdownIt.render(md) + scriptHtml + footerHtml;
}