44 |
45 |
46 |
47 | ## Style the TOC table
48 |
49 | The TOC must have some CSS style to appear correctly, you can find a default implementation into file `css/toc.css`
50 | The style is compatible with mediawiki themes
51 |
52 | # Disable generation per page
53 |
54 | It is possible to suppress the TOC generation in specific pages, for example the index page normally doesn't have a TOC.
55 | This can be done into the [Front Matter](http://jekyllrb.com/docs/frontmatter/) section used by jekyll
56 |
57 |
58 | You must add the `noToc: true` directive
59 |
60 | ---
61 | permalink: index.html
62 | layout: default
63 | title: Main Page with TOC
64 | noToc: true
65 | ---
66 |
67 |
68 | # Advanced configuration
69 |
70 | Normally no configuration is necessary but you can set some parameter into you `_config.yml` file
71 |
72 |
73 |
74 |
Parameter name
75 |
Description
76 |
Default value
77 |
78 |
79 |
80 |
minItemsToShowToc
81 |
Minimum number of items to show the TOC Suppose you want to generated the TOC only if there are at least 3 H1
82 |
0 (no limit)
83 |
84 |
85 |
86 |
tocTopTag
87 |
The top level tag given nokogiri to find Suppose you want to generated the TOC start form h1 to h5
88 |
h1
89 |
90 |
91 |
anchorPrefix
92 |
The prefix used to generate the anchor name
93 |
tocAnchor-
94 |
95 |
96 |
97 |
showToggleButton
98 |
The TOC has a button used to collapse/expand the list, this requires a little of Javascript
99 | This package contains a jQuery plugin to handle the click
100 |
false
101 |
102 |
103 |
104 | # Toggling the button via jQuery
105 |
106 | If the toogle button is visible you can use the jquery plugin included in this repository
107 |
108 | Below is shown an usage example
109 |
110 |
111 |
112 |
113 | {{ page.title }}
114 |
115 |
116 |
117 |
118 |
119 |
120 |
125 |
126 |
127 |
128 | {{ content | toc_generate }}
129 |
130 |
131 |
132 |
133 | # How it works
134 |
135 | The filter converts all `H1` and `H2` elements in a parent-child TOC based on how the markdown code is traslated in HTML.
136 | Markdown generates `H1` and `H2` as siblings
137 |
138 | For example the markdown code shown below
139 |
140 | heading 1
141 | =========
142 |
143 | blah blah
144 |
145 | heading 1.1
146 | -----------
147 |
148 | Generates the following HTML code
149 |
150 |
heading 1
151 |
blah blah
152 |
heading 1.1
153 |
154 | # Github pages can't use plugins
155 |
156 | If you host your jekyll pages on github you can't run plugins, in this scenario you can use a full javascript solution using [TOC Generator for Markdown](https://github.com/dafi/tocmd-generator)
157 |
--------------------------------------------------------------------------------
/_plugins/tocGenerator.rb:
--------------------------------------------------------------------------------
1 | require 'nokogiri'
2 |
3 | module Jekyll
4 | module TOCGenerator
5 | TOGGLE_HTML = '
%1
%2
'
6 | TOC_CONTAINER_HTML = '
%1
%2
'
7 | HIDE_HTML = '[%1]'
8 |
9 | def toc_generate(html)
10 | # No Toc can be specified on every single page
11 | # For example the index page has no table of contents
12 | no_toc = @context.environments.first["page"]["noToc"] || false;
13 |
14 | if no_toc
15 | return html
16 | end
17 |
18 | config = @context.registers[:site].config
19 | # Minimum number of items needed to show TOC, default 0 (0 means no minimum)
20 | min_items_to_show_toc = config["minItemsToShowToc"] || 0
21 |
22 | anchor_prefix = config["anchorPrefix"] || 'tocAnchor-'
23 |
24 | # better for traditional page seo, commonlly use h1 as title
25 | toc_top_tag = config["tocTopTag"] || 'h1'
26 | toc_top_tag = toc_top_tag.gsub(/h/, '').to_i
27 | if toc_top_tag > 5
28 | toc_top_tag = 5
29 | end
30 | toc_sec_tag = toc_top_tag + 1
31 | toc_top_tag = "h#{toc_top_tag}"
32 | toc_sec_tag = "h#{toc_sec_tag}"
33 |
34 |
35 | # Text labels
36 | contents_label = config["contentsLabel"] || 'Contents'
37 | hide_label = config["hideLabel"] || 'hide'
38 | show_label = config["showLabel"] || 'show'
39 | show_toggle_button = config["showToggleButton"]
40 |
41 | toc_html = ''
42 | toc_level = 1
43 | toc_section = 1
44 | item_number = 1
45 | level_html = ''
46 |
47 | doc = Nokogiri::HTML(html)
48 |
49 | # Find H1 tag and all its H2 siblings until next H1
50 | doc.css(toc_top_tag).each do |tag|
51 | # TODO This XPATH expression can greatly improved
52 | ct = tag.xpath("count(following-sibling::#{toc_top_tag})")
53 | sects = tag.xpath("following-sibling::#{toc_sec_tag}[count(following-sibling::#{toc_top_tag})=#{ct}]")
54 |
55 | level_html = '';
56 | inner_section = 0;
57 |
58 | sects.map.each do |sect|
59 | inner_section += 1;
60 | anchor_id = anchor_prefix + toc_level.to_s + '-' + toc_section.to_s + '-' + inner_section.to_s
61 | sect['id'] = "#{anchor_id}"
62 |
63 | level_html += create_level_html(anchor_id,
64 | toc_level + 1,
65 | toc_section + inner_section,
66 | item_number.to_s + '.' + inner_section.to_s,
67 | sect.text,
68 | '')
69 | end
70 | if level_html.length > 0
71 | level_html = '