mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
toc support
This commit is contained in:
parent
1a63c7cf6d
commit
bb3f03fb17
@ -124,13 +124,14 @@
|
||||
"web/js/markdown-it/markdown-it-emoji.min.js",
|
||||
"web/js/markdown-it/markdown-it-footnote.min.js",
|
||||
"web/js/markdown-it/markdown-it-front-matter.js",
|
||||
"web/js/markdown-it/markdown-it-headinganchor.js",
|
||||
"web/js/markdown-it/markdown-it-imsize.min.js",
|
||||
"web/js/markdown-it/markdown-it-sub.min.js",
|
||||
"web/js/markdown-it/markdown-it-sup.min.js",
|
||||
"web/js/markdown-it/markdown-it-task-lists.js",
|
||||
"web/js/markdown-it/markdown-it-texmath.js",
|
||||
"web/js/markdown-it/markdown-it-inject-linenumbers.js",
|
||||
"web/js/markdown-it/markdownItAnchor.umd.js",
|
||||
"web/js/markdown-it/markdownItTocDoneRight.umd.js",
|
||||
"web/js/markdownit.js"
|
||||
],
|
||||
"styles" : [
|
||||
|
@ -30,7 +30,8 @@
|
||||
<file>web/js/markdown-it/markdown-it-emoji.min.js</file>
|
||||
<file>web/js/markdown-it/markdown-it-footnote.min.js</file>
|
||||
<file>web/js/markdown-it/markdown-it-front-matter.js</file>
|
||||
<file>web/js/markdown-it/markdown-it-headinganchor.js</file>
|
||||
<file>web/js/markdown-it/markdownItAnchor.umd.js</file>
|
||||
<file>web/js/markdown-it/markdownItTocDoneRight.umd.js</file>
|
||||
<file>web/js/markdown-it/markdown-it-imsize.min.js</file>
|
||||
<file>web/js/markdown-it/markdown-it-sub.min.js</file>
|
||||
<file>web/js/markdown-it/markdown-it-sup.min.js</file>
|
||||
|
@ -49,3 +49,35 @@
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Table of Contents */
|
||||
.vx-table-of-contents ol {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#vx-content.vx-section-number .vx-table-of-contents > ol > li ol {
|
||||
counter-reset: toc;
|
||||
}
|
||||
|
||||
#vx-content.vx-section-number .vx-table-of-contents > ol > li ol li {
|
||||
counter-increment: toc;
|
||||
}
|
||||
|
||||
#vx-content.vx-section-number .vx-table-of-contents > ol > li ol li:before {
|
||||
content: counters(toc, '.') '. ';
|
||||
font-family: cursive;
|
||||
}
|
||||
|
||||
.vx-header-anchor {
|
||||
visibility: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.vx-header-anchor::after {
|
||||
content: attr(vx-data-anchor-icon);
|
||||
}
|
||||
|
||||
#vx-content h1:hover .vx-header-anchor, #vx-content h2:hover .vx-header-anchor, #vx-content h3:hover .vx-header-anchor, #vx-content h4:hover .vx-header-anchor, #vx-content h5:hover .vx-header-anchor, #vx-content h6:hover .vx-header-anchor {
|
||||
visibility: visible;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
@ -3,11 +3,6 @@ v11.0.0
|
||||
Alex Kocharin
|
||||
Vitaly Puzrin
|
||||
|
||||
# [markdown-it-headinganchor](https://github.com/adam-p/markdown-it-headinganchor)
|
||||
v1.3.0
|
||||
Adam Pritchard
|
||||
Modified by Le Tan
|
||||
|
||||
# [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists)
|
||||
v2.1.0
|
||||
Revin Guillen
|
||||
@ -52,3 +47,9 @@ Modified by Le Tan
|
||||
|
||||
# [markdown-it-xss](https://github.com/yzyeengang/markdown-it-xss)
|
||||
v1.0.0
|
||||
|
||||
# [markdonw-it-anchor](https://github.com/valeriangalliat/markdown-it-anchor)
|
||||
v6.0.1
|
||||
|
||||
# [markdonw-it-toc-done-right](https://github.com/nagaozen/markdown-it-toc-done-right)
|
||||
v4.2.0
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*! markdown-it-headinganchor 1.2.1 https://github.com//adam-p/markdown-it-headinganchor @license MIT */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownitHeadingAnchor = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
/*
|
||||
* Copyright Adam Pritchard 2015
|
||||
* MIT License : http://adampritchard.mit-license.org/
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/*jshint node:true*/
|
||||
|
||||
function slugify(md, s) {
|
||||
// Unicode-friendly
|
||||
var spaceRegex = new RegExp(md.utils.lib.ucmicro.Z.source, 'g');
|
||||
return encodeURIComponent(s.replace(spaceRegex, ''));
|
||||
}
|
||||
|
||||
function makeRule(md, options) {
|
||||
return function addHeadingAnchors(state) {
|
||||
// Go to length-2 because we're going to be peeking ahead.
|
||||
for (var i = 0; i < state.tokens.length - 1; ++i) {
|
||||
if (state.tokens[i].type !== 'heading_open' ||
|
||||
state.tokens[i+1].type !== 'inline') {
|
||||
continue;
|
||||
}
|
||||
|
||||
var headingOpenToken = state.tokens[i];
|
||||
var headingInlineToken = state.tokens[i+1];
|
||||
|
||||
if (!headingInlineToken.content) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var anchorName = options.slugify(md, headingInlineToken.content);
|
||||
|
||||
options.headingHook(headingOpenToken, headingInlineToken, anchorName);
|
||||
|
||||
if (options.addHeadingID) {
|
||||
headingOpenToken.attrPush(['id', anchorName]);
|
||||
}
|
||||
|
||||
if (options.addHeadingAnchor) {
|
||||
var anchorToken = new state.Token('html_inline', '', 0);
|
||||
if (options.addHeadingID) {
|
||||
// No need to add id in anchor.
|
||||
anchorToken.content = '<a class="' + options.anchorClass + '" ' +
|
||||
'href="#' + anchorName + '" ' +
|
||||
'data-anchor-icon="' + options.anchorIcon + '" ' +
|
||||
'></a>';
|
||||
} else {
|
||||
anchorToken.content = '<a id="' + anchorName + '" ' +
|
||||
'class="' + options.anchorClass + '" ' +
|
||||
'href="#' + anchorName + '" ' +
|
||||
'data-anchor-icon="' + options.anchorIcon + '" ' +
|
||||
'></a>';
|
||||
}
|
||||
|
||||
headingInlineToken.children.push(anchorToken);
|
||||
}
|
||||
|
||||
// Advance past the inline and heading_close tokens.
|
||||
i += 2;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function headinganchor_plugin(md, opts) {
|
||||
var defaults = {
|
||||
anchorClass: 'markdown-it-headinganchor',
|
||||
addHeadingID: true,
|
||||
addHeadingAnchor: true,
|
||||
// Added by Le Tan (github.com/tamlok)
|
||||
anchorIcon: '#',
|
||||
slugify: slugify,
|
||||
headingHook: function(openToken, inlineToken, anchor) {}
|
||||
};
|
||||
var options = md.utils.assign(defaults, opts);
|
||||
md.core.ruler.push('heading_anchors', makeRule(md, options));
|
||||
};
|
||||
|
||||
},{}]},{},[1])(1)
|
||||
});
|
@ -0,0 +1,2 @@
|
||||
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(n=n||self).markdownItAnchor=e()}(this,function(){var n={false:"push",true:"unshift"},e=Object.prototype.hasOwnProperty,t=function(n,t,r,i){var u=n,o=i;if(r&&e.call(t,u))throw Error("User defined id attribute '"+n+"' is NOT unique. Please fix it in your markdown to continue.");for(;e.call(t,u);)u=n+"-"+o++;return t[u]=!0,u},r=function n(e,r){r=Object.assign({},n.defaults,r),e.core.ruler.push("anchor",function(n){var e,i={},u=n.tokens,o=Array.isArray(r.level)?(e=r.level,function(n){return e.includes(n)}):function(n){return function(e){return e>=n}}(r.level);u.filter(function(n){return"heading_open"===n.type}).filter(function(n){return o(Number(n.tag.substr(1)))}).forEach(function(e){var o=u[u.indexOf(e)+1].children.filter(function(n){return"text"===n.type||"code_inline"===n.type}).reduce(function(n,e){return n+e.content},""),c=e.attrGet("id");c=null==c?t(r.slugify(o),i,!1,r.uniqueSlugStartIndex):t(c,i,!0,r.uniqueSlugStartIndex),e.attrSet("id",c),r.permalink&&r.renderPermalink(c,r,n,u.indexOf(e)),r.callback&&r.callback(e,{slug:c,title:o})})})};return r.defaults={level:1,slugify:function(n){return encodeURIComponent(String(n).trim().toLowerCase().replace(/\s+/g,"-"))},uniqueSlugStartIndex:1,permalink:!1,renderPermalink:function(e,t,r,i){var u,o=[Object.assign(new r.Token("link_open","a",1),{attrs:[].concat(t.permalinkClass?[["class",t.permalinkClass]]:[],[["href",t.permalinkHref(e,r)]],Object.entries(t.permalinkAttrs(e,r)))}),Object.assign(new r.Token("html_block","",0),{content:t.permalinkSymbol}),new r.Token("link_close","a",-1)];t.permalinkSpace&&o[n[!t.permalinkBefore]](Object.assign(new r.Token("text","",0),{content:" "})),(u=r.tokens[i+1].children)[n[t.permalinkBefore]].apply(u,o)},permalinkClass:"header-anchor",permalinkSpace:!0,permalinkSymbol:"¶",permalinkBefore:!1,permalinkHref:function(n){return"#"+n},permalinkAttrs:function(n){return{}}},r});
|
||||
//# sourceMappingURL=markdownItAnchor.umd.js.map
|
@ -0,0 +1,2 @@
|
||||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).markdownItTocDoneRight=n()}(this,function(){function e(e){return encodeURIComponent(String(e).trim().toLowerCase().replace(/\s+/g,"-"))}function n(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}return function(t,r){var l;r=Object.assign({},{placeholder:"(\\$\\{toc\\}|\\[\\[?_?toc_?\\]?\\]|\\$\\<toc(\\{[^}]*\\})\\>)",slugify:e,uniqueSlugStartIndex:1,containerClass:"table-of-contents",containerId:void 0,listClass:void 0,itemClass:void 0,linkClass:void 0,level:1,listType:"ol",format:void 0,callback:void 0},r);var i=new RegExp("^"+r.placeholder+"$","i");t.renderer.rules.tocOpen=function(e,t){var l=Object.assign({},r);return e&&t>=0&&(l=Object.assign(l,e[t].inlineOptions)),"<nav"+(l.containerId?' id="'+n(l.containerId)+'"':"")+' class="'+n(l.containerClass)+'">'},t.renderer.rules.tocClose=function(){return"</nav>"},t.renderer.rules.tocBody=function(e,t){var i=Object.assign({},r);e&&t>=0&&(i=Object.assign(i,e[t].inlineOptions));var o,s={},c=Array.isArray(i.level)?(o=i.level,function(e){return o.includes(e)}):function(e){return function(n){return n>=e}}(i.level);return function e(t){var l=i.listClass?' class="'+n(i.listClass)+'"':"",o=i.itemClass?' class="'+n(i.itemClass)+'"':"",a=i.linkClass?' class="'+n(i.linkClass)+'"':"";if(0===t.c.length)return"";var u="";return(0===t.l||c(t.l))&&(u+="<"+(n(i.listType)+l)+">"),t.c.forEach(function(t){c(t.l)?u+="<li"+o+"><a"+a+' href="#'+function(e){for(var n=e,t=i.uniqueSlugStartIndex;Object.prototype.hasOwnProperty.call(s,n);)n=e+"-"+t++;return s[n]=!0,n}(r.slugify(t.n))+'">'+("function"==typeof i.format?i.format(t.n,n):n(t.n))+"</a>"+e(t)+"</li>":u+=e(t)}),(0===t.l||c(t.l))&&(u+="</"+n(i.listType)+">"),u}(l)},t.core.ruler.push("generateTocAst",function(e){l=function(e){for(var n={l:0,n:"",c:[]},t=[n],r=0,l=e.length;r<l;r++){var i=e[r];if("heading_open"===i.type){var o=e[r+1].children.filter(function(e){return"text"===e.type||"code_inline"===e.type}).reduce(function(e,n){return e+n.content},""),s={l:parseInt(i.tag.substr(1),10),n:o,c:[]};if(s.l>t[0].l)t[0].c.push(s),t.unshift(s);else if(s.l===t[0].l)t[1].c.push(s),t[0]=s;else{for(;s.l<=t[0].l;)t.shift();t[0].c.push(s),t.unshift(s)}}}return n}(e.tokens),"function"==typeof r.callback&&r.callback(t.renderer.rules.tocOpen()+t.renderer.rules.tocBody()+t.renderer.rules.tocClose(),l)}),t.block.ruler.before("heading","toc",function(e,n,t,r){var l,o=e.src.slice(e.bMarks[n]+e.tShift[n],e.eMarks[n]).split(" ")[0];if(!i.test(o))return!1;if(r)return!0;var s=i.exec(o),c={};if(null!==s&&3===s.length)try{c=JSON.parse(s[2])}catch(e){}return e.line=n+1,(l=e.push("tocOpen","nav",1)).markup="",l.map=[n,e.line],l.inlineOptions=c,(l=e.push("tocBody","",0)).markup="",l.map=[n,e.line],l.inlineOptions=c,l.children=[],(l=e.push("tocClose","nav",-1)).markup="",!0},{alt:["paragraph","reference","blockquote"]})}});
|
||||
//# sourceMappingURL=markdownItTocDoneRight.umd.js.map
|
@ -111,7 +111,8 @@ class MarkdownIt extends VxWorker {
|
||||
this.codeNodesCollected = false;
|
||||
|
||||
// Used to deduplicate header Ids.
|
||||
this.headerIds = new Set();
|
||||
// One for markdownItAnchor and one for markdownItTocDoneRight.
|
||||
this.headerIds = [new Set(), new Set()];
|
||||
|
||||
this.mdit = window.markdownit({
|
||||
html: this.options.enableHtmlTag,
|
||||
@ -140,16 +141,6 @@ class MarkdownIt extends VxWorker {
|
||||
return /^file:/.test(str) ? true : this.defaultValidateLink(p_url);
|
||||
};
|
||||
|
||||
this.mdit.use(window.markdownitHeadingAnchor, {
|
||||
anchorClass: 'vx-anchor',
|
||||
addHeadingID: true,
|
||||
addHeadingAnchor: false,
|
||||
anchorIcon: '#',
|
||||
slugify: (md, str) => {
|
||||
return this.generateHeaderId(str);
|
||||
},
|
||||
});
|
||||
|
||||
this.mdit.use(window.markdownitTaskLists);
|
||||
|
||||
this.mdit.use(window.markdownitSub);
|
||||
@ -216,6 +207,30 @@ class MarkdownIt extends VxWorker {
|
||||
this.mdit.use(window['markdown-it-xss']);
|
||||
});
|
||||
}
|
||||
|
||||
this.mdit.use(window.markdownItAnchor, {
|
||||
slugify: (str) => {
|
||||
return this.generateHeaderId(this.headerIds[0], str);
|
||||
},
|
||||
permalink: true,
|
||||
permalinkBefore: false,
|
||||
permalinkClass: 'vx-header-anchor',
|
||||
permalinkSpace: false,
|
||||
// We use CSS:after to add the mark.
|
||||
permalinkSymbol: '',
|
||||
permalinkAttrs: (slug, state) => {
|
||||
return {
|
||||
'vx-data-anchor-icon': '¶'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.mdit.use(window.markdownItTocDoneRight, {
|
||||
slugify: (str) => {
|
||||
return this.generateHeaderId(this.headerIds[1], str);
|
||||
},
|
||||
containerClass: 'vx-table-of-contents'
|
||||
});
|
||||
}
|
||||
|
||||
registerInternal() {
|
||||
@ -233,7 +248,8 @@ class MarkdownIt extends VxWorker {
|
||||
this.frontMatterNode = null;
|
||||
this.codeNodesStore.clearNodes();
|
||||
this.codeNodesCollected = false;
|
||||
this.headerIds.clear();
|
||||
this.headerIds[0].clear();
|
||||
this.headerIds[1].clear();
|
||||
|
||||
if (p_node != this.lastContainerNode) {
|
||||
this.lastContainerNode = p_node;
|
||||
@ -300,15 +316,15 @@ class MarkdownIt extends VxWorker {
|
||||
return this.codeNodesStore.getNodes(p_langs);
|
||||
}
|
||||
|
||||
generateHeaderId(p_str) {
|
||||
generateHeaderId(p_headerIds, p_str) {
|
||||
let idBase = p_str.replace(/\s/g, '-').toLowerCase();
|
||||
let id = idBase;
|
||||
let idx = 1;
|
||||
while (this.headerIds.has(id)) {
|
||||
while (p_headerIds.has(id)) {
|
||||
id = idBase + '-' + idx;
|
||||
++idx;
|
||||
}
|
||||
this.headerIds.add(id);
|
||||
p_headerIds.add(id);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ class NodeLineMapper {
|
||||
}
|
||||
}
|
||||
|
||||
getHeadingContent(p_node) {
|
||||
return p_node.textContent;
|
||||
}
|
||||
|
||||
updateHeadingNodes() {
|
||||
this.headingNodes = this.container.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
||||
let headings = [];
|
||||
@ -45,12 +49,13 @@ class NodeLineMapper {
|
||||
let regExp = /^\d(?:\.\d)*\.? /;
|
||||
for (let i = 0; i < this.headingNodes.length; ++i) {
|
||||
let node = this.headingNodes[i];
|
||||
let headingContent = this.getHeadingContent(node);
|
||||
headings.push({
|
||||
name: node.textContent,
|
||||
name: headingContent,
|
||||
level: parseInt(node.tagName.substr(1)),
|
||||
anchor: node.id
|
||||
});
|
||||
if (needSectionNumber && regExp.test(node.textContent)) {
|
||||
if (needSectionNumber && regExp.test(headingContent)) {
|
||||
needSectionNumber = false;
|
||||
}
|
||||
}
|
||||
|
@ -293,3 +293,5 @@ void NotebookExplorer::locateNode(Node *p_node)
|
||||
m_nodeExplorer->setCurrentNode(p_node);
|
||||
m_nodeExplorer->setFocus();
|
||||
}
|
||||
|
||||
|
||||
|
@ -409,7 +409,11 @@ QAction *ViewWindow::addAction(QToolBar *p_toolBar, ViewWindowToolBarHelper::Act
|
||||
act = ViewWindowToolBarHelper::addAction(p_toolBar, p_action);
|
||||
connect(act, &QAction::triggered,
|
||||
this, [this]() {
|
||||
if (m_findAndReplace && m_findAndReplace->isVisible()) {
|
||||
hideFindAndReplaceWidget();
|
||||
} else {
|
||||
showFindAndReplaceWidget();
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user