├── package.json
├── README.md
├── LICENSE
├── .gitignore
└── dist
├── toc.css
└── toc.js
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docsify-toc",
3 | "version": "1.1.0",
4 | "description": "docsify-toc",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "files": [
10 | "src",
11 | "dist"
12 | ],
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/mrpotatoes/docsify-toc.git"
16 | },
17 | "keywords": [],
18 | "author": "",
19 | "license": "ISC",
20 | "bugs": {
21 | "url": "https://github.com/mrpotatoes/docsify-toc/issues"
22 | },
23 | "homepage": "https://github.com/mrpotatoes/docsify-toc#readme"
24 | }
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Docsify Table of Contents
2 |
3 |
4 |
5 |
6 | docsify-toc
7 |
8 |
9 |
10 | **Note**: I won't be adding features but feel free to add pull requests and if they work/pass tests I'll add them in.
11 |
12 | ## To use
13 | Add stylesheet
14 | ```html
15 |
16 | ```
17 |
18 | Add JS
19 | ```html
20 |
21 | ```
22 |
23 | Add settings
24 | ```js
25 | window.$docsify = {
26 | toc: {
27 | scope: '.markdown-section',
28 | headings: 'h1, h2, h3, h4, h5, h6',
29 | title: 'Table of Contents',
30 | },
31 | }
32 | ```
33 |
34 | # TODO
35 | - [ ] Tests
36 | - [ ] Example
37 | - [x] ~Documentation~
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Andric LibreSinn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # Bower dependency directory (https://bower.io/)
29 | bower_components
30 |
31 | # node-waf configuration
32 | .lock-wscript
33 |
34 | # Compiled binary addons (https://nodejs.org/api/addons.html)
35 | build/Release
36 |
37 | # Dependency directories
38 | node_modules/
39 | jspm_packages/
40 |
41 | # TypeScript v1 declaration files
42 | typings/
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # Yarn Integrity file
57 | .yarn-integrity
58 |
59 | # dotenv environment variables file
60 | .env
61 |
62 | # next.js build output
63 | .next
64 |
--------------------------------------------------------------------------------
/dist/toc.css:
--------------------------------------------------------------------------------
1 | .content {
2 | display: flex;
3 | flex-direction: row-reverse;
4 | justify-content: center;
5 | }
6 | .markdown-section {
7 | /* flex: 1 1 0%; */
8 | margin: 0 48px;
9 | }
10 | .nav {
11 | width: var(--toc-width, 700px);
12 | /* align-self: flex-start;
13 | flex: 0 0 auto; */
14 | }
15 | aside.nav.nothing {
16 | width: 0;
17 | }
18 |
19 | .page_toc {
20 | position: fixed;
21 | border-left-style: solid;
22 | border-left-width: 1px;
23 | border-left-color: rgba(0, 0, 0, 0.07);
24 | border-image-slice: 1;
25 | padding-left: 5px;
26 | }
27 |
28 | .page_toc a > * {
29 | pointer-events: none;
30 | }
31 |
32 | .page_toc code {
33 | background-color: #f8f8f8;
34 | border-radius: 2px;
35 | color: #e96900;
36 | font-family: 'Roboto Mono', Monaco, courier, monospace;
37 | font-size: 0.8rem;
38 | margin: 0 2px;
39 | padding: 3px 5px;
40 | }
41 |
42 | .page_toc p.title {
43 | margin: 0px 0 0px 9px;
44 | padding-bottom: 5px;
45 | font-weight: 600;
46 | font-size: 1.2em;
47 | }
48 | .page_toc .anchor:hover:after {
49 | content: "";
50 | }
51 |
52 | .page_toc ul {
53 | list-style-type: none;
54 | margin-top: 0px;
55 | padding-left: 10px;
56 | color: var(--text-color-base, black);
57 | text-decoration: none;
58 | font-weight: 300;
59 | line-height: 1.6em;
60 | }
61 |
62 | .page_toc ul a:hover span {
63 | color: var(--text-color-tertiary, #42b983);
64 | border-bottom: none !important;
65 | text-decoration:none !important;
66 | }
67 |
68 | .page_toc ul a {
69 | color: var(--text-color-base, black);
70 | text-decoration: none;
71 | font-weight: 300;
72 | line-height: 1.6em;
73 | }
74 |
75 | @media screen and (max-width: 1300px) {
76 | .page_toc {
77 | position: relative;
78 | left: 0;
79 | top: -20px;
80 | padding: 10px 0;
81 | border: none;
82 | border-bottom: 1px solid #ddd;
83 | font-size: 1.0em;
84 | }
85 | .page_toc a:before {
86 | content: "- ";
87 | }
88 | .nav {
89 | margin: 0 auto;
90 | width: 800px;
91 | }
92 | .page_toc p.title {
93 | font-weight: 300;
94 | font-size: 1.8em;
95 | }
96 | .content {
97 | display: block;
98 | }
99 | .markdown-section {
100 | margin: 0 auto;
101 | }
102 | }
103 |
104 | .page_toc .active {
105 | border-left: 5px solid;
106 | color: var(--theme-color, #42b983);
107 | padding-left: 10px;
108 | }
109 |
--------------------------------------------------------------------------------
/dist/toc.js:
--------------------------------------------------------------------------------
1 | var defaultOptions = {
2 | headings: 'h1, h2',
3 | scope: '.markdown-section',
4 |
5 | // To make work
6 | title: 'Contents',
7 | listType: 'ul',
8 | }
9 |
10 | // Element builders
11 | var tocHeading = function(Title) {
12 | return document.createElement('h2').appendChild(
13 | document.createTextNode(Title)
14 | )
15 | }
16 |
17 | var aTag = function(src) {
18 | var a = document.createElement('a');
19 | var content = src.firstChild.innerHTML;
20 |
21 | // Use this to clip text w/ HTML in it.
22 | // https://github.com/arendjr/text-clipper
23 | a.innerHTML = content;
24 | a.href = src.firstChild.href;
25 | a.onclick = tocClick
26 |
27 | // In order to remove this gotta fix the styles.
28 | a.setAttribute('class', 'anchor');
29 |
30 | return a
31 | };
32 |
33 | var tocClick = function(e) {
34 | var divs = document.querySelectorAll('.page_toc .active');
35 |
36 | // Remove the previous classes
37 | [].forEach.call(divs, function(div) {
38 | div.setAttribute('class', 'anchor')
39 | });
40 |
41 | // Make sure this is attached to the parent not itself
42 | e.currentTarget.setAttribute('class', 'active')
43 | };
44 |
45 | var createList = function(wrapper, count) {
46 | while (count--) {
47 | if(wrapper){
48 | wrapper = wrapper.appendChild(
49 | document.createElement('ul')
50 | );
51 | }
52 | if (count) {
53 | wrapper = wrapper.appendChild(
54 | document.createElement('li')
55 | );
56 | }
57 | }
58 |
59 | return wrapper;
60 | };
61 |
62 | //------------------------------------------------------------------------
63 |
64 | var getHeaders = function(selector) {
65 | var headings2 = document.querySelectorAll(selector);
66 | var ret = [];
67 |
68 | [].forEach.call(headings2, function(heading) {
69 | ret = ret.concat(heading);
70 | });
71 |
72 | return ret;
73 | };
74 |
75 | var getLevel = function(header) {
76 | var decs = header.match(/\d/g);
77 |
78 | return decs ? Math.min.apply(null, decs) : 1;
79 | };
80 |
81 | var jumpBack = function(currentWrapper, offset) {
82 | while (offset--) {
83 | currentWrapper = currentWrapper.parentElement;
84 | }
85 |
86 | return currentWrapper;
87 | };
88 |
89 | var buildTOC = function(options) {
90 | var ret = document.createElement('ul');
91 | var wrapper = ret;
92 | var lastLi = null;
93 | var selector = options.scope + ' ' + options.headings
94 | var headers = getHeaders(selector).filter(h => h.id);
95 |
96 | headers.reduce(function(prev, curr, index) {
97 | var currentLevel = getLevel(curr.tagName);
98 | var offset = currentLevel - prev;
99 |
100 | wrapper = (offset > 0)
101 | ? createList(lastLi, offset)
102 | : jumpBack(wrapper, -offset * 2)
103 |
104 | wrapper = wrapper || ret;
105 |
106 | var li = document.createElement('li');
107 |
108 | wrapper.appendChild(li).appendChild(aTag(curr));
109 |
110 | lastLi = li;
111 |
112 | return currentLevel;
113 | }, getLevel(options.headings));
114 |
115 | return ret;
116 | };
117 |
118 | // Docsify plugin functions
119 | function plugin(hook, vm) {
120 | var userOptions = vm.config.toc;
121 |
122 | hook.mounted(function () {
123 | var content = window.Docsify.dom.find(".content");
124 | if (content) {
125 | var nav = window.Docsify.dom.create("aside", "");
126 | window.Docsify.dom.toggleClass(nav, "add", "nav");
127 | window.Docsify.dom.before(content, nav);
128 | }
129 | });
130 |
131 | hook.doneEach(function () {
132 | var nav = document.querySelectorAll('.nav')[0]
133 | var t = Array.from(document.querySelectorAll('.nav'))
134 |
135 | if (!nav) {
136 | return;
137 | }
138 |
139 | const toc = buildTOC(userOptions);
140 |
141 | // Just unset it for now.
142 | if (!toc.innerHTML) {
143 | nav.innerHTML = null
144 | return;
145 | }
146 |
147 | // Fix me in the future
148 | var title = document.createElement('p');
149 | title.innerHTML = userOptions.title;
150 | title.setAttribute('class', 'title');
151 |
152 | var container = document.createElement('div');
153 | container.setAttribute('class', 'page_toc');
154 |
155 | container.appendChild(title);
156 | container.appendChild(toc);
157 |
158 | // Existing TOC
159 | var tocChild = document.querySelectorAll('.nav .page_toc');
160 |
161 | if (tocChild.length > 0) {
162 | tocChild[0].parentNode.removeChild(tocChild[0]);
163 | }
164 |
165 | nav.appendChild(container);
166 | });
167 | }
168 |
169 | // Docsify plugin options
170 | window.$docsify['toc'] = Object.assign(defaultOptions, window.$docsify['toc']);
171 | window.$docsify.plugins = [].concat(plugin, window.$docsify.plugins);
172 |
--------------------------------------------------------------------------------