diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index 4a575de..d10714d 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -2,31 +2,41 @@ require 'table_of_contents/parser' module Jekyll + class TocTag < Liquid::Tag + def render(context) + return unless context.registers[:page]['toc'] == true + content_html = context.registers[:page].content + ::Jekyll::TableOfContents::Parser.new(content_html).build_toc + end + end + module TableOfContentsFilter def toc_only(html) - return html unless page['toc'] - - ::Jekyll::TableOfContents::Parser.new(html).build_toc + return html unless toc_enabled? + ::Jekyll::TableOfContents::Parser.new(html, toc_config).build_toc end def inject_anchors(html) - return html unless page['toc'] - - ::Jekyll::TableOfContents::Parser.new(html).inject_anchors_into_html + return html unless toc_enabled? + ::Jekyll::TableOfContents::Parser.new(html, toc_config).inject_anchors_into_html end def toc(html) - return html unless page['toc'] - - ::Jekyll::TableOfContents::Parser.new(html).toc + return html unless toc_enabled? + ::Jekyll::TableOfContents::Parser.new(html, toc_config).toc end private - def page - @context.registers[:page] + def toc_enabled? + @context.registers[:page]['toc'] == true + end + + def toc_config + @context.registers[:site].config["toc"] end end end Liquid::Template.register_filter(Jekyll::TableOfContentsFilter) +# Liquid::Template.register_tag('toc', Jekyll::TocTag) # will be enabled at v1.0 diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 5a0ef94..d5a432d 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -4,8 +4,15 @@ module TableOfContents class Parser PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u - def initialize(html) + DEFAULT_CONFIG = { + "min_level" => 1, + "max_level" => 6, + } + + def initialize(html, options = {}) @doc = Nokogiri::HTML::DocumentFragment.parse(html) + options = DEFAULT_CONFIG.merge(options) + @toc_levels = options["min_level"]..options["max_level"] @entries = parse_content end @@ -33,7 +40,8 @@ def parse_content entries = [] headers = Hash.new(0) - @doc.css('h1, h2, h3, h4, h5, h6').each do |node| + # TODO: Use kramdown auto ids + @doc.css(toc_headings).each do |node| text = node.text id = text.downcase id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation @@ -104,6 +112,10 @@ def get_nest_entries(entries, min_h_num) nest_entries << entry end end + + def toc_headings + @toc_levels.map { |level| "h#{level}" }.join(",") + end end end end diff --git a/test/test_kramdown_list.rb b/test/test_kramdown_list.rb index f86b788..0980a0d 100644 --- a/test/test_kramdown_list.rb +++ b/test/test_kramdown_list.rb @@ -1,6 +1,23 @@ require 'test_helper' class TestKramdownList < Minitest::Test + # NOTE: kramdown automatically injects `id` attribute + # TODO: test Japanese heading + def test_kramdown_heading + text = <<-MARKDOWN +# h1 + +## h2 + MARKDOWN + expected = <<-HTML +
* level-4
+* level-3 * level-2 * level-1
+
HTML
assert_equal(expected, Kramdown::Document.new(text).to_html)
end
- def test_kramdown_list_3
+ def test_kramdown_list_4
text = <<-MARKDOWN
* level-1
* level-4
@@ -101,7 +121,7 @@ def test_kramdown_list_3
assert_equal(expected, Kramdown::Document.new(text).to_html)
end
- def test_kramdown_list_3
+ def test_kramdown_list_5
text = <<-MARKDOWN
* level-1
* level-3
diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb
index 5b8b42d..5af8181 100644
--- a/test/test_various_toc_html.rb
+++ b/test/test_various_toc_html.rb
@@ -53,6 +53,18 @@ def test_nested_toc
assert_equal(expected, doc.css('ul.section-nav').to_s)
end
+ 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
+