jekyll-toc 0.8.0.beta2 → 0.8.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Code Climate](https://codeclimate.com/github/toshimaru/jekyll-toc/badges/gpa.svg)](https://codeclimate.com/github/toshimaru/jekyll-toc)
|
6
6
|
[![Test Coverage](https://api.codeclimate.com/v1/badges/cd56b207f327603662a1/test_coverage)](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
|
![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png)
|
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
|
+
![screenshot](https://user-images.githubusercontent.com/803398/28401455-0ba60868-6d55-11e7-8159-0ae7591aee66.png)
|
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
|