From c9e562576ef59a93285e0eddbb44533e47860111 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 25 Nov 2017 23:57:32 +0900 Subject: [PATCH] TOC configuration: configurable heading min_level and max_level (#39) * Fix duplicated method name * Add toc_enabled? method * Add kramdown heading test * Create `toc` liqud custom tag * Check toc is enabled * unregister_tag toc * Add TODO * Make toc headings dynamic * Add max_level, min_level test --- lib/jekyll-toc.rb | 32 +++++++++++++++++++++----------- lib/table_of_contents/parser.rb | 16 ++++++++++++++-- test/test_kramdown_list.rb | 24 ++++++++++++++++++++++-- test/test_various_toc_html.rb | 16 ++++++++++++++-- 4 files changed, 71 insertions(+), 17 deletions(-) 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 +

h1

+ +

h2

+ HTML + + assert_equal(expected, Kramdown::Document.new(text).to_html) + end + def test_kramdown_list_1 text = <<-MARKDOWN * level-1 @@ -72,12 +89,15 @@ def test_kramdown_list_3 * level-1 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 + + HTML + + assert_equal(expected, doc.css('ul.section-nav').to_s) + end + def test_complex_nested_toc parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_2) doc = Nokogiri::HTML(parser.toc) @@ -76,7 +88,7 @@ def test_complex_nested_toc assert_equal(expected, doc.css('ul.section-nav').to_s) end - def test_decremental_headings + def test_decremental_headings1 parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_3) doc = Nokogiri::HTML(parser.toc) expected = <<-HTML @@ -94,7 +106,7 @@ def test_decremental_headings end - def test_decremental_headings + def test_decremental_headings2 parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_4) doc = Nokogiri::HTML(parser.toc) expected = <<-HTML