jekyll-toc 0.8.0.beta2 → 0.8.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +33 -32
- data/lib/table_of_contents/parser.rb +21 -24
- data/lib/version.rb +1 -1
- data/test/test_various_toc_html.rb +58 -9
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ff793cf0c346ce007f527e7441cad059b4ee01d05cf5ff632c163c75031af6f7
|
4
|
+
data.tar.gz: 000f6cddbd70c9b906caed9182bbefca8ca2127afc9568cebd7fcb5ef636e9f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 065f6561458207ea00a1512fc78499a77e753c807d9a8fa17b4a2a47b0c89e31eae4f8ff7f4a6a3cf69a85dcd5700dda0fd7e46d34395dd480fb390da6978cc9
|
7
|
+
data.tar.gz: 2e54f2d06c29eb9afcab58d5f960007e45c6955f42fdee6642ba18055dfd46016b42f7df70d9dffcbc7d763f71f969b00bc5c8342a292be2539b79145b7fb1c3
|
data/README.md
CHANGED
@@ -5,17 +5,18 @@
|
|
5
5
|
[](https://codeclimate.com/github/toshimaru/jekyll-toc)
|
6
6
|
[](https://codeclimate.com/github/toshimaru/jekyll-toc/test_coverage)
|
7
7
|
|
8
|
-
|
8
|
+
## Table of Contents
|
9
9
|
|
10
10
|
- [Installation](#installation)
|
11
11
|
- [Usage](#usage)
|
12
12
|
- [Generated HTML](#generated-html)
|
13
13
|
- [Customization](#customization)
|
14
14
|
- [Skip TOC](#skip-toc)
|
15
|
+
- [Skip TOC Section](#skip-toc-section)
|
15
16
|
- [TOC levels](#toc-levels)
|
16
17
|
- [CSS Styling](#css-styling)
|
17
18
|
|
18
|
-
|
19
|
+
## Installation
|
19
20
|
|
20
21
|
Add jekyll-toc plugin in your site's `Gemfile`, and run `bundle install`.
|
21
22
|
|
@@ -40,14 +41,14 @@ toc: true
|
|
40
41
|
---
|
41
42
|
```
|
42
43
|
|
43
|
-
|
44
|
+
## Usage
|
44
45
|
|
45
46
|
There are three Liquid filters, which can be applied to HTML content,
|
46
47
|
e.g. the Liquid variable `content` available in Jekyll's templates.
|
47
48
|
|
48
|
-
|
49
|
+
### 1. Basic Usage
|
49
50
|
|
50
|
-
|
51
|
+
#### `toc` filter
|
51
52
|
|
52
53
|
Add the `toc` filter to your site's `{{ content }}` (e.g. `_layouts/post.html`).
|
53
54
|
|
@@ -57,17 +58,17 @@ Add the `toc` filter to your site's `{{ content }}` (e.g. `_layouts/post.html`).
|
|
57
58
|
|
58
59
|
This filter places the TOC directly above the content.
|
59
60
|
|
60
|
-
|
61
|
+
### 2. Advanced Usage
|
61
62
|
|
62
63
|
If you'd like separated TOC and content, you can use `toc_only` and `inject_anchors` filters.
|
63
64
|
|
64
|
-
|
65
|
+
#### `toc_only` filter
|
65
66
|
|
66
67
|
Generates the TOC itself as described [below](#generated-table-of-contents-html).
|
67
68
|
Mostly useful in cases where the TOC should _not_ be placed immediately
|
68
69
|
above the content but at some other place of the page, i.e. an aside.
|
69
70
|
|
70
|
-
|
71
|
+
#### `inject_anchors` filter
|
71
72
|
|
72
73
|
Injects HTML anchors into the content without actually outputing the
|
73
74
|
TOC itself. They are of the form:
|
@@ -81,7 +82,7 @@ TOC itself. They are of the form:
|
|
81
82
|
This is only useful when the TOC itself should be placed at some other
|
82
83
|
location with the `toc_only` filter.
|
83
84
|
|
84
|
-
|
85
|
+
### Generated HTML
|
85
86
|
|
86
87
|

|
87
88
|
|
@@ -109,42 +110,30 @@ jekyll-toc generates an unordered list. The HTML output is as follows.
|
|
109
110
|
</ul>
|
110
111
|
```
|
111
112
|
|
112
|
-
|
113
|
+
### Customization
|
113
114
|
|
114
|
-
|
115
|
+
#### Skip TOC
|
115
116
|
|
116
|
-
The
|
117
|
+
The heading is ignored in the toc when you add `no_toc` to the class.
|
117
118
|
|
118
119
|
```html
|
119
120
|
<h1>h1</h1>
|
120
|
-
<h1 class="no_toc">This
|
121
|
+
<h1 class="no_toc">This heading is ignored in the toc</h1>
|
121
122
|
<h2>h2</h2>
|
122
123
|
```
|
123
124
|
|
124
|
-
|
125
|
-
|
126
|
-
The toc levels can be configured on `_config.yml`.
|
127
|
-
|
128
|
-
```yml
|
129
|
-
toc:
|
130
|
-
min_level: 2 # default: 1
|
131
|
-
max_level: 5 # default: 6
|
132
|
-
```
|
133
|
-
|
134
|
-
The default level range is `<h1>` to `<h6>`.
|
135
|
-
|
136
|
-
### Ignore within
|
125
|
+
#### Skip TOC Section
|
137
126
|
|
138
127
|
It can be configured to ignore elements within a selector:
|
139
128
|
|
140
129
|
```yml
|
141
130
|
toc:
|
142
|
-
|
131
|
+
no_toc_section_class: no_toc_within # default: no_toc_section
|
143
132
|
```
|
144
133
|
|
145
134
|
```html
|
146
135
|
<h1>h1</h1>
|
147
|
-
<div class="
|
136
|
+
<div class="no_toc_within">
|
148
137
|
<h2>h2</h2>
|
149
138
|
<h3>h3</h3>
|
150
139
|
</div>
|
@@ -153,21 +142,33 @@ toc:
|
|
153
142
|
|
154
143
|
Which would result in only the `<h1>` & `<h4>` within the example being included in the TOC.
|
155
144
|
|
156
|
-
|
145
|
+
#### TOC levels
|
146
|
+
|
147
|
+
The toc levels can be configured on `_config.yml`.
|
148
|
+
|
149
|
+
```yml
|
150
|
+
toc:
|
151
|
+
min_level: 2 # default: 1
|
152
|
+
max_level: 5 # default: 6
|
153
|
+
```
|
154
|
+
|
155
|
+
The default level range is `<h1>` to `<h6>`.
|
156
|
+
|
157
|
+
#### CSS Styling
|
157
158
|
|
158
159
|
The toc can be modified with CSS. The sample CSS is the following.
|
159
160
|
|
160
161
|
```css
|
161
162
|
.section-nav {
|
162
|
-
background-color: #
|
163
|
+
background-color: #fff;
|
163
164
|
margin: 5px 0;
|
164
165
|
padding: 10px 30px;
|
165
|
-
border: 1px solid #
|
166
|
+
border: 1px solid #e8e8e8;
|
166
167
|
border-radius: 3px;
|
167
168
|
}
|
168
169
|
```
|
169
170
|
|
170
|
-

|
171
172
|
|
172
173
|
Each TOC `li` entry has two CSS classes for further styling.
|
173
174
|
The general `toc-entry` is applied to all `li` elements in the `ul.section-nav`.
|
@@ -4,9 +4,11 @@ module Jekyll
|
|
4
4
|
module TableOfContents
|
5
5
|
# Parse html contents and generate table of contents
|
6
6
|
class Parser
|
7
|
+
NO_TOC_CLASS_NAME = 'no_toc'
|
7
8
|
PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u
|
8
9
|
|
9
10
|
DEFAULT_CONFIG = {
|
11
|
+
'no_toc_section_class' => 'no_toc_section',
|
10
12
|
'min_level' => 1,
|
11
13
|
'max_level' => 6
|
12
14
|
}.freeze
|
@@ -14,11 +16,15 @@ module Jekyll
|
|
14
16
|
def initialize(html, options = {})
|
15
17
|
@doc = Nokogiri::HTML::DocumentFragment.parse(html)
|
16
18
|
options = generate_option_hash(options)
|
17
|
-
@toc_levels = options[
|
18
|
-
@
|
19
|
+
@toc_levels = options['min_level']..options['max_level']
|
20
|
+
@no_toc_section_class = options['no_toc_section_class']
|
19
21
|
@entries = parse_content
|
20
22
|
end
|
21
23
|
|
24
|
+
def toc
|
25
|
+
build_toc + inject_anchors_into_html
|
26
|
+
end
|
27
|
+
|
22
28
|
def build_toc
|
23
29
|
%(<ul class="section-nav">\n#{build_toc_list(@entries)}</ul>)
|
24
30
|
end
|
@@ -31,38 +37,26 @@ module Jekyll
|
|
31
37
|
@doc.inner_html
|
32
38
|
end
|
33
39
|
|
34
|
-
def toc
|
35
|
-
build_toc + inject_anchors_into_html
|
36
|
-
end
|
37
|
-
|
38
40
|
private
|
39
41
|
|
40
42
|
# parse logic is from html-pipeline toc_filter
|
41
43
|
# https://github.com/jch/html-pipeline/blob/v1.1.0/lib/html/pipeline/toc_filter.rb
|
42
44
|
def parse_content
|
43
|
-
entries = []
|
44
45
|
headers = Hash.new(0)
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# TODO: Use kramdown auto ids
|
51
|
-
@doc.css(toc_headings).reject { |n| n.classes.include?('no_toc') }.each do |node|
|
47
|
+
(@doc.css(toc_headings) - @doc.css(toc_headings_in_no_toc_section))
|
48
|
+
.reject { |n| n.classes.include?(NO_TOC_CLASS_NAME) }
|
49
|
+
.inject([]) do |entries, node|
|
52
50
|
text = node.text
|
53
|
-
id =
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
.downcase
|
58
|
-
.gsub(PUNCTUATION_REGEXP, '') # remove punctuation
|
59
|
-
.tr(' ', '-') # replace spaces with dash
|
60
|
-
end
|
51
|
+
id = node.attribute('id') || text
|
52
|
+
.downcase
|
53
|
+
.gsub(PUNCTUATION_REGEXP, '') # remove punctuation
|
54
|
+
.tr(' ', '-') # replace spaces with dash
|
61
55
|
|
62
56
|
uniq = headers[id] > 0 ? "-#{headers[id]}" : ''
|
63
57
|
headers[id] += 1
|
64
58
|
header_content = node.children.first
|
65
|
-
next unless header_content
|
59
|
+
next entries unless header_content
|
66
60
|
|
67
61
|
entries << {
|
68
62
|
id: id,
|
@@ -73,8 +67,6 @@ module Jekyll
|
|
73
67
|
h_num: node.name.delete('h').to_i
|
74
68
|
}
|
75
69
|
end
|
76
|
-
|
77
|
-
entries
|
78
70
|
end
|
79
71
|
|
80
72
|
# Returns the list items for entries
|
@@ -117,6 +109,7 @@ module Jekyll
|
|
117
109
|
def get_nest_entries(entries, min_h_num)
|
118
110
|
entries.inject([]) do |nest_entries, entry|
|
119
111
|
break nest_entries if entry[:h_num] == min_h_num
|
112
|
+
|
120
113
|
nest_entries << entry
|
121
114
|
end
|
122
115
|
end
|
@@ -125,6 +118,10 @@ module Jekyll
|
|
125
118
|
@toc_levels.map { |level| "h#{level}" }.join(',')
|
126
119
|
end
|
127
120
|
|
121
|
+
def toc_headings_in_no_toc_section
|
122
|
+
@toc_levels.map { |level| ".#{@no_toc_section_class} h#{level}" }.join(',')
|
123
|
+
end
|
124
|
+
|
128
125
|
def generate_option_hash(options)
|
129
126
|
DEFAULT_CONFIG.merge(options)
|
130
127
|
rescue TypeError
|
data/lib/version.rb
CHANGED
@@ -86,7 +86,7 @@ class TestVariousTocHtml < Minitest::Test
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def test_nested_toc_with_min_and_max
|
89
|
-
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1, {
|
89
|
+
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1, { 'min_level' => 2, 'max_level' => 5 })
|
90
90
|
doc = Nokogiri::HTML(parser.toc)
|
91
91
|
expected = <<-HTML
|
92
92
|
<ul class="section-nav">
|
@@ -248,7 +248,44 @@ class TestVariousTocHtml < Minitest::Test
|
|
248
248
|
assert_equal(expected, actual)
|
249
249
|
end
|
250
250
|
|
251
|
-
TEST_HTML_IGNORE = <<-HTML
|
251
|
+
TEST_HTML_IGNORE = <<-HTML
|
252
|
+
<h1>h1</h1>
|
253
|
+
<div class="no_toc_section">
|
254
|
+
<h2>h2</h2>
|
255
|
+
</div>
|
256
|
+
<h3>h3</h3>
|
257
|
+
<h6>h6</h6>
|
258
|
+
HTML
|
259
|
+
|
260
|
+
def test_nested_toc_with_no_toc_section_class
|
261
|
+
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE)
|
262
|
+
doc = Nokogiri::HTML(parser.toc)
|
263
|
+
expected = <<-HTML
|
264
|
+
<ul class="section-nav">
|
265
|
+
<li class="toc-entry toc-h1">
|
266
|
+
<a href="#h1">h1</a>
|
267
|
+
<ul>
|
268
|
+
<li class="toc-entry toc-h3">
|
269
|
+
<a href="#h3">h3</a>
|
270
|
+
<ul>
|
271
|
+
<li class="toc-entry toc-h6"><a href="#h6">h6</a></li>
|
272
|
+
</ul>
|
273
|
+
</li>
|
274
|
+
</ul>
|
275
|
+
</li>
|
276
|
+
</ul>
|
277
|
+
HTML
|
278
|
+
actual = doc.css('ul.section-nav').to_s
|
279
|
+
assert_equal(expected, actual)
|
280
|
+
|
281
|
+
html = parser.inject_anchors_into_html
|
282
|
+
assert_match(%r{<h1>.+</h1>}m, html)
|
283
|
+
assert_match(%r{<h3>.+</h3>}m, html)
|
284
|
+
assert_match(%r{<h6>.+</h6>}m, html)
|
285
|
+
assert_includes(html, '<h2>h2</h2>')
|
286
|
+
end
|
287
|
+
|
288
|
+
TEST_HTML_IGNORE_2 = <<-HTML
|
252
289
|
<h1>h1</h1>
|
253
290
|
<div class="exclude">
|
254
291
|
<h2>h2</h2>
|
@@ -256,13 +293,13 @@ TEST_HTML_IGNORE = <<-HTML
|
|
256
293
|
<h3>h3</h3>
|
257
294
|
<div class="exclude">
|
258
295
|
<h4>h4</h4>
|
259
|
-
<
|
296
|
+
<h5>h5</h5>
|
260
297
|
</div>
|
261
298
|
<h6>h6</h6>
|
262
|
-
HTML
|
299
|
+
HTML
|
263
300
|
|
264
|
-
def
|
265
|
-
parser = Jekyll::TableOfContents::Parser.new(
|
301
|
+
def test_nested_toc_with_no_toc_section_class_option
|
302
|
+
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE_2, { 'no_toc_section_class' => 'exclude' })
|
266
303
|
doc = Nokogiri::HTML(parser.toc)
|
267
304
|
expected = <<-HTML
|
268
305
|
<ul class="section-nav">
|
@@ -280,8 +317,15 @@ HTML
|
|
280
317
|
</ul>
|
281
318
|
HTML
|
282
319
|
actual = doc.css('ul.section-nav').to_s
|
283
|
-
|
284
320
|
assert_equal(expected, actual)
|
321
|
+
|
322
|
+
html = parser.inject_anchors_into_html
|
323
|
+
assert_match(%r{<h1>.+</h1>}m, html)
|
324
|
+
assert_match(%r{<h3>.+</h3>}m, html)
|
325
|
+
assert_match(%r{<h6>.+</h6>}m, html)
|
326
|
+
assert_includes(html, '<h2>h2</h2>')
|
327
|
+
assert_includes(html, '<h4>h4</h4>')
|
328
|
+
assert_includes(html, '<h5>h5</h5>')
|
285
329
|
end
|
286
330
|
|
287
331
|
TEST_EXPLICIT_ID = <<-HTML
|
@@ -291,7 +335,7 @@ HTML
|
|
291
335
|
HTML
|
292
336
|
|
293
337
|
def test_toc_with_explicit_id
|
294
|
-
parser = Jekyll::TableOfContents::Parser.new(TEST_EXPLICIT_ID
|
338
|
+
parser = Jekyll::TableOfContents::Parser.new(TEST_EXPLICIT_ID)
|
295
339
|
doc = Nokogiri::HTML(parser.toc)
|
296
340
|
expected = <<-HTML
|
297
341
|
<ul class="section-nav">
|
@@ -300,7 +344,12 @@ HTML
|
|
300
344
|
<li class="toc-entry toc-h1"><a href="#third">h3</a></li>
|
301
345
|
</ul>
|
302
346
|
HTML
|
347
|
+
actual = doc.css('ul.section-nav').to_s
|
348
|
+
assert_equal(expected, actual)
|
303
349
|
|
304
|
-
|
350
|
+
html = parser.inject_anchors_into_html
|
351
|
+
assert_includes(html, %(<a id="h1" class="anchor" href="#h1" aria-hidden="true">))
|
352
|
+
assert_includes(html, %(<a id="second" class="anchor" href="#second" aria-hidden="true">))
|
353
|
+
assert_includes(html, %(<a id="third" class="anchor" href="#third" aria-hidden="true">))
|
305
354
|
end
|
306
355
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-toc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.0.
|
4
|
+
version: 0.8.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- toshimaru
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-10-
|
12
|
+
date: 2018-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -158,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
158
|
version: 1.3.1
|
159
159
|
requirements: []
|
160
160
|
rubyforge_project:
|
161
|
-
rubygems_version: 2.
|
161
|
+
rubygems_version: 2.7.6
|
162
162
|
signing_key:
|
163
163
|
specification_version: 4
|
164
164
|
summary: Jekyll Table of Contents plugin
|