Skip to content

Commit ee1230b

Browse files
authored
Merge pull request #1532 from freitagsrunde/feature/customTocLevel
Set TOC depth freely for every note by using YAML metadata or an option within `[toc]`
2 parents cab80c1 + 3438c57 commit ee1230b

File tree

9 files changed

+120
-9
lines changed

9 files changed

+120
-9
lines changed

lib/config/default.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,6 @@ module.exports = {
188188
// 2nd appearance: "31-good-morning-my-friend---do-you-have-5-1"
189189
// 3rd appearance: "31-good-morning-my-friend---do-you-have-5-2"
190190
linkifyHeaderStyle: 'keep-case',
191-
autoVersionCheck: true
191+
autoVersionCheck: true,
192+
defaultTocDepth: 3
192193
}

lib/config/environment.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,5 +147,6 @@ module.exports = {
147147
openID: toBooleanConfig(process.env.CMD_OPENID),
148148
defaultUseHardbreak: toBooleanConfig(process.env.CMD_DEFAULT_USE_HARD_BREAK),
149149
linkifyHeaderStyle: process.env.CMD_LINKIFY_HEADER_STYLE,
150-
autoVersionCheck: toBooleanConfig(process.env.CMD_AUTO_VERSION_CHECK)
150+
autoVersionCheck: toBooleanConfig(process.env.CMD_AUTO_VERSION_CHECK),
151+
defaultTocDepth: toIntegerConfig(process.env.CMD_DEFAULT_TOC_DEPTH)
151152
}

lib/status/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ exports.getConfig = (req, res) => {
4141
allowedUploadMimeTypes: config.allowedUploadMimeTypes,
4242
defaultUseHardbreak: config.defaultUseHardbreak,
4343
linkifyHeaderStyle: config.linkifyHeaderStyle,
44-
useCDN: config.useCDN
44+
useCDN: config.useCDN,
45+
defaultTocDepth: config.defaultTocDepth
4546
}
4647
res.set({
4748
'Cache-Control': 'private', // only cache by client

public/css/extra.css

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,32 @@
263263
padding-right: 40px;
264264
}
265265

266+
.ui-toc-dropdown .nav .nav>li>ul>li>ul>li>a {
267+
padding-top: 1px;
268+
padding-bottom: 1px;
269+
padding-left: 50px;
270+
font-size: 12px;
271+
font-weight: 400;
272+
}
273+
274+
.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>ul>li>a {
275+
padding-right: 50px;
276+
}
277+
278+
.ui-toc-dropdown .nav .nav>li>ul>li>ul>li>ul>li>a {
279+
padding-top: 1px;
280+
padding-bottom: 1px;
281+
padding-left: 60px;
282+
font-size: 12px;
283+
font-weight: 400;
284+
}
285+
286+
.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>ul>li>ul>li>a {
287+
padding-right: 60px;
288+
}
289+
290+
291+
266292
.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover {
267293
padding-left: 29px;
268294
}
@@ -279,6 +305,22 @@
279305
padding-right: 39px;
280306
}
281307

308+
.ui-toc-dropdown .nav .nav>li>ul>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>ul>li>a:hover {
309+
padding-left: 49px;
310+
}
311+
312+
.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>ul>li>a:focus,.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>ul>li>a:hover {
313+
padding-right: 49px;
314+
}
315+
316+
.ui-toc-dropdown .nav .nav>li>ul>li>ul>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>ul>li>ul>li>a:hover {
317+
padding-left: 59px;
318+
}
319+
320+
.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>ul>li>ul>li>a:focus,.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>ul>li>ul>li>a:hover {
321+
padding-right: 59px;
322+
}
323+
282324
.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a {
283325
padding-left: 28px;
284326
font-weight: 500;
@@ -297,6 +339,24 @@
297339
padding-right: 38px;
298340
}
299341

342+
.ui-toc-dropdown .nav .nav>.active>.nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>.nav>.active>a {
343+
padding-left: 48px;
344+
font-weight: 500;
345+
}
346+
347+
.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.active>.nav>.nav>.active>a {
348+
padding-right: 48px;
349+
}
350+
351+
.ui-toc-dropdown .nav .nav>.active>.nav>.active>.nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>.nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>.nav>.active>.nav>.active>a {
352+
padding-left: 58px;
353+
font-weight: 500;
354+
}
355+
356+
.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active>.nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active>.nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.active>.nav>.nav>.active>.nav>.active>a {
357+
padding-right: 58px;
358+
}
359+
300360
/* support japanese font */
301361
.markdown-body[lang^="ja"] {
302362
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ Pro W3", Osaka, Meiryo, "メイリオ", "MS Gothic", "MS ゴシック", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";

public/docs/features.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ View
8282
## Table of Contents:
8383
You can look at the bottom right section of the view area, there is a _ToC_ button <i class="fa fa-bars"></i>.
8484
Pressing that button will show you a current _Table of Contents_, and will highlight which section you're at.
85-
ToCs support up to **three header levels**.
85+
ToCs support up to **five header levels**, the **default** is **set to three**. The maxLevel can be set for each note by using
86+
[YAML Metadata](./yaml-metadata)
8687

8788
## Permalink
8889
Every header will automatically add a permalink on the right side.
@@ -133,12 +134,19 @@ You can provide advanced note information to set the browser behavior (visit abo
133134
- GA: set to use Google Analytics
134135
- disqus: set to use Disqus
135136
- slideOptions: setup slide mode options
137+
- toc: set options of the Table of Contents.
136138

137139
## ToC:
138-
Use the syntax `[TOC]` to embed table of content into your note.
140+
Use the syntax `[TOC]` to embed table of content into your note. By default, three header levels are displayed. This can also be specified by using [YAML Metadata](./yaml-metadata).
139141

140142
[TOC]
141143

144+
You can also specify the number of header levels by specifying the `maxLevel` like this: `[TOC maxLevel=1]`
145+
146+
[TOC maxLevel=1]
147+
148+
149+
142150
## Emoji
143151
You can type any emoji like this :smile: :smiley: :cry: :wink:
144152
> See full emoji list [here](http://www.emoji-cheat-sheet.com/).

public/docs/yaml-metadata.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,22 @@ This option allows you to enable Disqus with your shortname.
139139
disqus: codimd
140140
```
141141

142+
toc
143+
---
144+
145+
This option allows you to set options regarding the table of contents (toc). Currently, its only option is to set the maxDepth.
146+
147+
**Notice: always use two spaces as indention in YAML metadata!**
148+
149+
150+
> **maxDepth:**
151+
> default: not set (whioch will show everything until level 3 (h1 -- h3))
152+
> max: 5 (as defined by md-toc.js)
153+
154+
155+
**Example**
156+
157+
142158
type
143159
---
144160
This option allows you to switch the document view to the slide preview, to simplify live editing of presentations.

public/js/extra.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,12 @@ export function generateToc (id) {
877877
const target = $(`#${id}`)
878878
target.html('')
879879
/* eslint-disable no-unused-vars */
880+
881+
var tocOptions = md.meta.toc || {}
882+
var maxLevel = (typeof tocOptions.maxLevel === 'number' && tocOptions.maxLevel > 0) ? tocOptions.maxLevel : window.defaultTocDepth
883+
880884
var toc = new window.Toc('doc', {
881-
level: 3,
885+
level: maxLevel,
882886
top: -1,
883887
class: 'toc',
884888
ulClass: 'nav',
@@ -1076,11 +1080,20 @@ export function renderTOC (view) {
10761080
const target = $(`#${id}`)
10771081
target.html('')
10781082
/* eslint-disable no-unused-vars */
1083+
1084+
const specificDepth = parseInt(toc.data('toc-depth'))
1085+
1086+
var tocOptions = md.meta.toc || {}
1087+
var yamlMaxDepth = (typeof tocOptions.maxLevel === 'number' && tocOptions.maxLevel > 0) ? tocOptions.maxLevel : window.defaultTocDepth
1088+
1089+
var maxLevel = specificDepth || yamlMaxDepth
1090+
10791091
const TOC = new window.Toc('doc', {
1080-
level: 3,
1092+
level: maxLevel,
10811093
top: -1,
10821094
class: 'toc',
10831095
targetId: id,
1096+
data: { tocDepth: specificDepth },
10841097
process: getHeaderContent
10851098
})
10861099
/* eslint-enable no-unused-vars */
@@ -1335,9 +1348,12 @@ const gistPlugin = new Plugin(
13351348
// TOC
13361349
const tocPlugin = new Plugin(
13371350
// regexp to match
1338-
/^\[TOC\]$/i,
1351+
/^\[TOC(|\s*maxLevel=\d+?)\]$/i,
13391352

1340-
(match, utils) => '<div class="toc"></div>'
1353+
(match, utils) => {
1354+
const tocDepth = match[1].split(/[?&=]+/)[1]
1355+
return `<div class="toc" data-toc-depth="${tocDepth}"></div>`
1356+
}
13411357
)
13421358
// slideshare
13431359
const slidesharePlugin = new Plugin(

public/js/lib/common/constant.ejs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ window.linkifyHeaderStyle = '<%- linkifyHeaderStyle %>'
1313
window.DROPBOX_APP_KEY = '<%- DROPBOX_APP_KEY %>'
1414

1515
window.USE_CDN = <%- useCDN %>
16+
17+
window.defaultTocDepth = <%- defaultTocDepth %>

public/vendor/md-toc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
/**
33
* md-toc.js v1.0.2
44
* https://github.com/yijian166/md-toc.js
5+
*
6+
* Adapted to accept data attributes
57
*/
68

79
(function (window) {
@@ -15,6 +17,7 @@
1517
this.tocTop = parseInt(options.top) || 0
1618
this.elChilds = this.el.children
1719
this.process = options['process']
20+
this.data = options.data || {}
1821
if (!this.elChilds.length) return
1922
this._init()
2023
}
@@ -123,6 +126,9 @@
123126
this.toc = document.createElement('div')
124127
this.toc.innerHTML = this.tocContent
125128
this.toc.setAttribute('class', this.tocClass)
129+
if (this.data.tocDepth) {
130+
this.toc.dataset.tocDepth = this.data.tocDepth
131+
}
126132
if (!this.options.targetId) {
127133
this.el.appendChild(this.toc)
128134
} else {

0 commit comments

Comments
 (0)