Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1f0be2f
Url-Encoding for element id (spaces and UTF-8 support)
N7K4 Jan 8, 2020
35a1a1b
Save parent element of entry, to add a anchor id
N7K4 Jan 8, 2020
7ed55a2
Replace em-font-icon element with a unicode arrow
N7K4 Jan 8, 2020
c714baf
Format Code
N7K4 Jan 8, 2020
2f054aa
Format Code
N7K4 Jan 8, 2020
b68f210
Add class for the link to top
N7K4 Jan 17, 2020
7931ec2
PR94 - codeclimate fixes
N7K4 Jan 18, 2020
be51dcc
PR94 - codeclimate fixes
N7K4 Jan 18, 2020
9d41988
PR94 - codeclimate fixes
N7K4 Jan 18, 2020
790cc88
PR94 - codeclimate fixes
N7K4 Jan 18, 2020
941f02a
PR94 - codeclimate fixes
N7K4 Jan 18, 2020
56ebcc4
Add Testing Section to readme
N7K4 Jan 18, 2020
b223d13
Fix UnitTest test_toc_tag
N7K4 Jan 18, 2020
5586a92
Fix unit tests, id and anchor
Jan 19, 2020
3599b77
Merge branch 'master' into navigateToTop
N7K4 Jan 28, 2020
92f7c78
Url-Encoding for element id (spaces and UTF-8 support)
N7K4 Jan 8, 2020
9e2d5db
Add config value 'anchor_id_url_encoded', with default value false
N7K4 Feb 29, 2020
acdb182
Wrap the url encoding with the configuration variable
N7K4 Feb 29, 2020
194a3ff
Create Unit Tests
N7K4 Feb 29, 2020
bf32752
Add .whitesource configuration file
mend-bolt-for-github[bot] Apr 28, 2020
2a38db1
Merge pull request #1 from n13org/whitesource/configure
N7K4 Apr 28, 2020
e8cac14
Merge pull request #3 from toshimaru/master
N7K4 Apr 28, 2020
6ff175a
Update Gem Specs to n13.org
N7K4 Apr 28, 2020
68bf26d
Merge pull request #4 from n13org/issue95_Feb2020
N7K4 Apr 28, 2020
75b677a
Merge branch 'master' into navigateToTop
N7K4 Apr 28, 2020
fffe6b2
Delete jekyll_3.7.gemfile
N7K4 Apr 28, 2020
3b65bcb
Delete jekyll_3.8.gemfile
N7K4 Apr 28, 2020
4c62a90
Drop support for jekyll v3.0
N7K4 Apr 28, 2020
a63cfd2
Fix unit test
N7K4 Apr 28, 2020
4d29132
Fix unit test
N7K4 Apr 28, 2020
6684128
Add configuration list_id "toc"
N7K4 Nov 16, 2020
65ba147
Update from master
N7K4 Nov 16, 2020
fa9c46f
Fix rubocop
N7K4 Nov 16, 2020
3fb1a9d
Disable some rubocops rules
N7K4 Nov 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ They are of the form:
This is only useful when the TOC itself should be placed at some other
location with the `toc_only` filter.

## Testing

To run the tests you `rake`. First install gem packages local and run `rake test`.

```shell
rake test
```

## Generated HTML

jekyll-toc generates an unordered list. The HTML output is as follows.
Expand Down
25 changes: 22 additions & 3 deletions lib/table_of_contents/parser.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# frozen_string_literal: true

require 'erb'

# Jekyll Modul, the root of everything
module Jekyll
# Module to wrap the classes for TOC creation
module TableOfContents
# Parse html contents and generate table of contents
class Parser
include ERB::Util

PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u

def initialize(html, options = {})
Expand All @@ -17,13 +23,24 @@ def toc
end

def build_toc
%(<ul class="#{@configuration.list_class}">\n#{build_toc_list(@entries)}</ul>)
%(<ul id="toc" class="#{@configuration.list_class}">\n#{build_toc_list(@entries)}</ul>)
end

def inject_anchors_into_html
@entries.each do |entry|
entry[:header_content].add_previous_sibling(
%(<a class="anchor" href="##{entry[:id]}" aria-hidden="true"><span class="octicon octicon-link"></span></a>)
# Add id to h-element
entry[:header_parent].set_attribute('id', "#{entry[:id]}.to_s")

# Add link icon after text
entry[:header_content].add_next_sibling(
%(<a class="anchor" href="##{entry[:id]}" aria-hidden="true">&nbsp;&#128279;</a>)
)

# Add link 'nav to toc'
arr_to_top = [2, 3]
next unless arr_to_top.include?(entry[:h_num])
entry[:header_content].add_next_sibling(
%(<span style="float: right"><a class="anchor_to_top" href="#toc" aria-hidden="true">&#x21A5;</a></span>)
)
end

Expand All @@ -45,6 +62,7 @@ def parse_content
.downcase
.gsub(PUNCTUATION_REGEXP, '') # remove punctuation
.tr(' ', '-') # replace spaces with dash
id = url_encode(id)

suffix_num = headers[id]
headers[id] += 1
Expand All @@ -53,6 +71,7 @@ def parse_content
id: suffix_num.zero? ? id : "#{id}-#{suffix_num}",
text: CGI.escapeHTML(text),
node_name: node.name,
header_parent: node,
header_content: node.children.first,
h_num: node.name.delete('h').to_i
}
Expand Down
2 changes: 1 addition & 1 deletion test/parser/test_inject_anchors_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def setup
def test_injects_anchors_into_content
html = @parser.inject_anchors_into_html

assert_match(%r{<a class="anchor" href="#simple-h1" aria-hidden="true"><span.*span></a>Simple H1}, html)
assert_match(%r{<a class="anchor" href="#simple-h1" aria-hidden="true">.+</a>}, html)
end

def test_does_not_inject_toc
Expand Down
4 changes: 2 additions & 2 deletions test/parser/test_option_error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class TestOptionError < Minitest::Test
BASE_HTML = '<h1>h1</h1>'
EXPECTED_HTML = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1"><a href="#h1">h1</a></li>
</ul>
HTML
Expand All @@ -30,7 +30,7 @@ def test_option_is_string
expected = EXPECTED_HTML
assert_equal(expected, doc.css('ul.section-nav').to_s)
end

def test_option_is_array
parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, [])
doc = Nokogiri::HTML(parser.toc)
Expand Down
4 changes: 2 additions & 2 deletions test/parser/test_toc_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def setup
def test_injects_anchors
html = @parser.toc

assert_match(%r{<a class="anchor" href="#simple-h1" aria-hidden="true"><span.*span></a>Simple H1}, html)
assert_match(%r{<a class="anchor" href="#simple-h1" aria-hidden="true">.+</a>}, html)
end

def test_nested_toc
Expand All @@ -31,6 +31,6 @@ def test_nested_toc
def test_injects_toc_container
html = @parser.toc

assert_match(/<ul class="section-nav">/, html)
assert_match(/<ul id=\"toc\" class="section-nav">/, html)
end
end
2 changes: 1 addition & 1 deletion test/parser/test_toc_only_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def setup
def test_injects_toc_container
html = @parser.build_toc

assert_match(/<ul class="section-nav">/, html)
assert_match(/<ul id=\"toc\" class="section-nav">/, html)
end

def test_does_not_return_content
Expand Down
48 changes: 24 additions & 24 deletions test/parser/test_various_toc_html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def test_nested_toc
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand All @@ -89,7 +89,7 @@ def test_nested_toc_with_min_and_max
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1, 'min_level' => 2, 'max_level' => 5)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h3"><a href="#h3">h3</a></li>
</ul>
HTML
Expand All @@ -102,7 +102,7 @@ def test_complex_nested_toc
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_2)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand All @@ -126,7 +126,7 @@ def test_decremental_headings1
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_3)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h6"><a href="#h6">h6</a></li>
<li class="toc-entry toc-h5"><a href="#h5">h5</a></li>
<li class="toc-entry toc-h4"><a href="#h4">h4</a></li>
Expand All @@ -144,7 +144,7 @@ def test_decremental_headings2
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_4)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand Down Expand Up @@ -172,7 +172,7 @@ def test_no_toc
parser = Jekyll::TableOfContents::Parser.new(NO_TOC_HTML)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand Down Expand Up @@ -200,7 +200,7 @@ def test_japanese_toc
parser = Jekyll::TableOfContents::Parser.new(JAPANESE_HEADINGS_HTML)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#%E3%81%82">あ</a>
<ul>
Expand All @@ -223,7 +223,7 @@ def test_angle_bracket
parser = Jekyll::TableOfContents::Parser.new(ANGLE_BRACKET_HTML)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1"><a href="#h1">h1</a></li>
<li class="toc-entry toc-h1"><a href="#base-href">&lt;base href&gt;</a></li>
<li class="toc-entry toc-h1"><a href="#--">&amp; &lt; &gt;</a></li>
Expand All @@ -238,7 +238,7 @@ def test_tags_inside_heading
parser = Jekyll::TableOfContents::Parser.new(TAGS_INSIDE_HEADINGS_HTML)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h2"><a href="#h2">h2</a></li>
<li class="toc-entry toc-h2"><a href="#h2-1">h2</a></li>
</ul>
Expand All @@ -261,7 +261,7 @@ def test_nested_toc_with_no_toc_section_class
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand All @@ -279,9 +279,9 @@ def test_nested_toc_with_no_toc_section_class
assert_equal(expected, actual)

html = parser.inject_anchors_into_html
assert_match(%r{<h1>.+</h1>}m, html)
assert_match(%r{<h3>.+</h3>}m, html)
assert_match(%r{<h6>.+</h6>}m, html)
assert_match(%r{<h1 id=".+">.+</h1>}m, html)
assert_match(%r{<h3 id=".+">.+</h3>}m, html)
assert_match(%r{<h6 id=".+">.+</h6>}m, html)
assert_includes(html, '<h2>h2</h2>')
end

Expand All @@ -302,7 +302,7 @@ def test_nested_toc_with_no_toc_section_class_option
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE_2, 'no_toc_section_class' => 'exclude')
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand All @@ -320,9 +320,9 @@ def test_nested_toc_with_no_toc_section_class_option
assert_equal(expected, actual)

html = parser.inject_anchors_into_html
assert_match(%r{<h1>.+</h1>}m, html)
assert_match(%r{<h3>.+</h3>}m, html)
assert_match(%r{<h6>.+</h6>}m, html)
assert_match(%r{<h1 id=".+">.+</h1>}m, html)
assert_match(%r{<h3 id=".+">.+</h3>}m, html)
assert_match(%r{<h6 id=".+">.+</h6>}m, html)
assert_includes(html, '<h2>h2</h2>')
assert_includes(html, '<h4>h4</h4>')
assert_includes(html, '<h5>h5</h5>')
Expand All @@ -345,7 +345,7 @@ def test_multiple_no_toc_section_classes
parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE_3, 'no_toc_section_class' => ['no_toc_section', 'exclude'])
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1">
<a href="#h1">h1</a>
<ul>
Expand All @@ -363,9 +363,9 @@ def test_multiple_no_toc_section_classes
assert_equal(expected, actual)

html = parser.inject_anchors_into_html
assert_match(%r{<h1>.+</h1>}m, html)
assert_match(%r{<h3>.+</h3>}m, html)
assert_match(%r{<h6>.+</h6>}m, html)
assert_match(%r{<h1 id=".+">.+</h1>}m, html)
assert_match(%r{<h3 id=".+">.+</h3>}m, html)
assert_match(%r{<h6 id=".+">.+</h6>}m, html)
assert_includes(html, '<h2>h2</h2>')
assert_includes(html, '<h4>h4</h4>')
assert_includes(html, '<h5>h5</h5>')
Expand All @@ -381,7 +381,7 @@ def test_toc_with_explicit_id
parser = Jekyll::TableOfContents::Parser.new(TEST_EXPLICIT_ID)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1"><a href="#h1">h1</a></li>
<li class="toc-entry toc-h1"><a href="#second">h2</a></li>
<li class="toc-entry toc-h1"><a href="#third">h3</a></li>
Expand All @@ -406,7 +406,7 @@ def test_anchor_is_uniq
parser = Jekyll::TableOfContents::Parser.new(TEST_UNIQ_ID)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="section-nav">
<ul id="toc" class="section-nav">
<li class="toc-entry toc-h1"><a href="#h1">h1</a></li>
<li class="toc-entry toc-h1"><a href="#h1-1">h1</a></li>
<li class="toc-entry toc-h1"><a href="#h1-2">h1</a></li>
Expand All @@ -423,7 +423,7 @@ def test_custom_css_classes
)
doc = Nokogiri::HTML(parser.toc)
expected = <<~HTML
<ul class="custom-list">
<ul id="toc" class="custom-list">
<li class="custom-item custom-prefix-h1">
<a href="#h1">h1</a>
<ul class="custom-sublist">
Expand Down
4 changes: 2 additions & 2 deletions test/test_jekyll-toc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_toc

def test_toc_only2
@context = enable_toc_context
assert_equal "<ul class=\"section-nav\">\n</ul>", toc_only(DUMMY_HTML)
assert_equal "<ul id=\"toc\" class=\"section-nav\">\n</ul>", toc_only(DUMMY_HTML)
end

def test_inject_anchors2
Expand All @@ -34,7 +34,7 @@ def test_inject_anchors2

def test_toc2
@context = enable_toc_context
assert_equal "<ul class=\"section-nav\">\n</ul>#{DUMMY_HTML}", toc(DUMMY_HTML)
assert_equal "<ul id=\"toc\" class=\"section-nav\">\n</ul>#{DUMMY_HTML}", toc(DUMMY_HTML)
end

private
Expand Down
2 changes: 1 addition & 1 deletion test/test_toc_tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_toc_tag
site: @stubbed_context1.new({ 'toc' => nil })
)
tag = Jekyll::TocTag.parse('toc_tag', '', Tokenizer.new(''), ParseContext.new)
assert_equal tag.render(context), "<ul class=\"section-nav\">\n<li class=\"toc-entry toc-h1\"><a href=\"#test\">test</a></li>\n</ul>"
assert_equal tag.render(context), "<ul id=\"toc\" class=\"section-nav\">\n<li class=\"toc-entry toc-h1\"><a href=\"#test\">test</a></li>\n</ul>"
end

def test_toc_tag_returns_empty_string
Expand Down