From bf001ff9affae413d30991c7e738292b03976c48 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 25 Nov 2017 23:57:32 +0900 Subject: [PATCH 001/112] 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 From 057cff1aab0518960e84b59dad4b414e605f4d69 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 25 Nov 2017 23:59:11 +0900 Subject: [PATCH 002/112] v0.5.0.rc --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 07cc5f1..84a40d4 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.4.0'.freeze + VERSION = '0.5.0.rc'.freeze end From 956e6b5cf968edcd3c8c2890ce21372d66c5d8fd Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Thu, 28 Dec 2017 00:39:04 +0900 Subject: [PATCH 003/112] V0.5.0 release: configurable heading min_level and max_level (#40) * README: TOC level customization * Bump to v0.5.0 --- README.md | 39 +++++++++++++++++---------------------- lib/version.rb | 2 +- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index fb4ff3e..c7fa611 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ location with the `toc_only` filter. ## Generated HTML -jekyll-toc generates an unordered list. The final output is as follows. +jekyll-toc generates an unordered list. The HTML output is as follows. ```html
    @@ -104,7 +104,21 @@ It looks like the image below. ![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) -## CSS Styling +## Customization + +### TOC level + +The toc levels can be configured on `_config.yml`. + +```yml +toc: + min_level: 2 # default: 1 + max_level: 5 # default: 6 +``` + +The default level range is `

    ` to `

    `. + +### CSS Styling The toc can be modified with CSS. The sample CSS is the following. @@ -122,25 +136,6 @@ The toc can be modified with CSS. The sample CSS is the following. Each TOC `li` entry has two CSS classes for further styling. The general `toc-entry` is applied to all `li` elements in the `ul.section-nav`. -Depending on the heading level each specific entry refers to, it has a second -CSS class `toc-XX`, where `XX` is the HTML heading tag name. -For example, the TOC entry linking to a heading `

    ...

    ` (a single +Depending on the heading level each specific entry refers to, it has a second CSS class `toc-XX`, where `XX` is the HTML heading tag name. For example, the TOC entry linking to a heading `

    ...

    ` (a single `#` in Markdown) will get the CSS class `toc-h1`. - -That way, one can tune the depth of the TOC displayed on the site. -The following CSS will display only the first two heading levels and hides -all other links: - -```css -.toc-entry.toc-h1, -.toc-entry.toc-h2 -{} -.toc-entry.toc-h3, -.toc-entry.toc-h4, -.toc-entry.toc-h5, -.toc-entry.toc-h6 -{ - display: none; -} -``` diff --git a/lib/version.rb b/lib/version.rb index 84a40d4..94e62f7 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.5.0.rc'.freeze + VERSION = '0.5.0'.freeze end From 5edfdc9d34a1d287b9efbdfd61c09d689eb7d157 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 30 Dec 2017 00:05:35 -0500 Subject: [PATCH 004/112] Fix toc_config being nil --- lib/table_of_contents/parser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index d5a432d..125b8c7 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -11,7 +11,7 @@ class Parser def initialize(html, options = {}) @doc = Nokogiri::HTML::DocumentFragment.parse(html) - options = DEFAULT_CONFIG.merge(options) + options = options.nil? ? DEFAULT_CONFIG.clone : DEFAULT_CONFIG.merge(options) @toc_levels = options["min_level"]..options["max_level"] @entries = parse_content end From bafcf98cc590ce7b7092337bf0f9cd534f23e315 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 30 Dec 2017 15:14:21 +0900 Subject: [PATCH 005/112] v0.5.1 release (#42) * Add Ruby 2.5 support * v0.5.1 * Fix nil toc config error * Fix hash merge TypeError * Revert "Add Ruby 2.5 support" This reverts commit 506abcb7acbe02008adc6851c1582e00d1f59721. * Simplify test --- lib/jekyll-toc.rb | 2 +- lib/table_of_contents/parser.rb | 8 ++++++- lib/version.rb | 2 +- test/test_option_error.rb | 38 +++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 test/test_option_error.rb diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index d10714d..d00dc89 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -33,7 +33,7 @@ def toc_enabled? end def toc_config - @context.registers[:site].config["toc"] + @context.registers[:site].config["toc"] || {} end end end diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 125b8c7..52f74ba 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -11,7 +11,7 @@ class Parser def initialize(html, options = {}) @doc = Nokogiri::HTML::DocumentFragment.parse(html) - options = options.nil? ? DEFAULT_CONFIG.clone : DEFAULT_CONFIG.merge(options) + options = generate_option_hash(options) @toc_levels = options["min_level"]..options["max_level"] @entries = parse_content end @@ -116,6 +116,12 @@ def get_nest_entries(entries, min_h_num) def toc_headings @toc_levels.map { |level| "h#{level}" }.join(",") end + + def generate_option_hash(options) + DEFAULT_CONFIG.merge(options) + rescue TypeError + DEFAULT_CONFIG + end end end end diff --git a/lib/version.rb b/lib/version.rb index 94e62f7..445e0eb 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.5.0'.freeze + VERSION = '0.5.1'.freeze end diff --git a/test/test_option_error.rb b/test/test_option_error.rb new file mode 100644 index 0000000..9f4a7ec --- /dev/null +++ b/test/test_option_error.rb @@ -0,0 +1,38 @@ +require 'test_helper' + +class TestOptionError < Minitest::Test + BASE_HTML = "

    h1

    " + EXPECTED_HTML = <<-HTML + + HTML + + def test_option_is_nil + parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, nil) + doc = Nokogiri::HTML(parser.toc) + expected = EXPECTED_HTML + assert_equal(expected, doc.css('ul.section-nav').to_s) + end + + def test_option_is_epmty_string + parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, "") + doc = Nokogiri::HTML(parser.toc) + expected = EXPECTED_HTML + assert_equal(expected, doc.css('ul.section-nav').to_s) + end + + def test_option_is_string + parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, "string") + doc = Nokogiri::HTML(parser.toc) + 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) + expected = EXPECTED_HTML + assert_equal(expected, doc.css('ul.section-nav').to_s) + end +end From 3972bb255029baa0363541458b879d0f73e90597 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Mon, 5 Feb 2018 12:47:58 +0900 Subject: [PATCH 006/112] :up: Ruby 2.5.0 support --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5d53438..ac98cd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ rvm: - 2.2 - 2.3.4 - 2.4.1 + - 2.5.0 # gemfile is generated by appraisal gemfile: - gemfiles/jekyll_3.6.gemfile From 082fbf40ada8478334391d97f63a47dffbc580d6 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Mon, 5 Feb 2018 13:08:22 +0900 Subject: [PATCH 007/112] Add Jekyll 3.7 --- .travis.yml | 1 + Appraisals | 4 ++++ gemfiles/jekyll_3.1.gemfile | 2 +- gemfiles/jekyll_3.2.gemfile | 2 +- gemfiles/jekyll_3.3.gemfile | 2 +- gemfiles/jekyll_3.4.gemfile | 2 +- gemfiles/jekyll_3.5.gemfile | 2 +- gemfiles/jekyll_3.6.gemfile | 2 +- gemfiles/jekyll_3.7.gemfile | 7 +++++++ 9 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 gemfiles/jekyll_3.7.gemfile diff --git a/.travis.yml b/.travis.yml index ac98cd4..6912eb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ rvm: - 2.5.0 # gemfile is generated by appraisal gemfile: + - gemfiles/jekyll_3.7.gemfile - gemfiles/jekyll_3.6.gemfile - gemfiles/jekyll_3.5.gemfile - gemfiles/jekyll_3.4.gemfile diff --git a/Appraisals b/Appraisals index 17df253..0df4db6 100644 --- a/Appraisals +++ b/Appraisals @@ -1,3 +1,7 @@ +appraise "jekyll-3.7" do + gem "jekyll", "3.7" +end + appraise "jekyll-3.6" do gem "jekyll", "3.6" end diff --git a/gemfiles/jekyll_3.1.gemfile b/gemfiles/jekyll_3.1.gemfile index 6c5ecbf..8078c11 100644 --- a/gemfiles/jekyll_3.1.gemfile +++ b/gemfiles/jekyll_3.1.gemfile @@ -4,4 +4,4 @@ source "https://rubygems.org" gem "jekyll", "3.1" -gemspec :path => "../" +gemspec path: "../" diff --git a/gemfiles/jekyll_3.2.gemfile b/gemfiles/jekyll_3.2.gemfile index b97a7b1..7f84c89 100644 --- a/gemfiles/jekyll_3.2.gemfile +++ b/gemfiles/jekyll_3.2.gemfile @@ -4,4 +4,4 @@ source "https://rubygems.org" gem "jekyll", "3.2" -gemspec :path => "../" +gemspec path: "../" diff --git a/gemfiles/jekyll_3.3.gemfile b/gemfiles/jekyll_3.3.gemfile index b91e601..009cf0e 100644 --- a/gemfiles/jekyll_3.3.gemfile +++ b/gemfiles/jekyll_3.3.gemfile @@ -4,4 +4,4 @@ source "https://rubygems.org" gem "jekyll", "3.3" -gemspec :path => "../" +gemspec path: "../" diff --git a/gemfiles/jekyll_3.4.gemfile b/gemfiles/jekyll_3.4.gemfile index 7871a55..57dfda6 100644 --- a/gemfiles/jekyll_3.4.gemfile +++ b/gemfiles/jekyll_3.4.gemfile @@ -4,4 +4,4 @@ source "https://rubygems.org" gem "jekyll", "3.4" -gemspec :path => "../" +gemspec path: "../" diff --git a/gemfiles/jekyll_3.5.gemfile b/gemfiles/jekyll_3.5.gemfile index 52c5f7c..9105252 100644 --- a/gemfiles/jekyll_3.5.gemfile +++ b/gemfiles/jekyll_3.5.gemfile @@ -4,4 +4,4 @@ source "https://rubygems.org" gem "jekyll", "3.5" -gemspec :path => "../" +gemspec path: "../" diff --git a/gemfiles/jekyll_3.6.gemfile b/gemfiles/jekyll_3.6.gemfile index 635bc90..510edb0 100644 --- a/gemfiles/jekyll_3.6.gemfile +++ b/gemfiles/jekyll_3.6.gemfile @@ -4,4 +4,4 @@ source "https://rubygems.org" gem "jekyll", "3.6" -gemspec :path => "../" +gemspec path: "../" diff --git a/gemfiles/jekyll_3.7.gemfile b/gemfiles/jekyll_3.7.gemfile new file mode 100644 index 0000000..c551ac2 --- /dev/null +++ b/gemfiles/jekyll_3.7.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "jekyll", "3.7" + +gemspec path: "../" From 8ac4ee3676181c0d61f80f292e13d49a3ba04cc7 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Mon, 5 Feb 2018 13:17:38 +0900 Subject: [PATCH 008/112] Drop Ruby 2.1 support because it's eol-ed. ref. https://www.ruby-lang.org/en/news/2017/04/01/support-of-ruby-2-1-has-ended/ --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6912eb1..9d88932 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: ruby cache: bundler rvm: - - 2.1 - 2.2 - 2.3.4 - 2.4.1 From 037003f4407e10b5fc585ad1da87e870188e65d8 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Mon, 5 Feb 2018 13:24:24 +0900 Subject: [PATCH 009/112] Drop Jekyll 3.1 support --- .travis.yml | 1 - Appraisals | 4 ---- gemfiles/jekyll_3.1.gemfile | 7 ------- 3 files changed, 12 deletions(-) delete mode 100644 gemfiles/jekyll_3.1.gemfile diff --git a/.travis.yml b/.travis.yml index 9d88932..94e3016 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,6 @@ gemfile: - gemfiles/jekyll_3.4.gemfile - gemfiles/jekyll_3.3.gemfile - gemfiles/jekyll_3.2.gemfile - - gemfiles/jekyll_3.1.gemfile addons: code_climate: repo_token: 6b81e393ea6ad38560386f650ea2fb0e57a7beb5e20f8c8364fabee30d5bff07 diff --git a/Appraisals b/Appraisals index 0df4db6..0edbdc3 100644 --- a/Appraisals +++ b/Appraisals @@ -21,7 +21,3 @@ end appraise "jekyll-3.2" do gem "jekyll", "3.2" end - -appraise "jekyll-3.1" do - gem "jekyll", "3.1" -end diff --git a/gemfiles/jekyll_3.1.gemfile b/gemfiles/jekyll_3.1.gemfile deleted file mode 100644 index 8078c11..0000000 --- a/gemfiles/jekyll_3.1.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "jekyll", "3.1" - -gemspec path: "../" From 952e560f21f3bbb06f6a56cbeca981718f8a5fb4 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Mon, 5 Feb 2018 13:52:15 +0900 Subject: [PATCH 010/112] Bump version --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 445e0eb..d58d87e 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.5.1'.freeze + VERSION = '0.5.2'.freeze end From 960e7ac57925cb6b98fd462c9d6857279afb5b6c Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 5 May 2018 23:10:21 +0900 Subject: [PATCH 011/112] Add Jekyll 3.8 Support / Drop Jekyll 3.2, 3.3, 3.4 Support (#47) * Add Support for Jekyll 3.8 * Drop support Jekyll 3.2/3.3/3.4 * Modify Appraisals file --- .travis.yml | 4 +--- Appraisals | 16 ++++------------ gemfiles/jekyll_3.3.gemfile | 7 ------- gemfiles/jekyll_3.4.gemfile | 7 ------- .../{jekyll_3.2.gemfile => jekyll_3.8.gemfile} | 2 +- 5 files changed, 6 insertions(+), 30 deletions(-) delete mode 100644 gemfiles/jekyll_3.3.gemfile delete mode 100644 gemfiles/jekyll_3.4.gemfile rename gemfiles/{jekyll_3.2.gemfile => jekyll_3.8.gemfile} (82%) diff --git a/.travis.yml b/.travis.yml index 94e3016..9bde3f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,12 +7,10 @@ rvm: - 2.5.0 # gemfile is generated by appraisal gemfile: + - gemfiles/jekyll_3.8.gemfile - gemfiles/jekyll_3.7.gemfile - gemfiles/jekyll_3.6.gemfile - gemfiles/jekyll_3.5.gemfile - - gemfiles/jekyll_3.4.gemfile - - gemfiles/jekyll_3.3.gemfile - - gemfiles/jekyll_3.2.gemfile addons: code_climate: repo_token: 6b81e393ea6ad38560386f650ea2fb0e57a7beb5e20f8c8364fabee30d5bff07 diff --git a/Appraisals b/Appraisals index 0edbdc3..e8f09ef 100644 --- a/Appraisals +++ b/Appraisals @@ -1,3 +1,7 @@ +appraise "jekyll-3.8" do + gem "jekyll", "3.8" +end + appraise "jekyll-3.7" do gem "jekyll", "3.7" end @@ -9,15 +13,3 @@ end appraise "jekyll-3.5" do gem "jekyll", "3.5" end - -appraise "jekyll-3.4" do - gem "jekyll", "3.4" -end - -appraise "jekyll-3.3" do - gem "jekyll", "3.3" -end - -appraise "jekyll-3.2" do - gem "jekyll", "3.2" -end diff --git a/gemfiles/jekyll_3.3.gemfile b/gemfiles/jekyll_3.3.gemfile deleted file mode 100644 index 009cf0e..0000000 --- a/gemfiles/jekyll_3.3.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "jekyll", "3.3" - -gemspec path: "../" diff --git a/gemfiles/jekyll_3.4.gemfile b/gemfiles/jekyll_3.4.gemfile deleted file mode 100644 index 57dfda6..0000000 --- a/gemfiles/jekyll_3.4.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "jekyll", "3.4" - -gemspec path: "../" diff --git a/gemfiles/jekyll_3.2.gemfile b/gemfiles/jekyll_3.8.gemfile similarity index 82% rename from gemfiles/jekyll_3.2.gemfile rename to gemfiles/jekyll_3.8.gemfile index 7f84c89..32635d8 100644 --- a/gemfiles/jekyll_3.2.gemfile +++ b/gemfiles/jekyll_3.8.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "jekyll", "3.2" +gem "jekyll", "3.8" gemspec path: "../" From 0a8475476defaa08ebd852a80bc935caa3fe7649 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 5 May 2018 23:13:40 +0900 Subject: [PATCH 012/112] required Ruby version >= 2.2 --- jekyll-toc.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index 392bd32..7b1a4fc 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] - spec.required_ruby_version = '>= 2.1.0' + spec.required_ruby_version = '>= 2.2.2' spec.add_runtime_dependency 'nokogiri', '~> 1.6' From abb95a8f5fcafd5579b511fbf07a4d5da86e16c2 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 5 May 2018 23:14:21 +0900 Subject: [PATCH 013/112] gem dependency: nokogiri ~> 1.7, jekyll ~>3.5 --- jekyll-toc.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index 7b1a4fc..6b2fc26 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -17,11 +17,11 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.2.2' - spec.add_runtime_dependency 'nokogiri', '~> 1.6' + spec.add_runtime_dependency 'nokogiri', '~> 1.7' spec.add_development_dependency 'appraisal' spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0' - spec.add_development_dependency 'jekyll', '>= 3.1' + spec.add_development_dependency 'jekyll', '>= 3.5' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'pry' spec.add_development_dependency 'rake' From 92aef5abea7a1619151041c29c0ec6987cf8dbd9 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 5 May 2018 23:22:46 +0900 Subject: [PATCH 014/112] Update Test Coverage Badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7fa611..cb304ad 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Gem Version](https://badge.fury.io/rb/jekyll-toc.svg)](http://badge.fury.io/rb/jekyll-toc) [![Dependency Status](https://gemnasium.com/toshimaru/jekyll-toc.svg)](https://gemnasium.com/toshimaru/jekyll-toc) [![Code Climate](https://codeclimate.com/github/toshimaru/jekyll-toc/badges/gpa.svg)](https://codeclimate.com/github/toshimaru/jekyll-toc) -[![Test Coverage](https://codeclimate.com/github/toshimaru/jekyll-toc/badges/coverage.svg)](https://codeclimate.com/github/toshimaru/jekyll-toc/coverage) +[![Test Coverage](https://api.codeclimate.com/v1/badges/cd56b207f327603662a1/test_coverage)](https://codeclimate.com/github/toshimaru/jekyll-toc/test_coverage) # Installation From a4919a11efd76b15c466b61ab23adeacdcbb9328 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 5 May 2018 23:22:53 +0900 Subject: [PATCH 015/112] v0.6.0 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index d58d87e..4108c4b 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.5.2'.freeze + VERSION = '0.6.0'.freeze end From d8728145c141572fdf9f7c51f16f434d96e0408a Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Tue, 11 Sep 2018 10:50:12 -0400 Subject: [PATCH 016/112] Add support for no_toc Fixes #37 by ignoring heading entries with class "no_toc" (the same class name used by kramdown's TOC feature). --- lib/table_of_contents/parser.rb | 5 ++++- lib/version.rb | 2 +- test/test_helper.rb | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 52f74ba..6f30c21 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -57,6 +57,7 @@ def parse_content uniq: uniq, text: text, node_name: node.name, + no_toc: node.attribute('class')&.value&.include?('no_toc'), content_node: header_content, h_num: node.name.delete('h').to_i } @@ -73,7 +74,9 @@ def build_toc_list(entries, last_ul_used: false) while i < entries.count entry = entries[i] - if entry[:h_num] == min_h_num + if entry[:no_toc] + # Do nothing / skip entry + elsif entry[:h_num] == min_h_num # If the current entry should not be indented in the list, add the entry to the list toc_list << %(
  • #{entry[:text]}) # If the next entry should be indented in the list, generate a sublist diff --git a/lib/version.rb b/lib/version.rb index 4108c4b..fd1c35e 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.6.0'.freeze + VERSION = '0.7.0-dev.1'.freeze end diff --git a/test/test_helper.rb b/test/test_helper.rb index f74df54..6e8fcc0 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -12,6 +12,7 @@

    Simple H4

    Simple H5
    Simple H6
    +

    No-toc H1

    HTML module TestHelpers From 34be08ff8c2dd4575f8c1cb95703d101e383726d Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Tue, 11 Sep 2018 11:00:54 -0400 Subject: [PATCH 017/112] Ensure this feature runs on Ruby 2.2 as well --- lib/table_of_contents/parser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 6f30c21..df5c4d9 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -57,7 +57,7 @@ def parse_content uniq: uniq, text: text, node_name: node.name, - no_toc: node.attribute('class')&.value&.include?('no_toc'), + no_toc: node.attribute('class') && node.attribute('class').value.include?('no_toc'), content_node: header_content, h_num: node.name.delete('h').to_i } From 5ccbb13eb3ad2474531ea7aa9cb1120b270401e1 Mon Sep 17 00:00:00 2001 From: Jeff Fredrickson Date: Wed, 19 Sep 2018 15:31:37 -0400 Subject: [PATCH 018/112] add support for custom CSS classes --- lib/table_of_contents/parser.rb | 18 ++++++++++++++---- test/test_various_toc_html.rb | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 52f74ba..2cc8752 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -7,17 +7,25 @@ class Parser DEFAULT_CONFIG = { "min_level" => 1, "max_level" => 6, + "list_class" => "section-nav", + "sublist_class" => "", + "item_class" => "toc-entry", + "item_prefix" => "toc-" } def initialize(html, options = {}) @doc = Nokogiri::HTML::DocumentFragment.parse(html) options = generate_option_hash(options) @toc_levels = options["min_level"]..options["max_level"] + @list_class = options["list_class"] + @sublist_class = options["sublist_class"] + @item_class = options["item_class"] + @item_prefix = options["item_prefix"] @entries = parse_content end def build_toc - %(
      \n#{build_toc_list(@entries, last_ul_used: true)}
    ) + %(
      \n#{build_toc_list(@entries, last_ul_used: true)}
    ) end def inject_anchors_into_html @@ -75,13 +83,14 @@ def build_toc_list(entries, last_ul_used: false) entry = entries[i] if entry[:h_num] == min_h_num # If the current entry should not be indented in the list, add the entry to the list - toc_list << %(
  • #{entry[:text]}) + toc_list << %(
  • #{entry[:text]}) # If the next entry should be indented in the list, generate a sublist if i + 1 < entries.count next_entry = entries[i + 1] if next_entry[:h_num] > min_h_num nest_entries = get_nest_entries(entries[i + 1, entries.count], min_h_num) - toc_list << %(\n
      \n#{build_toc_list(nest_entries, last_ul_used: true)}
    \n) + ul_attributes = @sublist_class.empty? ? "" : %( class="#{@sublist_class}") + toc_list << %(\n\n#{build_toc_list(nest_entries, last_ul_used: true)}
\n) i += nest_entries.count end end @@ -93,7 +102,8 @@ def build_toc_list(entries, last_ul_used: false) if last_ul_used toc_list << build_toc_list(nest_entries, last_ul_used: true) else - toc_list << %(
    \n#{build_toc_list(nest_entries, last_ul_used: true)}
\n) + ul_attributes = @sublist_class.empty? ? "" : %( class="#{@sublist_class}") + toc_list << %(\n#{build_toc_list(nest_entries, last_ul_used: true)}\n) end i += nest_entries.count - 1 end diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index 5af8181..a3f31e5 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -133,4 +133,26 @@ def test_decremental_headings2 assert_equal(expected, doc.css('ul.section-nav').to_s) end + + def test_custom_css_classes + parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1, { "item_class" => "custom-item", "list_class" => "custom-list", "sublist_class" => "custom-sublist", "item_prefix" => "custom-prefix-" }) + doc = Nokogiri::HTML(parser.toc) + expected = <<-HTML +
    +
  • +h1 + +
  • +
+ HTML + + assert_equal(expected, doc.css('ul.custom-list').to_s) + end end From 48ada104e4e822195535b4992d703bc83846a331 Mon Sep 17 00:00:00 2001 From: Jeff Fredrickson Date: Wed, 19 Sep 2018 15:35:04 -0400 Subject: [PATCH 019/112] add documentation for custom CSS classes --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index cb304ad..e0c1bee 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,20 @@ toc: max_level: 5 # default: 6 ``` +You can apply custom CSS classes to the generated `
    ` and `
  • ` tags. + +```yml +toc: + # Default is "section-nav": + list_class: my-list-class + # Default is no class for sublists: + sublist_class: my-sublist-class + # Default is "toc-entry": + item_class: my-item-class + # Default is "toc-": + item_prefix: item- +``` + The default level range is `

    ` to `

    `. ### CSS Styling From f64a833112d53415829fbfb4b3a68848c449ce32 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Fri, 21 Sep 2018 01:00:55 +0900 Subject: [PATCH 020/112] v0.7.0-alpha1 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index fd1c35e..0945d61 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.7.0-dev.1'.freeze + VERSION = '0.7.0-alpha1'.freeze end From ff84612518167a8e0403ae5f98fa7f7cf1a2d78b Mon Sep 17 00:00:00 2001 From: toshimaru Date: Fri, 21 Sep 2018 01:01:06 +0900 Subject: [PATCH 021/112] Remove gemnasium badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cb304ad..bc8515a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Build Status](https://travis-ci.org/toshimaru/jekyll-toc.svg?branch=master)](https://travis-ci.org/toshimaru/jekyll-toc) [![Gem Version](https://badge.fury.io/rb/jekyll-toc.svg)](http://badge.fury.io/rb/jekyll-toc) -[![Dependency Status](https://gemnasium.com/toshimaru/jekyll-toc.svg)](https://gemnasium.com/toshimaru/jekyll-toc) [![Code Climate](https://codeclimate.com/github/toshimaru/jekyll-toc/badges/gpa.svg)](https://codeclimate.com/github/toshimaru/jekyll-toc) [![Test Coverage](https://api.codeclimate.com/v1/badges/cd56b207f327603662a1/test_coverage)](https://codeclimate.com/github/toshimaru/jekyll-toc/test_coverage) From 5069000b607e6089357351103abc18988b79c820 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Fri, 21 Sep 2018 01:02:44 +0900 Subject: [PATCH 022/112] Update Ruby patch version --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9bde3f3..0bfc15d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,9 @@ language: ruby cache: bundler rvm: - 2.2 - - 2.3.4 - - 2.4.1 - - 2.5.0 + - 2.3.7 + - 2.4.4 + - 2.5.1 # gemfile is generated by appraisal gemfile: - gemfiles/jekyll_3.8.gemfile From ba869a258e4970c6061baa2bb2a1737847041b43 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Fri, 21 Sep 2018 01:15:53 +0900 Subject: [PATCH 023/112] jekyll-toc requires jekyll > 3.5 --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index bc8515a..75051f7 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,6 @@ plugins: - jekyll-toc ``` -**NOTE: If you're using older Jekyll version(v3.4 or earlier), use `gems` instead of `plugins`.** - Set `toc: true` in posts for which you want the TOC to appear. ```yml From 400bf2c939a7fe45fded5cb1a9ace9c814403e4f Mon Sep 17 00:00:00 2001 From: Jeff Fredrickson Date: Thu, 20 Sep 2018 12:18:39 -0400 Subject: [PATCH 024/112] only need to define ul_attributes once --- lib/table_of_contents/parser.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 0be01a3..a49aeb7 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -82,6 +82,7 @@ def build_toc_list(entries, last_ul_used: false) while i < entries.count entry = entries[i] + ul_attributes = @sublist_class.empty? ? "" : %( class="#{@sublist_class}") if entry[:no_toc] # Do nothing / skip entry elsif entry[:h_num] == min_h_num @@ -92,7 +93,6 @@ def build_toc_list(entries, last_ul_used: false) next_entry = entries[i + 1] if next_entry[:h_num] > min_h_num nest_entries = get_nest_entries(entries[i + 1, entries.count], min_h_num) - ul_attributes = @sublist_class.empty? ? "" : %( class="#{@sublist_class}") toc_list << %(\n\n#{build_toc_list(nest_entries, last_ul_used: true)}
\n) i += nest_entries.count end @@ -105,7 +105,6 @@ def build_toc_list(entries, last_ul_used: false) if last_ul_used toc_list << build_toc_list(nest_entries, last_ul_used: true) else - ul_attributes = @sublist_class.empty? ? "" : %( class="#{@sublist_class}") toc_list << %(\n#{build_toc_list(nest_entries, last_ul_used: true)}\n) end i += nest_entries.count - 1 From 5ee6988d89da2e08722ac508db9121e881cd45ab Mon Sep 17 00:00:00 2001 From: toshimaru Date: Fri, 21 Sep 2018 02:15:50 +0900 Subject: [PATCH 025/112] v0.7.0.alpha1 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 0945d61..71b2590 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.7.0-alpha1'.freeze + VERSION = '0.7.0.alpha1'.freeze end From d5b5d65b7db9b669261341d58f3ab6c0036ea539 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:11:38 +0900 Subject: [PATCH 026/112] Move no_toc test --- test/test_helper.rb | 1 - test/test_various_toc_html.rb | 55 +++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 6e8fcc0..f74df54 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -12,7 +12,6 @@

Simple H4

Simple H5
Simple H6
-

No-toc H1

HTML module TestHelpers diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index 5af8181..f8ed7ca 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -31,6 +31,17 @@ class TestVariousTocHtml < Minitest::Test
h5
HTML + NO_TOC_HTML = <<-HTML +

h1

+

h2

+

h2

+

h3

+

h3

+

h4

+

h4

+

No-toc H1

+ HTML + def test_nested_toc parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1) doc = Nokogiri::HTML(parser.toc) @@ -49,8 +60,9 @@ def test_nested_toc HTML + actual = doc.css('ul.section-nav').to_s - assert_equal(expected, doc.css('ul.section-nav').to_s) + assert_equal(expected, actual) end def test_nested_toc_with_min_and_max @@ -61,8 +73,9 @@ def test_nested_toc_with_min_and_max
  • h3
  • HTML + actual = doc.css('ul.section-nav').to_s - assert_equal(expected, doc.css('ul.section-nav').to_s) + assert_equal(expected, actual) end def test_complex_nested_toc @@ -84,8 +97,9 @@ def test_complex_nested_toc HTML + actual = doc.css('ul.section-nav').to_s - assert_equal(expected, doc.css('ul.section-nav').to_s) + assert_equal(expected, actual) end def test_decremental_headings1 @@ -101,11 +115,11 @@ def test_decremental_headings1
  • h1
  • HTML + actual = doc.css('ul.section-nav').to_s - assert_equal(expected, doc.css('ul.section-nav').to_s) + assert_equal(expected, actual) end - def test_decremental_headings2 parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_4) doc = Nokogiri::HTML(parser.toc) @@ -133,4 +147,35 @@ def test_decremental_headings2 assert_equal(expected, doc.css('ul.section-nav').to_s) end + + def test_no_toc + parser = Jekyll::TableOfContents::Parser.new(NO_TOC_HTML) + doc = Nokogiri::HTML(parser.toc) + expected = <<-HTML + + HTML + actual = doc.css('ul.section-nav').to_s + + assert_equal(expected, actual) + end end From 7716627f0260b802149c31829a1c406481092843 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:34:27 +0900 Subject: [PATCH 027/112] Use tr! instead of gsub! / Use frozen Hash --- lib/table_of_contents/parser.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index df5c4d9..1419aab 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -5,14 +5,14 @@ class Parser PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u DEFAULT_CONFIG = { - "min_level" => 1, - "max_level" => 6, - } + 'min_level' => 1, + 'max_level' => 6 + }.freeze def initialize(html, options = {}) @doc = Nokogiri::HTML::DocumentFragment.parse(html) options = generate_option_hash(options) - @toc_levels = options["min_level"]..options["max_level"] + @toc_levels = options['min_level']..options['max_level'] @entries = parse_content end @@ -45,7 +45,7 @@ def parse_content text = node.text id = text.downcase id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation - id.gsub!(' ', '-') # replace spaces with dash + id.tr!(' ', '-') # replace spaces with dash uniq = headers[id] > 0 ? "-#{headers[id]}" : '' headers[id] += 1 From 43e5cad0f42ef382e9ca6f3a220af5c46962f912 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:34:39 +0900 Subject: [PATCH 028/112] Better no_toc logic --- lib/table_of_contents/parser.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 1419aab..8578245 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -41,7 +41,7 @@ def parse_content headers = Hash.new(0) # TODO: Use kramdown auto ids - @doc.css(toc_headings).each do |node| + @doc.css(toc_headings).reject { |n| n.classes.include?('no_toc') }.each do |node| text = node.text id = text.downcase id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation @@ -57,7 +57,6 @@ def parse_content uniq: uniq, text: text, node_name: node.name, - no_toc: node.attribute('class') && node.attribute('class').value.include?('no_toc'), content_node: header_content, h_num: node.name.delete('h').to_i } @@ -74,9 +73,7 @@ def build_toc_list(entries, last_ul_used: false) while i < entries.count entry = entries[i] - if entry[:no_toc] - # Do nothing / skip entry - elsif entry[:h_num] == min_h_num + if entry[:h_num] == min_h_num # If the current entry should not be indented in the list, add the entry to the list toc_list << %(
  • #{entry[:text]}) # If the next entry should be indented in the list, generate a sublist From 216bda8a87dd48fcdbcab4a2b6f97b1306e4355a Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:43:25 +0900 Subject: [PATCH 029/112] Test for new no_toc logic --- test/test_various_toc_html.rb | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index f8ed7ca..3c1c1d1 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class TestVariousTocHtml < Minitest::Test @@ -33,13 +35,13 @@ class TestVariousTocHtml < Minitest::Test NO_TOC_HTML = <<-HTML

    h1

    +

    no_toc h1

    h2

    -

    h2

    +

    no_toc h2

    h3

    -

    h3

    -

    h4

    +

    no_toc h3

    h4

    -

    No-toc H1

    +

    no_toc h4

    HTML def test_nested_toc @@ -156,16 +158,13 @@ def test_no_toc
  • h1
      -
    • h2
    • -h2 +h2 From 8eb300ca9063b508e18fcd423960fb8c1872e2ad Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:43:34 +0900 Subject: [PATCH 030/112] Add frozen_string_literal magic comment --- lib/jekyll-toc.rb | 2 ++ lib/table_of_contents/parser.rb | 4 +++- test/test_helper.rb | 2 ++ test/test_inject_anchors_filter.rb | 2 ++ test/test_kramdown_list.rb | 2 ++ test/test_option_error.rb | 2 ++ test/test_toc_filter.rb | 2 ++ test/test_toc_only_filter.rb | 2 ++ 8 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index d00dc89..a022e7e 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'nokogiri' require 'table_of_contents/parser' diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 8578245..a54b955 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Jekyll module TableOfContents # Parse html contents and generate table of contents @@ -68,7 +70,7 @@ def parse_content # Returns the list items for entries def build_toc_list(entries, last_ul_used: false) i = 0 - toc_list = '' + toc_list = +'' min_h_num = entries.map { |e| e[:h_num] }.min while i < entries.count diff --git a/test/test_helper.rb b/test/test_helper.rb index f74df54..f1e5781 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'simplecov' SimpleCov.start diff --git a/test/test_inject_anchors_filter.rb b/test/test_inject_anchors_filter.rb index 3b0ab2a..3c7a95f 100644 --- a/test/test_inject_anchors_filter.rb +++ b/test/test_inject_anchors_filter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class TestInjectAnchorsFilter < Minitest::Test diff --git a/test/test_kramdown_list.rb b/test/test_kramdown_list.rb index 0980a0d..7df81fa 100644 --- a/test/test_kramdown_list.rb +++ b/test/test_kramdown_list.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class TestKramdownList < Minitest::Test diff --git a/test/test_option_error.rb b/test/test_option_error.rb index 9f4a7ec..c91dc9f 100644 --- a/test/test_option_error.rb +++ b/test/test_option_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class TestOptionError < Minitest::Test diff --git a/test/test_toc_filter.rb b/test/test_toc_filter.rb index 11a3ec9..874a9d7 100644 --- a/test/test_toc_filter.rb +++ b/test/test_toc_filter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class TestTOCFilter < Minitest::Test diff --git a/test/test_toc_only_filter.rb b/test/test_toc_only_filter.rb index d9f9c8b..cc0b9eb 100644 --- a/test/test_toc_only_filter.rb +++ b/test/test_toc_only_filter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class TestTOCOnlyFilter < Minitest::Test From 30626f67325ef2aac1c98ef87ec1cd5d05dc64e3 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:53:19 +0900 Subject: [PATCH 031/112] Add Skip TOC customization in README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 75051f7..9116fa4 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,16 @@ It looks like the image below. ## Customization +### Skip TOC(`no_toc`) + +The heding is ignored in the toc when you add `no_toc` to the class. + +```html +

      h1

      +

      This heding is ignored in the toc

      +

      h2

      +``` + ### TOC level The toc levels can be configured on `_config.yml`. From f04347e7a2ff968717a47aeff441d80a6084f92d Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 15:55:42 +0900 Subject: [PATCH 032/112] Use dup --- lib/jekyll-toc.rb | 2 +- lib/table_of_contents/parser.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index a022e7e..439b027 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -35,7 +35,7 @@ def toc_enabled? end def toc_config - @context.registers[:site].config["toc"] || {} + @context.registers[:site].config['toc'] || {} end end end diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index a54b955..8857e3c 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -70,7 +70,7 @@ def parse_content # Returns the list items for entries def build_toc_list(entries, last_ul_used: false) i = 0 - toc_list = +'' + toc_list = ''.dup min_h_num = entries.map { |e| e[:h_num] }.min while i < entries.count From 80bab14a4303de9d61a3740b240e3bc660259b57 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 16:08:53 +0900 Subject: [PATCH 033/112] v0.7.0.beta1 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 71b2590..287676f 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.7.0.alpha1'.freeze + VERSION = '0.7.0.beta1'.freeze end From c07976a83a9e8cc84f115e2b62f823252330adfa Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 23:15:25 +0900 Subject: [PATCH 034/112] Add Table of Contents to README --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9116fa4..78b6930 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,16 @@ [![Code Climate](https://codeclimate.com/github/toshimaru/jekyll-toc/badges/gpa.svg)](https://codeclimate.com/github/toshimaru/jekyll-toc) [![Test Coverage](https://api.codeclimate.com/v1/badges/cd56b207f327603662a1/test_coverage)](https://codeclimate.com/github/toshimaru/jekyll-toc/test_coverage) +# Table of Contents + +- [Installation](#installation) +- [Usage](#usage) +- [Generated HTML](#generated-html) +- [Customization](#customization) + - [Skip TOC](#skip-toc) + - [TOC levels](#toc-levels) + - [CSS Styling](#css-styling) + # Installation Add jekyll-toc plugin in your site's `Gemfile`, and run `bundle install`. @@ -73,6 +83,8 @@ location with the `toc_only` filter. ## Generated HTML +![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) + jekyll-toc generates an unordered list. The HTML output is as follows. ```html @@ -97,13 +109,9 @@ jekyll-toc generates an unordered list. The HTML output is as follows.
    ``` -It looks like the image below. - -![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) - ## Customization -### Skip TOC(`no_toc`) +### Skip TOC The heding is ignored in the toc when you add `no_toc` to the class. @@ -113,7 +121,7 @@ The heding is ignored in the toc when you add `no_toc` to the class.

    h2

    ``` -### TOC level +### TOC levels The toc levels can be configured on `_config.yml`. From b98b8f279f6e3d49e35d6581e952ee839947bb31 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 23:27:21 +0900 Subject: [PATCH 035/112] Refactoring / Add Japanese heading test --- test/test_kramdown_list.rb | 49 +++++++++++++++++++++++++++----------- test/test_option_error.rb | 6 ++--- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/test/test_kramdown_list.rb b/test/test_kramdown_list.rb index 7df81fa..6c42a82 100644 --- a/test/test_kramdown_list.rb +++ b/test/test_kramdown_list.rb @@ -4,7 +4,6 @@ class TestKramdownList < Minitest::Test # NOTE: kramdown automatically injects `id` attribute - # TODO: test Japanese heading def test_kramdown_heading text = <<-MARKDOWN # h1 @@ -14,10 +13,27 @@ def test_kramdown_heading expected = <<-HTML

    h1

    -

    h2

    +

    h2

    HTML + actual = Kramdown::Document.new(text).to_html - assert_equal(expected, Kramdown::Document.new(text).to_html) + assert_equal(expected, actual) + end + + def test_kramdown_heading + text = <<-MARKDOWN +# 日本語見出し1 + +## 日本語見出し2 + MARKDOWN + expected = <<-HTML +

    日本語見出し1

    + +

    日本語見出し2

    + HTML + actual = Kramdown::Document.new(text).to_html + + assert_equal(expected, actual) end def test_kramdown_list_1 @@ -49,8 +65,9 @@ def test_kramdown_list_1
  • HTML + actual = Kramdown::Document.new(text).to_html - assert_equal(expected, Kramdown::Document.new(text).to_html) + assert_equal(expected, actual) end def test_kramdown_list_2 @@ -79,8 +96,9 @@ def test_kramdown_list_2 HTML + actual = Kramdown::Document.new(text).to_html - assert_equal(expected, Kramdown::Document.new(text).to_html) + assert_equal(expected, actual) end def test_kramdown_list_3 @@ -95,8 +113,9 @@ def test_kramdown_list_3 * level-3 * level-2 * level-1 HTML + actual = Kramdown::Document.new(text).to_html - assert_equal(expected, Kramdown::Document.new(text).to_html) + assert_equal(expected, actual) end def test_kramdown_list_4 @@ -119,18 +138,19 @@ def test_kramdown_list_4
  • level-1
  • HTML + actual = Kramdown::Document.new(text).to_html - assert_equal(expected, Kramdown::Document.new(text).to_html) + assert_equal(expected, actual) end - def test_kramdown_list_5 - text = <<-MARKDOWN + def test_kramdown_list_5 + text = <<-MARKDOWN * level-1 * level-3 * level-2 * level-1 - MARKDOWN - expected = <<-HTML + MARKDOWN + expected = <<-HTML
    • level-1
        @@ -140,8 +160,9 @@ def test_kramdown_list_5
      • level-1
      - HTML + HTML + actual = Kramdown::Document.new(text).to_html - assert_equal(expected, Kramdown::Document.new(text).to_html) - end + assert_equal(expected, actual) + end end diff --git a/test/test_option_error.rb b/test/test_option_error.rb index c91dc9f..8de4ee8 100644 --- a/test/test_option_error.rb +++ b/test/test_option_error.rb @@ -3,7 +3,7 @@ require 'test_helper' class TestOptionError < Minitest::Test - BASE_HTML = "

      h1

      " + BASE_HTML = '

      h1

      ' EXPECTED_HTML = <<-HTML
      • h1
      • @@ -18,14 +18,14 @@ def test_option_is_nil end def test_option_is_epmty_string - parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, "") + parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, '') doc = Nokogiri::HTML(parser.toc) expected = EXPECTED_HTML assert_equal(expected, doc.css('ul.section-nav').to_s) end def test_option_is_string - parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, "string") + parser = Jekyll::TableOfContents::Parser.new(BASE_HTML, 'string') doc = Nokogiri::HTML(parser.toc) expected = EXPECTED_HTML assert_equal(expected, doc.css('ul.section-nav').to_s) From 035cd0dafbe0b4b8ebf1197caf7b37e0c572df1e Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 23:27:56 +0900 Subject: [PATCH 036/112] v0.7.0 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 287676f..8c3dc03 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,3 +1,3 @@ module JekyllToc - VERSION = '0.7.0.beta1'.freeze + VERSION = '0.7.0'.freeze end From debb2ef7a84de64539250e1c1a522561d09b8ab5 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 23:32:06 +0900 Subject: [PATCH 037/112] More Japanese heading test --- test/test_various_toc_html.rb | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index 3c1c1d1..44fe7fc 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -44,6 +44,12 @@ class TestVariousTocHtml < Minitest::Test

        no_toc h4

        HTML + TEST_JAPANESE_HTML = <<-HTML +

        +

        +

        + HTML + def test_nested_toc parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1) doc = Nokogiri::HTML(parser.toc) @@ -177,4 +183,27 @@ def test_no_toc assert_equal(expected, actual) end + + def test_japanese_toc + parser = Jekyll::TableOfContents::Parser.new(TEST_JAPANESE_HTML) + doc = Nokogiri::HTML(parser.toc) + expected = <<-HTML + + HTML + actual = doc.css('ul.section-nav').to_s + + assert_equal(expected, actual) + end end From 52bad15748e09825c4fd4a3010649f25d445c0d6 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 29 Sep 2018 23:56:10 +0900 Subject: [PATCH 038/112] Remove unnecessary param `last_ul_used` --- lib/table_of_contents/parser.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 8857e3c..b032abb 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -19,7 +19,7 @@ def initialize(html, options = {}) end def build_toc - %(
          \n#{build_toc_list(@entries, last_ul_used: true)}
        ) + %(
          \n#{build_toc_list(@entries)}
        ) end def inject_anchors_into_html @@ -68,7 +68,7 @@ def parse_content end # Returns the list items for entries - def build_toc_list(entries, last_ul_used: false) + def build_toc_list(entries) i = 0 toc_list = ''.dup min_h_num = entries.map { |e| e[:h_num] }.min @@ -83,7 +83,7 @@ def build_toc_list(entries, last_ul_used: false) next_entry = entries[i + 1] if next_entry[:h_num] > min_h_num nest_entries = get_nest_entries(entries[i + 1, entries.count], min_h_num) - toc_list << %(\n
          \n#{build_toc_list(nest_entries, last_ul_used: true)}
        \n) + toc_list << %(\n
          \n#{build_toc_list(nest_entries)}
        \n) i += nest_entries.count end end @@ -92,11 +92,7 @@ def build_toc_list(entries, last_ul_used: false) elsif entry[:h_num] > min_h_num # If the current entry should be indented in the list, generate a sublist nest_entries = get_nest_entries(entries[i, entries.count], min_h_num) - if last_ul_used - toc_list << build_toc_list(nest_entries, last_ul_used: true) - else - toc_list << %(
          \n#{build_toc_list(nest_entries, last_ul_used: true)}
        \n) - end + toc_list << build_toc_list(nest_entries) i += nest_entries.count - 1 end i += 1 @@ -116,7 +112,7 @@ def get_nest_entries(entries, min_h_num) end def toc_headings - @toc_levels.map { |level| "h#{level}" }.join(",") + @toc_levels.map { |level| "h#{level}" }.join(',') end def generate_option_hash(options) From 31b0b7a687d9c899be82f60fe26f2c711ac86730 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sun, 30 Sep 2018 00:01:24 +0900 Subject: [PATCH 039/112] Fix typo --- test/test_kramdown_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_kramdown_list.rb b/test/test_kramdown_list.rb index 6c42a82..7196703 100644 --- a/test/test_kramdown_list.rb +++ b/test/test_kramdown_list.rb @@ -20,7 +20,7 @@ def test_kramdown_heading assert_equal(expected, actual) end - def test_kramdown_heading + def test_japanese_heading text = <<-MARKDOWN # 日本語見出し1 From 18fe1c9c02c1729ade48d33119866c362ded6e6f Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sun, 30 Sep 2018 01:32:48 +0900 Subject: [PATCH 040/112] Add CGI.escapeHTML --- lib/table_of_contents/parser.rb | 2 +- test/test_various_toc_html.rb | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index b032abb..0eb5be8 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -57,7 +57,7 @@ def parse_content entries << { id: id, uniq: uniq, - text: text, + text: CGI.escapeHTML(text), node_name: node.name, content_node: header_content, h_num: node.name.delete('h').to_i diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index 44fe7fc..aad9b9d 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -3,6 +3,12 @@ require 'test_helper' class TestVariousTocHtml < Minitest::Test + # https://github.com/toshimaru/jekyll-toc/issues/45 + ANGLE_BRACKT_HTML = <<-HTML +

        h1

        +

        <base href>

        + HTML + TEST_HTML_1 = <<-HTML

        h1

        h3

        @@ -206,4 +212,18 @@ def test_japanese_toc assert_equal(expected, actual) end + + def test_angle_bracket + parser = Jekyll::TableOfContents::Parser.new(ANGLE_BRACKT_HTML) + doc = Nokogiri::HTML(parser.toc) + expected = <<-HTML + + HTML + actual = doc.css('ul.section-nav').to_s + + assert_equal(expected, actual) + end end From c755235d1819694a3e6ac0ee468100549f029e49 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sun, 30 Sep 2018 14:58:32 +0900 Subject: [PATCH 041/112] escapeHTML test --- test/test_various_toc_html.rb | 38 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index aad9b9d..3a52eda 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -3,10 +3,28 @@ require 'test_helper' class TestVariousTocHtml < Minitest::Test - # https://github.com/toshimaru/jekyll-toc/issues/45 + # ref. https://github.com/toshimaru/jekyll-toc/issues/45 ANGLE_BRACKT_HTML = <<-HTML

        h1

        <base href>

        +

        & < >

        + HTML + + NO_TOC_HTML = <<-HTML +

        h1

        +

        no_toc h1

        +

        h2

        +

        no_toc h2

        +

        h3

        +

        no_toc h3

        +

        h4

        +

        no_toc h4

        + HTML + + TEST_JAPANESE_HTML = <<-HTML +

        +

        +

        HTML TEST_HTML_1 = <<-HTML @@ -39,23 +57,6 @@ class TestVariousTocHtml < Minitest::Test
        h5
        HTML - NO_TOC_HTML = <<-HTML -

        h1

        -

        no_toc h1

        -

        h2

        -

        no_toc h2

        -

        h3

        -

        no_toc h3

        -

        h4

        -

        no_toc h4

        - HTML - - TEST_JAPANESE_HTML = <<-HTML -

        -

        -

        - HTML - def test_nested_toc parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1) doc = Nokogiri::HTML(parser.toc) @@ -220,6 +221,7 @@ def test_angle_bracket HTML actual = doc.css('ul.section-nav').to_s From 05de7924a0ed7c9e64bc38b4839f2f3fcc21e0b4 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sun, 30 Sep 2018 15:05:47 +0900 Subject: [PATCH 042/112] Add test_tags_inside_heading --- test/test_various_toc_html.rb | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index 3a52eda..5deeb7d 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -4,7 +4,7 @@ class TestVariousTocHtml < Minitest::Test # ref. https://github.com/toshimaru/jekyll-toc/issues/45 - ANGLE_BRACKT_HTML = <<-HTML + ANGLE_BRACKET_HTML = <<-HTML

        h1

        <base href>

        & < >

        @@ -21,12 +21,17 @@ class TestVariousTocHtml < Minitest::Test

        no_toc h4

        HTML - TEST_JAPANESE_HTML = <<-HTML + JAPANESE_HEADINGS_HTML = <<-HTML

        HTML + TAGS_INSIDE_HEADINGS_HTML = <<-HTML +

        h2

        +

        h2

        + HTML + TEST_HTML_1 = <<-HTML

        h1

        h3

        @@ -192,7 +197,7 @@ def test_no_toc end def test_japanese_toc - parser = Jekyll::TableOfContents::Parser.new(TEST_JAPANESE_HTML) + parser = Jekyll::TableOfContents::Parser.new(JAPANESE_HEADINGS_HTML) doc = Nokogiri::HTML(parser.toc) expected = <<-HTML \n) + i += nest_entries.count end # Add the closing tag for the current entry in the list toc_list << %(\n) @@ -136,6 +135,10 @@ def generate_option_hash(options) rescue TypeError DEFAULT_CONFIG end + + def ul_attributes + @ul_attributes ||= @sublist_class.empty? ? '' : %( class="#{@sublist_class}") + end end end end From 94f735920fad6c763b3d721c2dbccf0bdd9b642f Mon Sep 17 00:00:00 2001 From: toshimaru Date: Mon, 29 Oct 2018 13:19:39 +0900 Subject: [PATCH 060/112] v0.9.0 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index a9ee8cf..8379a95 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.9.0.beta2' + VERSION = '0.9.0' end From 42fdd64ca196a2723fdc50aef2a300e36e1caa55 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Thu, 1 Nov 2018 15:51:24 +0900 Subject: [PATCH 061/112] Use cc-test-reporter instead of codeclimate-test-reporter (#68) * Use cc-test-reporter instead of codeclimate-test-reporter * :gem: simplecov * codeclimate test --- .travis.yml | 12 +++++++++--- jekyll-toc.gemspec | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e8b66a..e7085e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,8 @@ language: ruby cache: bundler +env: + global: + - CC_TEST_REPORTER_ID=6b81e393ea6ad38560386f650ea2fb0e57a7beb5e20f8c8364fabee30d5bff07 rvm: - 2.3.7 - 2.4.4 @@ -10,8 +13,11 @@ gemfile: - gemfiles/jekyll_3.7.gemfile - gemfiles/jekyll_3.6.gemfile - gemfiles/jekyll_3.5.gemfile -addons: - code_climate: - repo_token: 6b81e393ea6ad38560386f650ea2fb0e57a7beb5e20f8c8364fabee30d5bff07 +before_script: + # Download cc-test-reporter + - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter + - chmod +x ./cc-test-reporter + - ./cc-test-reporter before-build after_success: + - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT - bundle exec codeclimate-test-reporter diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index 5c93bf0..6e28785 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -20,10 +20,10 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'nokogiri', '~> 1.8' spec.add_development_dependency 'appraisal' - spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0' spec.add_development_dependency 'jekyll', '>= 3.5' spec.add_development_dependency 'minitest', '~> 5.0' spec.add_development_dependency 'pry' spec.add_development_dependency 'rake' spec.add_development_dependency 'rubocop' + spec.add_development_dependency 'simplecov' end From 970b1cd5141491ccb7d0fada34f628e1c470b47c Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sun, 4 Nov 2018 02:49:58 +0900 Subject: [PATCH 062/112] .rubocop.yml Update (#69) * Add Exclude files * Disable Style/FileName * Add module comment * Fix rubocop offence * Disable Metrics/LineLength --- .rubocop.yml | 11 ++++++++--- lib/jekyll-toc.rb | 1 + test/test_various_toc_html.rb | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9bad5c0..8d2d212 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,12 +1,13 @@ AllCops: TargetRubyVersion: 2.3 Exclude: + - '*.gemspec' - 'gemfiles/*' + - Rakefile + - Gemfile Metrics/LineLength: - Max: 100 - Exclude: - - 'test/**/*' + Enabled: false Metrics/MethodLength: Enabled: false @@ -16,3 +17,7 @@ Metrics/AbcSize: Metrics/ClassLength: Enabled: false + +Style/FileName: + Enabled: false + diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index 27077eb..6a7d70c 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -13,6 +13,7 @@ module Jekyll # end # end + # Jekyll Table of Contents filter plugin module TableOfContentsFilter def toc_only(html) return html unless toc_enabled? diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index 0a698b4..d83e415 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -86,7 +86,7 @@ def test_nested_toc end def test_nested_toc_with_min_and_max - parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1, { 'min_level' => 2, 'max_level' => 5 }) + parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1, 'min_level' => 2, 'max_level' => 5) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML
          @@ -299,7 +299,7 @@ def test_nested_toc_with_no_toc_section_class HTML def test_nested_toc_with_no_toc_section_class_option - parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE_2, { 'no_toc_section_class' => 'exclude' }) + parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_IGNORE_2, 'no_toc_section_class' => 'exclude') doc = Nokogiri::HTML(parser.toc) expected = <<~HTML
            @@ -356,7 +356,7 @@ def test_toc_with_explicit_id def test_custom_css_classes parser = Jekyll::TableOfContents::Parser.new( TEST_HTML_1, - { 'item_class' => 'custom-item', 'list_class' => 'custom-list', 'sublist_class' => 'custom-sublist', 'item_prefix' => 'custom-prefix-' } + 'item_class' => 'custom-item', 'list_class' => 'custom-list', 'sublist_class' => 'custom-sublist', 'item_prefix' => 'custom-prefix-' ) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML From 7d3dff90ae42421c8595e953143296dd733ebbca Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Wed, 28 Nov 2018 00:30:10 +0900 Subject: [PATCH 063/112] Allow mutiple `no_toc_section_class`es (#72) * Allow mutiple no_toc_section_class * multiple no_toc_sections * Update README.md * Rename test method name --- README.md | 10 ++++++++ lib/table_of_contents/parser.rb | 10 +++++++- test/test_various_toc_html.rb | 43 +++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ecdd354..ebaa992 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,16 @@ toc: no_toc_section_class: exclude # default: no_toc_section ``` +Configuring mutiple classes are allowed: + +```yml +toc: + no_toc_section_class: + - no_toc_section + - exclude + - your_custom_skip_class_name +``` + #### TOC levels The toc levels can be configured on `_config.yml`: diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 6cdcbcc..bbc4eb8 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -127,7 +127,15 @@ def toc_headings end def toc_headings_in_no_toc_section - @toc_levels.map { |level| ".#{@no_toc_section_class} h#{level}" }.join(',') + if @no_toc_section_class.is_a? Array + @no_toc_section_class.map { |cls| toc_headings_within(cls) }.join(',') + else + toc_headings_within(@no_toc_section_class) + end + end + + def toc_headings_within(class_name) + @toc_levels.map { |level| ".#{class_name} h#{level}" }.join(',') end def generate_option_hash(options) diff --git a/test/test_various_toc_html.rb b/test/test_various_toc_html.rb index d83e415..6526330 100644 --- a/test/test_various_toc_html.rb +++ b/test/test_various_toc_html.rb @@ -328,6 +328,49 @@ def test_nested_toc_with_no_toc_section_class_option assert_includes(html, '
            h5
            ') end + TEST_HTML_IGNORE_3 = <<~HTML +

            h1

            +
            +

            h2

            +
            +

            h3

            +
            +

            h4

            +
            h5
            +
            +
            h6
            + HTML + + 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 +
              +
            • + h1 +
                +
              • + h3 + +
              • +
              +
            • +
            + HTML + actual = doc.css('ul.section-nav').to_s + assert_equal(expected, actual) + + html = parser.inject_anchors_into_html + assert_match(%r{

            .+

            }m, html) + assert_match(%r{

            .+

            }m, html) + assert_match(%r{
            .+
            }m, html) + assert_includes(html, '

            h2

            ') + assert_includes(html, '

            h4

            ') + assert_includes(html, '
            h5
            ') + end + TEST_EXPLICIT_ID = <<~HTML

            h1

            h2

            From c362b5f8d5a850cfae2460e1f0575a51bff7b22a Mon Sep 17 00:00:00 2001 From: toshimaru Date: Wed, 28 Nov 2018 00:33:25 +0900 Subject: [PATCH 064/112] v0.9.1 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 8379a95..1812616 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.9.0' + VERSION = '0.9.1' end From 28bd3a335ec4da51debb84e575416bb3bf0288e1 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Wed, 28 Nov 2018 02:03:15 +0900 Subject: [PATCH 065/112] Fix readme[skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebaa992..2f065d0 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ toc: no_toc_section_class: exclude # default: no_toc_section ``` -Configuring mutiple classes are allowed: +Configuring multiple classes for `no_toc_section_class` is allowed: ```yml toc: From 6c9c0924ba706baf1eab35c3bcbf55669733afc2 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Wed, 20 Mar 2019 02:15:17 +0900 Subject: [PATCH 066/112] Update README.md --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2f065d0..c8f6b97 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ - [Installation](#installation) - [Usage](#usage) + - [1. Basic Usage](#1-basic-usage) + - [2. Advanced Usage](#2-advanced-usage) - [Generated HTML](#generated-html) - [Customization](#customization) - [Skip TOC](#skip-toc) @@ -64,13 +66,13 @@ If you'd like separated TOC and content, you can use `toc_only` and `inject_anch #### `toc_only` filter -Generates the TOC itself as described [below](#generated-table-of-contents-html). +Generates the TOC itself as described [below](#generated-html). Mostly useful in cases where the TOC should _not_ be placed immediately above the content but at some other place of the page, i.e. an aside. #### `inject_anchors` filter -Injects HTML anchors into the content without actually outputing the TOC itself. +Injects HTML anchors into the content without actually outputting the TOC itself. They are of the form: ```html @@ -82,9 +84,7 @@ 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. -### Generated HTML - -![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) +## Generated HTML jekyll-toc generates an unordered list. The HTML output is as follows. @@ -110,9 +110,11 @@ jekyll-toc generates an unordered list. The HTML output is as follows.
          ``` -### Customization +![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png)s + +## Customization -#### Skip TOC +### Skip TOC The heading is ignored in the toc when you add `no_toc` to the class. @@ -122,7 +124,7 @@ The heading is ignored in the toc when you add `no_toc` to the class.

          h2

          ``` -#### Skip TOC Section +### Skip TOC Section The headings are ignored inside the element which has `no_toc_section` class. @@ -148,13 +150,13 @@ Configuring multiple classes for `no_toc_section_class` is allowed: ```yml toc: - no_toc_section_class: + no_toc_section_class: - no_toc_section - exclude - your_custom_skip_class_name ``` -#### TOC levels +### TOC levels The toc levels can be configured on `_config.yml`: @@ -180,7 +182,7 @@ toc: The default level range is `

          ` to `

          `. -#### CSS Styling +### CSS Styling The toc can be modified with CSS. The sample CSS is the following. From 54282e51ac806aa3dc9803c37e9381d2fc12e93b Mon Sep 17 00:00:00 2001 From: gandalf3 Date: Thu, 21 Mar 2019 12:33:24 -0700 Subject: [PATCH 067/112] Have toc_only output an empty string when toc is disabled --- lib/jekyll-toc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index 6a7d70c..b2e508a 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -16,7 +16,7 @@ module Jekyll # Jekyll Table of Contents filter plugin module TableOfContentsFilter def toc_only(html) - return html unless toc_enabled? + return '' unless toc_enabled? ::Jekyll::TableOfContents::Parser.new(html, toc_config).build_toc end From 53386dfa6448834b746a0e99574298e1e68b4bbd Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 23 Mar 2019 12:29:37 +0900 Subject: [PATCH 068/112] Test aginast PR: #77 --- test/test_jekyll-toc.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/test_jekyll-toc.rb diff --git a/test/test_jekyll-toc.rb b/test/test_jekyll-toc.rb new file mode 100644 index 0000000..f32ea23 --- /dev/null +++ b/test/test_jekyll-toc.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'test_helper' + +class TestTableOfContentsFilter < Minitest::Test + include Jekyll::TableOfContentsFilter + + DUMMY_HTML = "
          Dummy HTML Content
          " + + def setup + stubbed_context = Struct.new(:registers) + @context = stubbed_context.new(page: "xxx") + @context + end + + def test_toc_only + assert_empty toc_only(DUMMY_HTML) + end + + def test_inject_anchors + assert_equal inject_anchors(DUMMY_HTML), DUMMY_HTML + end + + def test_toc + assert_equal toc(DUMMY_HTML), DUMMY_HTML + end +end From 7ed306528d1cf76b43b46bae278c7e92a65190bf Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 23 Mar 2019 12:41:41 +0900 Subject: [PATCH 069/112] :gem: nokogiri requires '~> 1.9' --- jekyll-toc.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index 6e28785..3b7fa15 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -17,7 +17,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.3' - spec.add_runtime_dependency 'nokogiri', '~> 1.8' + spec.add_runtime_dependency 'nokogiri', '~> 1.9' spec.add_development_dependency 'appraisal' spec.add_development_dependency 'jekyll', '>= 3.5' From c02c30bcb9a5e6dc344f1309da73034e021b7ad8 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 23 Mar 2019 12:43:28 +0900 Subject: [PATCH 070/112] v0.10.0 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 1812616..16bc637 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.9.1' + VERSION = '0.10.0' end From d018c2ba8e63e82a2473944b9422ed9344fdaf45 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sun, 24 Mar 2019 13:29:34 +0900 Subject: [PATCH 071/112] Avoid Duplicated IDs in a page (#79) * Organize test directory * Avoid duplicated id in a page * Add minitest-reporters * Fix failed tests --- jekyll-toc.gemspec | 3 ++- lib/table_of_contents/parser.rb | 2 +- test/{ => parser}/test_inject_anchors_filter.rb | 2 +- test/{ => parser}/test_option_error.rb | 0 test/{ => parser}/test_toc_filter.rb | 2 +- test/{ => parser}/test_toc_only_filter.rb | 0 test/{ => parser}/test_various_toc_html.rb | 6 +++--- test/test_helper.rb | 3 +++ 8 files changed, 11 insertions(+), 7 deletions(-) rename test/{ => parser}/test_inject_anchors_filter.rb (76%) rename test/{ => parser}/test_option_error.rb (100%) rename test/{ => parser}/test_toc_filter.rb (86%) rename test/{ => parser}/test_toc_only_filter.rb (100%) rename test/{ => parser}/test_various_toc_html.rb (97%) diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index 3b7fa15..dfae262 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -21,7 +21,8 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'appraisal' spec.add_development_dependency 'jekyll', '>= 3.5' - spec.add_development_dependency 'minitest', '~> 5.0' + spec.add_development_dependency 'minitest', '~> 5.11' + spec.add_development_dependency 'minitest-reporters' spec.add_development_dependency 'pry' spec.add_development_dependency 'rake' spec.add_development_dependency 'rubocop' diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index bbc4eb8..d7e6a84 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -40,7 +40,7 @@ def build_toc def inject_anchors_into_html @entries.each do |entry| entry[:content_node].add_previous_sibling( - %() + %() ) end diff --git a/test/test_inject_anchors_filter.rb b/test/parser/test_inject_anchors_filter.rb similarity index 76% rename from test/test_inject_anchors_filter.rb rename to test/parser/test_inject_anchors_filter.rb index 3c7a95f..c9158e5 100644 --- a/test/test_inject_anchors_filter.rb +++ b/test/parser/test_inject_anchors_filter.rb @@ -12,7 +12,7 @@ def setup def test_injects_anchors_into_content html = @parser.inject_anchors_into_html - assert_match(%r{Simple H1}, html) + assert_match(%r{Simple H1}, html) end def test_does_not_inject_toc diff --git a/test/test_option_error.rb b/test/parser/test_option_error.rb similarity index 100% rename from test/test_option_error.rb rename to test/parser/test_option_error.rb diff --git a/test/test_toc_filter.rb b/test/parser/test_toc_filter.rb similarity index 86% rename from test/test_toc_filter.rb rename to test/parser/test_toc_filter.rb index 874a9d7..a2ddd59 100644 --- a/test/test_toc_filter.rb +++ b/test/parser/test_toc_filter.rb @@ -12,7 +12,7 @@ def setup def test_injects_anchors html = @parser.toc - assert_match(%r{Simple H1}, html) + assert_match(%r{Simple H1}, html) end def test_nested_toc diff --git a/test/test_toc_only_filter.rb b/test/parser/test_toc_only_filter.rb similarity index 100% rename from test/test_toc_only_filter.rb rename to test/parser/test_toc_only_filter.rb diff --git a/test/test_various_toc_html.rb b/test/parser/test_various_toc_html.rb similarity index 97% rename from test/test_various_toc_html.rb rename to test/parser/test_various_toc_html.rb index 6526330..84b2287 100644 --- a/test/test_various_toc_html.rb +++ b/test/parser/test_various_toc_html.rb @@ -391,9 +391,9 @@ def test_toc_with_explicit_id assert_equal(expected, actual) html = parser.inject_anchors_into_html - assert_includes(html, %() + entry[:header_content].add_previous_sibling( + %() ) end @@ -63,17 +63,14 @@ def parse_content .gsub(PUNCTUATION_REGEXP, '') # remove punctuation .tr(' ', '-') # replace spaces with dash - uniq = headers[id].positive? ? "-#{headers[id]}" : '' + suffix_num = headers[id] headers[id] += 1 - header_content = node.children.first - next entries unless header_content entries << { - id: id, - uniq: uniq, + id: suffix_num.zero? ? id : "#{id}-#{suffix_num}", text: CGI.escapeHTML(text), node_name: node.name, - content_node: header_content, + header_content: node.children.first, h_num: node.name.delete('h').to_i } end @@ -89,7 +86,7 @@ def build_toc_list(entries) entry = entries[i] if entry[:h_num] == min_h_num # If the current entry should not be indented in the list, add the entry to the list - toc_list << %(
        • #{entry[:text]}) + toc_list << %(
        • #{entry[:text]}) # If the next entry should be indented in the list, generate a sublist next_i = i + 1 if next_i < entries.count && entries[next_i][:h_num] > min_h_num diff --git a/test/parser/test_various_toc_html.rb b/test/parser/test_various_toc_html.rb index 84b2287..87bb1e9 100644 --- a/test/parser/test_various_toc_html.rb +++ b/test/parser/test_various_toc_html.rb @@ -396,6 +396,27 @@ def test_toc_with_explicit_id assert_includes(html, %( + HTML + actual = doc.css('ul.section-nav').to_s + assert_equal(expected, actual) + end + def test_custom_css_classes parser = Jekyll::TableOfContents::Parser.new( TEST_HTML_1, From 1f552ca56846acf308477808c0620da764e1103a Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sun, 24 Mar 2019 14:47:52 +0900 Subject: [PATCH 073/112] v0.11.0 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 16bc637..ef703dd 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.10.0' + VERSION = '0.11.0' end From 59f17043905911a3f4bbf53c0fb1d88689652659 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 30 Mar 2019 06:21:24 +0900 Subject: [PATCH 074/112] Refactoring: Create Configuration Class (#81) * Create configuration class * Use Configuration class * Use `@configuration` * Add test for configuration * Add type error test * Update README * Fix rubocop * Fix rubocop 2 --- .rubocop.yml | 1 - README.md | 14 +++++++++ lib/jekyll-toc.rb | 1 + lib/table_of_contents/configuration.rb | 39 +++++++++++++++++++++++++ lib/table_of_contents/parser.rb | 40 ++++++-------------------- test/test_configuration.rb | 27 +++++++++++++++++ test/test_jekyll-toc.rb | 6 ++-- 7 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 lib/table_of_contents/configuration.rb create mode 100644 test/test_configuration.rb diff --git a/.rubocop.yml b/.rubocop.yml index 8d2d212..ccb87be 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -20,4 +20,3 @@ Metrics/ClassLength: Style/FileName: Enabled: false - diff --git a/README.md b/README.md index c8f6b97..e71d60a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - [1. Basic Usage](#1-basic-usage) - [2. Advanced Usage](#2-advanced-usage) - [Generated HTML](#generated-html) +- [Default Configuration](#default-configuration) - [Customization](#customization) - [Skip TOC](#skip-toc) - [Skip TOC Section](#skip-toc-section) @@ -112,6 +113,19 @@ jekyll-toc generates an unordered list. The HTML output is as follows. ![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png)s +## Default Configuration + +```yml +toc: + min_level: 1 + max_level: 6 + no_toc_section_class: no_toc_section + list_class: section-nav + sublist_class: '' + item_class: toc-entry + item_prefix: toc- +``` + ## Customization ### Skip TOC diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index b2e508a..e968564 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'nokogiri' +require 'table_of_contents/configuration' require 'table_of_contents/parser' module Jekyll diff --git a/lib/table_of_contents/configuration.rb b/lib/table_of_contents/configuration.rb new file mode 100644 index 0000000..ebf52b5 --- /dev/null +++ b/lib/table_of_contents/configuration.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Jekyll + module TableOfContents + # jekyll-toc configuration class + class Configuration + attr_accessor :toc_levels, :no_toc_section_class, :list_class, :sublist_class, :item_class, :item_prefix + + DEFAULT_CONFIG = { + 'min_level' => 1, + 'max_level' => 6, + 'no_toc_section_class' => 'no_toc_section', + 'list_class' => 'section-nav', + 'sublist_class' => '', + 'item_class' => 'toc-entry', + 'item_prefix' => 'toc-' + }.freeze + + def initialize(options) + options = generate_option_hash(options) + + @toc_levels = options['min_level']..options['max_level'] + @no_toc_section_class = options['no_toc_section_class'] + @list_class = options['list_class'] + @sublist_class = options['sublist_class'] + @item_class = options['item_class'] + @item_prefix = options['item_prefix'] + end + + private + + def generate_option_hash(options) + DEFAULT_CONFIG.merge(options) + rescue TypeError + DEFAULT_CONFIG + end + end + end +end diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 771158e..4d1ee3b 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -7,25 +7,9 @@ class Parser NO_TOC_CLASS_NAME = 'no_toc' PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u - DEFAULT_CONFIG = { - 'no_toc_section_class' => 'no_toc_section', - 'min_level' => 1, - 'max_level' => 6, - 'list_class' => 'section-nav', - 'sublist_class' => '', - 'item_class' => 'toc-entry', - 'item_prefix' => 'toc-' - }.freeze - def initialize(html, options = {}) @doc = Nokogiri::HTML::DocumentFragment.parse(html) - options = generate_option_hash(options) - @toc_levels = options['min_level']..options['max_level'] - @no_toc_section_class = options['no_toc_section_class'] - @list_class = options['list_class'] - @sublist_class = options['sublist_class'] - @item_class = options['item_class'] - @item_prefix = options['item_prefix'] + @configuration = Configuration.new(options) @entries = parse_content end @@ -34,7 +18,7 @@ def toc end def build_toc - %(
            \n#{build_toc_list(@entries)}
          ) + %(
            \n#{build_toc_list(@entries)}
          ) end def inject_anchors_into_html @@ -86,7 +70,7 @@ def build_toc_list(entries) entry = entries[i] if entry[:h_num] == min_h_num # If the current entry should not be indented in the list, add the entry to the list - toc_list << %(
        • #{entry[:text]}) + toc_list << %(
        • #{entry[:text]}) # If the next entry should be indented in the list, generate a sublist next_i = i + 1 if next_i < entries.count && entries[next_i][:h_num] > min_h_num @@ -120,29 +104,23 @@ def get_nest_entries(entries, min_h_num) end def toc_headings - @toc_levels.map { |level| "h#{level}" }.join(',') + @configuration.toc_levels.map { |level| "h#{level}" }.join(',') end def toc_headings_in_no_toc_section - if @no_toc_section_class.is_a? Array - @no_toc_section_class.map { |cls| toc_headings_within(cls) }.join(',') + if @configuration.no_toc_section_class.is_a? Array + @configuration.no_toc_section_class.map { |cls| toc_headings_within(cls) }.join(',') else - toc_headings_within(@no_toc_section_class) + toc_headings_within(@configuration.no_toc_section_class) end end def toc_headings_within(class_name) - @toc_levels.map { |level| ".#{class_name} h#{level}" }.join(',') - end - - def generate_option_hash(options) - DEFAULT_CONFIG.merge(options) - rescue TypeError - DEFAULT_CONFIG + @configuration.toc_levels.map { |level| ".#{class_name} h#{level}" }.join(',') end def ul_attributes - @ul_attributes ||= @sublist_class.empty? ? '' : %( class="#{@sublist_class}") + @ul_attributes ||= @configuration.sublist_class.empty? ? '' : %( class="#{@configuration.sublist_class}") end end end diff --git a/test/test_configuration.rb b/test/test_configuration.rb new file mode 100644 index 0000000..caf16f0 --- /dev/null +++ b/test/test_configuration.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'test_helper' + +class TestConfiguration < Minitest::Test + def test_default_conf1guration + configuration = Jekyll::TableOfContents::Configuration.new({}) + + assert_equal configuration.toc_levels, 1..6 + assert_equal configuration.no_toc_section_class, 'no_toc_section' + assert_equal configuration.list_class, 'section-nav' + assert_equal configuration.sublist_class, '' + assert_equal configuration.item_class, 'toc-entry' + assert_equal configuration.item_prefix, 'toc-' + end + + def test_type_error + configuration = Jekyll::TableOfContents::Configuration.new('TypeError!') + + assert_equal configuration.toc_levels, 1..6 + assert_equal configuration.no_toc_section_class, 'no_toc_section' + assert_equal configuration.list_class, 'section-nav' + assert_equal configuration.sublist_class, '' + assert_equal configuration.item_class, 'toc-entry' + assert_equal configuration.item_prefix, 'toc-' + end +end diff --git a/test/test_jekyll-toc.rb b/test/test_jekyll-toc.rb index f32ea23..c2a0c92 100644 --- a/test/test_jekyll-toc.rb +++ b/test/test_jekyll-toc.rb @@ -5,11 +5,11 @@ class TestTableOfContentsFilter < Minitest::Test include Jekyll::TableOfContentsFilter - DUMMY_HTML = "
          Dummy HTML Content
          " - + DUMMY_HTML = '
          Dummy HTML Content
          ' + def setup stubbed_context = Struct.new(:registers) - @context = stubbed_context.new(page: "xxx") + @context = stubbed_context.new(page: 'xxx') @context end From f354ebfd8db1d8bdf767de6f9b86a0dc9c7bb367 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 30 Mar 2019 06:22:06 +0900 Subject: [PATCH 075/112] v0.12.0.rc1 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index ef703dd..c690ead 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.11.0' + VERSION = '0.12.0.rc1' end From e48c5294a8ee3fbdca784b3643a5e0de7a82b49d Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 30 Mar 2019 17:10:46 +0900 Subject: [PATCH 076/112] Liquid::Template.register_tag 'toc' (#82) * Liquid::Template.register_tag 'toc' * Add Dprecation message for toc_only * Fix rubocop offences * Add test for Jekyll::TocTag * Add more test * Siplify stub object * Fix typo * Update README.md --- README.md | 19 +++++++++++++++++-- lib/jekyll-toc.rb | 21 ++++++++++++--------- test/test_jekyll-toc.rb | 4 +--- test/test_toc_tag.rb | 24 ++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 test/test_toc_tag.rb diff --git a/README.md b/README.md index e71d60a..431d513 100644 --- a/README.md +++ b/README.md @@ -65,19 +65,34 @@ This filter places the TOC directly above the content. If you'd like separated TOC and content, you can use `toc_only` and `inject_anchors` filters. -#### `toc_only` filter +#### ~~`toc_only` filter~~ + +⚠️ Please use `{% toc %}` instead of `{{ contents | toc_only }}`. Generates the TOC itself as described [below](#generated-html). Mostly useful in cases where the TOC should _not_ be placed immediately above the content but at some other place of the page, i.e. an aside. +#### toc tag + +```html +
          +
          + {% toc %} +
          +
          + {{ content }} +
          +
          +``` + #### `inject_anchors` filter Injects HTML anchors into the content without actually outputting the TOC itself. They are of the form: ```html - ``` diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index e968564..1fa5d37 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -5,18 +5,21 @@ require 'table_of_contents/parser' module Jekyll - # class TocTag < Liquid::Tag - # def render(context) - # return unless context.registers[:page]['toc'] - # - # content_html = context.registers[:page].content - # ::Jekyll::TableOfContents::Parser.new(content_html).build_toc - # end - # end + # toc tag for Jekyll + class TocTag < Liquid::Tag + def render(context) + return '' unless context.registers[:page]['toc'] + + content_html = context.registers[:page].content + ::Jekyll::TableOfContents::Parser.new(content_html).build_toc + end + end # Jekyll Table of Contents filter plugin module TableOfContentsFilter def toc_only(html) + Jekyll.logger.warn 'Deprecation: toc_only filter is deprecated and will be remove in jekyll-toc v1.0.', + 'Use `{% toc %}` instead of `{{ contents | toc_only }}`.' return '' unless toc_enabled? ::Jekyll::TableOfContents::Parser.new(html, toc_config).build_toc @@ -47,4 +50,4 @@ def toc_config end Liquid::Template.register_filter(Jekyll::TableOfContentsFilter) -# Liquid::Template.register_tag('toc', Jekyll::TocTag) # will be enabled at v1.0 +Liquid::Template.register_tag('toc', Jekyll::TocTag) # will be enabled at v1.0 diff --git a/test/test_jekyll-toc.rb b/test/test_jekyll-toc.rb index c2a0c92..483ee3f 100644 --- a/test/test_jekyll-toc.rb +++ b/test/test_jekyll-toc.rb @@ -8,9 +8,7 @@ class TestTableOfContentsFilter < Minitest::Test DUMMY_HTML = '
          Dummy HTML Content
          ' def setup - stubbed_context = Struct.new(:registers) - @context = stubbed_context.new(page: 'xxx') - @context + @context = Struct.new(:registers).new(page: { "toc" => false }) end def test_toc_only diff --git a/test/test_toc_tag.rb b/test/test_toc_tag.rb new file mode 100644 index 0000000..7052c37 --- /dev/null +++ b/test/test_toc_tag.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'test_helper' + +class TestTableOfContentsTag < Minitest::Test + include Liquid + + def setup + @stubbed_context = Struct.new(:registers) + @stubbed_context2 = Struct.new(:toc, :content) + end + + def test_toc_tag + context = @stubbed_context.new(page: @stubbed_context2.new({ 'toc' => false }, '

          test

          ')) + tag = Jekyll::TocTag.parse('toc_tag', '', Tokenizer.new(''), ParseContext.new) + assert_equal tag.render(context), "" + end + + def test_toc_tag_returns_empty_string + context = @stubbed_context.new(page: { 'toc' => false }) + tag = Jekyll::TocTag.parse('toc_tag', '', Tokenizer.new(''), ParseContext.new) + assert_empty tag.render(context) + end +end From 13ed59a8120496d020bd2677bea4ea978a385fb6 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sat, 30 Mar 2019 17:11:20 +0900 Subject: [PATCH 077/112] v0.12.0.rc2 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index c690ead..e9a339c 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.12.0.rc1' + VERSION = '0.12.0.rc2' end From 51147231f09fd93f2b7b509b7b5af4cdd52150de Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sun, 31 Mar 2019 18:51:45 +0900 Subject: [PATCH 078/112] Fix toc tag bug / Add tests (#83) * Fix typo * Use Hash access * Create Jekyll::TableOfContents::Helper module * Revert "Create Jekyll::TableOfContents::Helper module" This reverts commit 45649d79e9772302d3462ff75e0f89aa55a80aed. * Set toc_config * Add test for coverage --- README.md | 2 +- lib/jekyll-toc.rb | 12 +++++++----- test/test_jekyll-toc.rb | 39 +++++++++++++++++++++++++++++++++------ test/test_toc_tag.rb | 6 +++++- 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 431d513..e57e5c8 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ If you'd like separated TOC and content, you can use `toc_only` and `inject_anch #### ~~`toc_only` filter~~ -⚠️ Please use `{% toc %}` instead of `{{ contents | toc_only }}`. +⚠️ Please use `{% toc %}` instead of `{{ content | toc_only }}`. Generates the TOC itself as described [below](#generated-html). Mostly useful in cases where the TOC should _not_ be placed immediately diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index 1fa5d37..9fa142e 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -10,31 +10,33 @@ class TocTag < Liquid::Tag def render(context) return '' unless context.registers[:page]['toc'] - content_html = context.registers[:page].content - ::Jekyll::TableOfContents::Parser.new(content_html).build_toc + content_html = context.registers[:page]['content'] + toc_config = context.registers[:site].config['toc'] || {} + TableOfContents::Parser.new(content_html, toc_config).build_toc end end # Jekyll Table of Contents filter plugin module TableOfContentsFilter + # Deprecated method. Removed in v1.0. def toc_only(html) Jekyll.logger.warn 'Deprecation: toc_only filter is deprecated and will be remove in jekyll-toc v1.0.', 'Use `{% toc %}` instead of `{{ contents | toc_only }}`.' return '' unless toc_enabled? - ::Jekyll::TableOfContents::Parser.new(html, toc_config).build_toc + TableOfContents::Parser.new(html, toc_config).build_toc end def inject_anchors(html) return html unless toc_enabled? - ::Jekyll::TableOfContents::Parser.new(html, toc_config).inject_anchors_into_html + TableOfContents::Parser.new(html, toc_config).inject_anchors_into_html end def toc(html) return html unless toc_enabled? - ::Jekyll::TableOfContents::Parser.new(html, toc_config).toc + TableOfContents::Parser.new(html, toc_config).toc end private diff --git a/test/test_jekyll-toc.rb b/test/test_jekyll-toc.rb index 483ee3f..34fed46 100644 --- a/test/test_jekyll-toc.rb +++ b/test/test_jekyll-toc.rb @@ -7,19 +7,46 @@ class TestTableOfContentsFilter < Minitest::Test DUMMY_HTML = '
          Dummy HTML Content
          ' - def setup - @context = Struct.new(:registers).new(page: { "toc" => false }) - end - def test_toc_only + @context = disable_toc_context assert_empty toc_only(DUMMY_HTML) end def test_inject_anchors - assert_equal inject_anchors(DUMMY_HTML), DUMMY_HTML + @context = disable_toc_context + assert_equal DUMMY_HTML, inject_anchors(DUMMY_HTML) end def test_toc - assert_equal toc(DUMMY_HTML), DUMMY_HTML + @context = disable_toc_context + assert_equal DUMMY_HTML, toc(DUMMY_HTML) + end + + def test_toc_only2 + @context = enable_toc_context + assert_equal "
            \n
          ", toc_only(DUMMY_HTML) + end + + def test_inject_anchors2 + @context = enable_toc_context + assert_equal DUMMY_HTML, inject_anchors(DUMMY_HTML) + end + + def test_toc2 + @context = enable_toc_context + assert_equal "
            \n
          #{DUMMY_HTML}", toc(DUMMY_HTML) + end + + private + + def disable_toc_context + Struct.new(:registers).new(page: { 'toc' => false }) + end + + def enable_toc_context + Struct.new(:registers).new( + page: { 'toc' => true }, + site: Struct.new(:config).new({ 'toc' => false }) + ) end end diff --git a/test/test_toc_tag.rb b/test/test_toc_tag.rb index 7052c37..7b371ed 100644 --- a/test/test_toc_tag.rb +++ b/test/test_toc_tag.rb @@ -7,11 +7,15 @@ class TestTableOfContentsTag < Minitest::Test def setup @stubbed_context = Struct.new(:registers) + @stubbed_context1 = Struct.new(:config) @stubbed_context2 = Struct.new(:toc, :content) end def test_toc_tag - context = @stubbed_context.new(page: @stubbed_context2.new({ 'toc' => false }, '

          test

          ')) + context = @stubbed_context.new( + page: @stubbed_context2.new({ 'toc' => false }, '

          test

          '), + site: @stubbed_context1.new({ 'toc' => nil }) + ) tag = Jekyll::TocTag.parse('toc_tag', '', Tokenizer.new(''), ParseContext.new) assert_equal tag.render(context), "" end From f0f50a60f6dd0b41753bd59ad3ff5c9717bb746a Mon Sep 17 00:00:00 2001 From: toshimaru Date: Sun, 31 Mar 2019 18:52:20 +0900 Subject: [PATCH 079/112] v0.12.0.rc3 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index e9a339c..065c90d 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.12.0.rc2' + VERSION = '0.12.0.rc3' end From b400936f5e1f4d690a4c94d43ee61abbd9204811 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Tue, 2 Apr 2019 01:36:26 +0900 Subject: [PATCH 080/112] Update README.md --- README.md | 62 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e57e5c8..e75e641 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,11 @@ - [Generated HTML](#generated-html) - [Default Configuration](#default-configuration) - [Customization](#customization) + - [TOC levels](#toc-levels) - [Skip TOC](#skip-toc) - [Skip TOC Section](#skip-toc-section) - - [TOC levels](#toc-levels) - [CSS Styling](#css-styling) + - [Custom CSS Class](#custom-css-class) ## Installation @@ -126,7 +127,7 @@ jekyll-toc generates an unordered list. The HTML output is as follows.
        ``` -![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png)s +![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) ## Default Configuration @@ -143,6 +144,18 @@ toc: ## Customization +### TOC levels + +The toc levels can be configured on `_config.yml`: + +```yml +toc: + min_level: 2 # default: 1 + max_level: 5 # default: 6 +``` + +The default level range is `

        ` to `

        `. + ### Skip TOC The heading is ignored in the toc when you add `no_toc` to the class. @@ -185,32 +198,6 @@ toc: - your_custom_skip_class_name ``` -### TOC levels - -The toc levels can be configured on `_config.yml`: - -```yml -toc: - min_level: 2 # default: 1 - max_level: 5 # default: 6 -``` - -You can apply custom CSS classes to the generated `
          ` and `
        • ` tags. - -```yml -toc: - # Default is "section-nav": - list_class: my-list-class - # Default is no class for sublists: - sublist_class: my-sublist-class - # Default is "toc-entry": - item_class: my-item-class - # Default is "toc-": - item_prefix: item- -``` - -The default level range is `

          ` to `

          `. - ### CSS Styling The toc can be modified with CSS. The sample CSS is the following. @@ -227,8 +214,23 @@ The toc can be modified with CSS. The sample CSS is the following. ![screenshot](https://user-images.githubusercontent.com/803398/28401455-0ba60868-6d55-11e7-8159-0ae7591aee66.png) -Each TOC `li` entry has two CSS classes for further styling. -The general `toc-entry` is applied to all `li` elements in the `ul.section-nav`. +Each TOC `li` entry has two CSS classes for further styling. The general `toc-entry` is applied to all `li` elements in the `ul.section-nav`. Depending on the heading level each specific entry refers to, it has a second CSS class `toc-XX`, where `XX` is the HTML heading tag name. For example, the TOC entry linking to a heading `

          ...

          ` (a single `#` in Markdown) will get the CSS class `toc-h1`. + +### Custom CSS Class + +You can apply custom CSS classes to the generated `
            ` and `
          • ` tags. + +```yml +toc: + # Default is "section-nav": + list_class: my-list-class + # Default is no class for sublists: + sublist_class: my-sublist-class + # Default is "toc-entry": + item_class: my-item-class + # Default is "toc-": + item_prefix: item- +``` From 1bee5d471342ba5cc8858266f77e46bf6470ce55 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Tue, 2 Apr 2019 01:36:45 +0900 Subject: [PATCH 081/112] v0.12.0 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 065c90d..6b242f6 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.12.0.rc3' + VERSION = '0.12.0' end From d7656b7302f6cbcf25e62457fd57e7a6d01b7759 Mon Sep 17 00:00:00 2001 From: toshimaru Date: Tue, 2 Apr 2019 01:38:17 +0900 Subject: [PATCH 082/112] Copyright (c) 2019 Toshimaru --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index f5a4945..7c19aae 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017 Toshimaru Enomoto +Copyright (c) 2019 Toshimaru Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 53387fab078f51ab1923c017bb3587400204afc1 Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Sat, 6 Apr 2019 19:01:27 +0900 Subject: [PATCH 083/112] v0.12.1 (#84) * Fix message * Update README.md * Move NO_TOC_CLASS_NAME to configuration * v0.12.1 * Better heading for toc tag * Update README.md --- README.md | 8 +++++--- lib/jekyll-toc.rb | 2 +- lib/table_of_contents/configuration.rb | 4 +++- lib/table_of_contents/parser.rb | 3 +-- lib/version.rb | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e75e641..caa151a 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ This filter places the TOC directly above the content. If you'd like separated TOC and content, you can use `toc_only` and `inject_anchors` filters. -#### ~~`toc_only` filter~~ +#### ~~`toc_only` filter~~ `toc` tag ⚠️ Please use `{% toc %}` instead of `{{ content | toc_only }}`. @@ -74,8 +74,6 @@ Generates the TOC itself as described [below](#generated-html). Mostly useful in cases where the TOC should _not_ be placed immediately above the content but at some other place of the page, i.e. an aside. -#### toc tag - ```html
            @@ -87,6 +85,10 @@ above the content but at some other place of the page, i.e. an aside.
            ``` +#### Current Limitation + +**`{% toc %}` can be available only in [Jekyll Posts](https://jekyllrb.com/docs/step-by-step/08-blogging/) and [Jekyll Collections](https://jekyllrb.com/docs/collections/). If any concern or issue, please report it on [issue](https://github.com/toshimaru/jekyll-toc/issues/new).** + #### `inject_anchors` filter Injects HTML anchors into the content without actually outputting the TOC itself. diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index 9fa142e..95ee928 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -21,7 +21,7 @@ module TableOfContentsFilter # Deprecated method. Removed in v1.0. def toc_only(html) Jekyll.logger.warn 'Deprecation: toc_only filter is deprecated and will be remove in jekyll-toc v1.0.', - 'Use `{% toc %}` instead of `{{ contents | toc_only }}`.' + 'Use `{% toc %}` instead of `{{ content | toc_only }}`.' return '' unless toc_enabled? TableOfContents::Parser.new(html, toc_config).build_toc diff --git a/lib/table_of_contents/configuration.rb b/lib/table_of_contents/configuration.rb index ebf52b5..61eeeeb 100644 --- a/lib/table_of_contents/configuration.rb +++ b/lib/table_of_contents/configuration.rb @@ -4,7 +4,8 @@ module Jekyll module TableOfContents # jekyll-toc configuration class class Configuration - attr_accessor :toc_levels, :no_toc_section_class, :list_class, :sublist_class, :item_class, :item_prefix + attr_accessor :toc_levels, :no_toc_class, :no_toc_section_class, + :list_class, :sublist_class, :item_class, :item_prefix DEFAULT_CONFIG = { 'min_level' => 1, @@ -20,6 +21,7 @@ def initialize(options) options = generate_option_hash(options) @toc_levels = options['min_level']..options['max_level'] + @no_toc_class = 'no_toc' @no_toc_section_class = options['no_toc_section_class'] @list_class = options['list_class'] @sublist_class = options['sublist_class'] diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 4d1ee3b..85dd11c 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -4,7 +4,6 @@ module Jekyll module TableOfContents # Parse html contents and generate table of contents class Parser - NO_TOC_CLASS_NAME = 'no_toc' PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u def initialize(html, options = {}) @@ -39,7 +38,7 @@ def parse_content headers = Hash.new(0) (@doc.css(toc_headings) - @doc.css(toc_headings_in_no_toc_section)) - .reject { |n| n.classes.include?(NO_TOC_CLASS_NAME) } + .reject { |n| n.classes.include?(@configuration.no_toc_class) } .inject([]) do |entries, node| text = node.text id = node.attribute('id') || text diff --git a/lib/version.rb b/lib/version.rb index 6b242f6..7eb860d 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module JekyllToc - VERSION = '0.12.0' + VERSION = '0.12.1' end From 1db42d4790371ebe68611fea01b294d418447b1b Mon Sep 17 00:00:00 2001 From: Toshimaru Date: Thu, 8 Aug 2019 23:06:42 +0900 Subject: [PATCH 084/112] Remove `toc_only` deprecation message (#87) * Remove `toc_only` deprecation message * Drop Ruby 2.3 support * TargetRubyVersion: 2.4 * collection for rubocop * Update Ruby patch versions * Remove freeze method * Update README.md --- .rubocop.yml | 8 +++++++- .travis.yml | 7 +++---- README.md | 4 ++-- lib/jekyll-toc.rb | 2 -- test/parser/test_various_toc_html.rb | 1 - test/test_helper.rb | 2 +- test/test_toc_tag.rb | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index ccb87be..24af3db 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 2.3 + TargetRubyVersion: 2.4 Exclude: - '*.gemspec' - 'gemfiles/*' @@ -20,3 +20,9 @@ Metrics/ClassLength: Style/FileName: Enabled: false + +Style/BracesAroundHashParameters: + Enabled: false + +Style/WordArray: + Enabled: false diff --git a/.travis.yml b/.travis.yml index 92319d3..f4f9b9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,9 @@ env: global: - CC_TEST_REPORTER_ID=6b81e393ea6ad38560386f650ea2fb0e57a7beb5e20f8c8364fabee30d5bff07 rvm: - - 2.3.7 - - 2.4.4 - - 2.5.1 - - 2.6.2 + - 2.4.6 + - 2.5.5 + - 2.6.3 # gemfile is generated by appraisal gemfile: - gemfiles/jekyll_3.8.gemfile diff --git a/README.md b/README.md index caa151a..5c5b398 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,9 @@ This filter places the TOC directly above the content. If you'd like separated TOC and content, you can use `toc_only` and `inject_anchors` filters. -#### ~~`toc_only` filter~~ `toc` tag +#### `toc_only` filter -⚠️ Please use `{% toc %}` instead of `{{ content | toc_only }}`. +⚠️ ~~Please use `{% toc %}` instead of `{{ content | toc_only }}`.~~ Generates the TOC itself as described [below](#generated-html). Mostly useful in cases where the TOC should _not_ be placed immediately diff --git a/lib/jekyll-toc.rb b/lib/jekyll-toc.rb index 95ee928..d28c143 100644 --- a/lib/jekyll-toc.rb +++ b/lib/jekyll-toc.rb @@ -20,8 +20,6 @@ def render(context) module TableOfContentsFilter # Deprecated method. Removed in v1.0. def toc_only(html) - Jekyll.logger.warn 'Deprecation: toc_only filter is deprecated and will be remove in jekyll-toc v1.0.', - 'Use `{% toc %}` instead of `{{ content | toc_only }}`.' return '' unless toc_enabled? TableOfContents::Parser.new(html, toc_config).build_toc diff --git a/test/parser/test_various_toc_html.rb b/test/parser/test_various_toc_html.rb index 87bb1e9..2668b31 100644 --- a/test/parser/test_various_toc_html.rb +++ b/test/parser/test_various_toc_html.rb @@ -396,7 +396,6 @@ def test_toc_with_explicit_id assert_includes(html, %(
              /, html) + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + end + + def test_does_not_return_content + html = @parser.build_toc + + assert_nil(%r{

              Simple H1

              } =~ html) + end + + class TestTOCOnlyFilterEncodingOff < Minitest::Test + include TestHelpersEncoding + + def setup + read_html_and_create_parser(false) + end + + def test_injects_toc_container_without_anchor_id_url_encoded + html = @parser.build_toc + + assert_match(/
                /, html) + + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + assert_match(//, html) + end + end +end diff --git a/test/test_helper_encoding.rb b/test/test_helper_encoding.rb new file mode 100644 index 0000000..83c2e71 --- /dev/null +++ b/test/test_helper_encoding.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'simplecov' +SimpleCov.start + +require 'minitest/autorun' +require 'minitest/reporters' +Minitest::Reporters.use! + +require 'jekyll' +require 'jekyll-toc' +require 'table_of_contents/configuration' + +SIMPLE_HTML_WITH_IDS = <<~HTML +

                Simple H1

                +

                Simple H2a

                +

                Simple H2b

                +

                Simple H3a

                +

                Simple H3b

                +

                Simple H3c ÜÄÖ

                +HTML + +module TestHelpersEncoding + def read_html_and_create_parser(anchor_id_url_encoded) + @parser = Jekyll::TableOfContents::Parser.new(SIMPLE_HTML_WITH_IDS) + @config = Jekyll::TableOfContents::Configuration.new({}) + @config.anchor_id_url_encoded = anchor_id_url_encoded + end +end From d0f00ab42fcfcb33d845372cfe6b4a13e1fd6194 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Wed, 8 Jan 2020 18:25:49 +0100 Subject: [PATCH 091/112] Url-Encoding for element id (spaces and UTF-8 support) --- lib/table_of_contents/parser.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 85dd11c..34bc906 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require "erb" +include ERB::Util + module Jekyll module TableOfContents # Parse html contents and generate table of contents @@ -45,6 +48,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 From ab7e791451eb92f4a60713f007804d4276548e28 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Wed, 8 Jan 2020 18:30:00 +0100 Subject: [PATCH 092/112] Save parent element of entry, to add a anchor id --- lib/table_of_contents/parser.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 34bc906..2133d46 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -25,6 +25,9 @@ def build_toc def inject_anchors_into_html @entries.each do |entry| + # Add id to h-element + entry[:header_parent].set_attribute("id", "#{entry[:id]}") + entry[:header_content].add_previous_sibling( %(
                ) ) @@ -57,6 +60,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 } From 20d355abe09b942edd4fd38e8be25c53492e2935 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Wed, 8 Jan 2020 18:32:25 +0100 Subject: [PATCH 093/112] Replace em-font-icon element with a unicode arrow --- lib/table_of_contents/parser.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 2133d46..5dd1fb6 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -28,9 +28,9 @@ def inject_anchors_into_html # Add id to h-element entry[:header_parent].set_attribute("id", "#{entry[:id]}") - entry[:header_content].add_previous_sibling( - %() - ) + # Add link icon after text + entry[:header_content].add_next_sibling(%() + end @doc.inner_html From cb752bce83f0cb7aa4502d15e4c5af737abb49ab Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Wed, 8 Jan 2020 18:36:57 +0100 Subject: [PATCH 094/112] Format Code --- lib/table_of_contents/parser.rb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 5dd1fb6..04fd25b 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -20,7 +20,7 @@ def toc end def build_toc - %(
                  \n#{build_toc_list(@entries)}
                ) + %(
                  \n#{build_toc_list(@entries)}
                ) end def inject_anchors_into_html @@ -29,9 +29,18 @@ def inject_anchors_into_html entry[:header_parent].set_attribute("id", "#{entry[:id]}") # Add link icon after text - entry[:header_content].add_next_sibling(%() - - end + entry[:header_content].add_next_sibling( + %( + ) + + # Add link 'nav to toc' + arrToTop = [ 2, 3 ] + if arrToTop.include?(entry[:h_num]) then + entry[:header_content].add_next_sibling( + %() + ) + end + end @doc.inner_html end From 740ab0e5d719d15119b61a21628cf071e49e636d Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Wed, 8 Jan 2020 18:59:00 +0100 Subject: [PATCH 095/112] Format Code --- lib/table_of_contents/parser.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 04fd25b..f0b1279 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -25,21 +25,21 @@ def build_toc def inject_anchors_into_html @entries.each do |entry| - # Add id to h-element - entry[:header_parent].set_attribute("id", "#{entry[:id]}") + # Add id to h-element + entry[:header_parent].set_attribute("id", "#{entry[:id]}") - # Add link icon after text - entry[:header_content].add_next_sibling( - %( - ) - - # Add link 'nav to toc' - arrToTop = [ 2, 3 ] - if arrToTop.include?(entry[:h_num]) then - entry[:header_content].add_next_sibling( - %() - ) - end + # Add link icon after text + entry[:header_content].add_next_sibling( + %() + ) + + # Add link 'nav to toc' + arrToTop = [ 2, 3 ] + if arrToTop.include?(entry[:h_num]) then + entry[:header_content].add_next_sibling( + %() + ) + end end @doc.inner_html From 664d0d211380243301ce0a026857bf274608fbc2 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Fri, 17 Jan 2020 16:55:17 +0100 Subject: [PATCH 096/112] Add class for the link to top --- lib/table_of_contents/parser.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index f0b1279..f8025fd 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -37,7 +37,7 @@ def inject_anchors_into_html arrToTop = [ 2, 3 ] if arrToTop.include?(entry[:h_num]) then entry[:header_content].add_next_sibling( - %() + %() ) end end From b5f13713d2a80a42e863617611efe51da33e5702 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 12:11:13 +0100 Subject: [PATCH 097/112] PR94 - codeclimate fixes --- lib/table_of_contents/parser.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index f8025fd..c968ea3 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true -require "erb" -include ERB::Util +require 'erb' module Jekyll + include ERB::Util + module TableOfContents # Parse html contents and generate table of contents class Parser @@ -26,21 +27,21 @@ def build_toc def inject_anchors_into_html @entries.each do |entry| # Add id to h-element - entry[:header_parent].set_attribute("id", "#{entry[:id]}") - + entry[:header_parent].set_attribute('id', '#{entry[:id]}') + # Add link icon after text entry[:header_content].add_next_sibling( %() ) # Add link 'nav to toc' - arrToTop = [ 2, 3 ] - if arrToTop.include?(entry[:h_num]) then + arrToTop = [2, 3] + if arrToTop.include?(entry[:h_num]) entry[:header_content].add_next_sibling( %() ) end - end + end @doc.inner_html end From 83fcd11af959f29e0fbae4ba04794c5b25670d13 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 12:23:42 +0100 Subject: [PATCH 098/112] PR94 - codeclimate fixes --- lib/table_of_contents/parser.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index c968ea3..0d3dc4d 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,10 +1,9 @@ -# frozen_string_literal: true - require 'erb' +include ERB::Util +# Jekyll Modul, the root of everything module Jekyll - include ERB::Util - + # Module to wrap the classes for TOC creation module TableOfContents # Parse html contents and generate table of contents class Parser @@ -27,7 +26,7 @@ def build_toc def inject_anchors_into_html @entries.each do |entry| # Add id to h-element - entry[:header_parent].set_attribute('id', '#{entry[:id]}') + entry[:header_parent].set_attribute('id', "#{entry[:id]}") # Add link icon after text entry[:header_content].add_next_sibling( @@ -35,8 +34,8 @@ def inject_anchors_into_html ) # Add link 'nav to toc' - arrToTop = [2, 3] - if arrToTop.include?(entry[:h_num]) + arr_to_top = [2, 3] + if arr_to_top.include?(entry[:h_num]) entry[:header_content].add_next_sibling( %() ) From c67ae1adcd270efa35112b2b597e343654eb77ed Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 12:42:39 +0100 Subject: [PATCH 099/112] PR94 - codeclimate fixes --- lib/table_of_contents/parser.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 0d3dc4d..cf303fe 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true + require 'erb' -include ERB::Util # Jekyll Modul, the root of everything module Jekyll @@ -7,6 +8,8 @@ module Jekyll module TableOfContents # Parse html contents and generate table of contents class Parser + include ERB::Util + PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u def initialize(html, options = {}) @@ -26,7 +29,7 @@ def build_toc def inject_anchors_into_html @entries.each do |entry| # Add id to h-element - entry[:header_parent].set_attribute('id', "#{entry[:id]}") + entry[:header_parent].set_attribute('id', "#{entry[:id]}.to_s") # Add link icon after text entry[:header_content].add_next_sibling( From e3be7578bb9408303a826770f58529602a4f4884 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 12:56:46 +0100 Subject: [PATCH 100/112] PR94 - codeclimate fixes --- lib/table_of_contents/parser.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index cf303fe..a169e80 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -38,11 +38,12 @@ def inject_anchors_into_html # Add link 'nav to toc' arr_to_top = [2, 3] - if arr_to_top.include?(entry[:h_num]) + next unless arr_to_top.include?(entry[:h_num]) + #if arr_to_top.include?(entry[:h_num]) entry[:header_content].add_next_sibling( %() ) - end + #end end @doc.inner_html From 6906d0c0bd95d7c5ba25fff682dd97874dbb581f Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 13:00:41 +0100 Subject: [PATCH 101/112] PR94 - codeclimate fixes --- lib/table_of_contents/parser.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index a169e80..98a9e96 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -39,11 +39,9 @@ def inject_anchors_into_html # Add link 'nav to toc' arr_to_top = [2, 3] next unless arr_to_top.include?(entry[:h_num]) - #if arr_to_top.include?(entry[:h_num]) - entry[:header_content].add_next_sibling( - %() - ) - #end + entry[:header_content].add_next_sibling( + %() + ) end @doc.inner_html From cb69d67590dacb2a70be45515f450f6ca9893252 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 15:07:08 +0100 Subject: [PATCH 102/112] Add Testing Section to readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 5c5b398..b26fda8 100644 --- a/README.md +++ b/README.md @@ -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. From f42ff59184489aabce491dcd2ebc16c71fcf6999 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 18 Jan 2020 15:07:21 +0100 Subject: [PATCH 103/112] Fix UnitTest test_toc_tag --- test/test_toc_tag.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_toc_tag.rb b/test/test_toc_tag.rb index ce2b30e..7f7c642 100644 --- a/test/test_toc_tag.rb +++ b/test/test_toc_tag.rb @@ -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), "" + assert_equal tag.render(context), "" end def test_toc_tag_returns_empty_string From 3c5b7d724579295cc39dc534d722e934c467c481 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Sat, 29 Feb 2020 14:12:59 +0100 Subject: [PATCH 104/112] Fix unit tests, id and anchor --- test/parser/test_inject_anchors_filter.rb | 2 +- test/parser/test_option_error.rb | 4 +- test/parser/test_toc_filter.rb | 4 +- test/parser/test_toc_only_filter.rb | 2 +- test/parser/test_various_toc_html.rb | 48 +++++++++++------------ test/test_jekyll-toc.rb | 4 +- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/test/parser/test_inject_anchors_filter.rb b/test/parser/test_inject_anchors_filter.rb index c9158e5..8c55aa0 100644 --- a/test/parser/test_inject_anchors_filter.rb +++ b/test/parser/test_inject_anchors_filter.rb @@ -12,7 +12,7 @@ def setup def test_injects_anchors_into_content html = @parser.inject_anchors_into_html - assert_match(%r{Simple H1}, html) + assert_match(%r{}, html) end def test_does_not_inject_toc diff --git a/test/parser/test_option_error.rb b/test/parser/test_option_error.rb index c469e29..acf3977 100644 --- a/test/parser/test_option_error.rb +++ b/test/parser/test_option_error.rb @@ -5,7 +5,7 @@ class TestOptionError < Minitest::Test BASE_HTML = '

                h1

                ' EXPECTED_HTML = <<~HTML -
                  + HTML @@ -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) diff --git a/test/parser/test_toc_filter.rb b/test/parser/test_toc_filter.rb index a2ddd59..5d44b90 100644 --- a/test/parser/test_toc_filter.rb +++ b/test/parser/test_toc_filter.rb @@ -12,7 +12,7 @@ def setup def test_injects_anchors html = @parser.toc - assert_match(%r{Simple H1}, html) + assert_match(%r{}, html) end def test_nested_toc @@ -31,6 +31,6 @@ def test_nested_toc def test_injects_toc_container html = @parser.toc - assert_match(/
                    /, html) + assert_match(/
                      /, html) end end diff --git a/test/parser/test_toc_only_filter.rb b/test/parser/test_toc_only_filter.rb index cc0b9eb..c294c71 100644 --- a/test/parser/test_toc_only_filter.rb +++ b/test/parser/test_toc_only_filter.rb @@ -12,7 +12,7 @@ def setup def test_injects_toc_container html = @parser.build_toc - assert_match(/
                        /, html) + assert_match(/
                          /, html) end def test_does_not_return_content diff --git a/test/parser/test_various_toc_html.rb b/test/parser/test_various_toc_html.rb index 2668b31..82de0c8 100644 --- a/test/parser/test_various_toc_html.rb +++ b/test/parser/test_various_toc_html.rb @@ -66,7 +66,7 @@ def test_nested_toc parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_1) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                            +
                            • h1
                                @@ -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 -
                                  + HTML @@ -102,7 +102,7 @@ def test_complex_nested_toc parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_2) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                    +
                                    • h1
                                        @@ -126,7 +126,7 @@ def test_decremental_headings1 parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_3) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                          +
                                          • h6
                                          • h5
                                          • h4
                                          • @@ -144,7 +144,7 @@ def test_decremental_headings2 parser = Jekyll::TableOfContents::Parser.new(TEST_HTML_4) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                              +
                                              • h1
                                                  @@ -172,7 +172,7 @@ def test_no_toc parser = Jekyll::TableOfContents::Parser.new(NO_TOC_HTML) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                                    +
                                                    • h1
                                                        @@ -200,7 +200,7 @@ def test_japanese_toc parser = Jekyll::TableOfContents::Parser.new(JAPANESE_HEADINGS_HTML) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                                          +
                                                            • @@ -223,7 +223,7 @@ def test_angle_bracket parser = Jekyll::TableOfContents::Parser.new(ANGLE_BRACKET_HTML) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                                                +
                                                                • h1
                                                                • <base href>
                                                                • & < >
                                                                • @@ -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 -
                                                                    + @@ -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 -
                                                                      +
                                                                      • h1
                                                                          @@ -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{

                                                                          .+

                                                                          }m, html) - assert_match(%r{

                                                                          .+

                                                                          }m, html) - assert_match(%r{
                                                                          .+
                                                                          }m, html) + assert_match(%r{

                                                                          .+

                                                                          }m, html) + assert_match(%r{

                                                                          .+

                                                                          }m, html) + assert_match(%r{
                                                                          .+
                                                                          }m, html) assert_includes(html, '

                                                                          h2

                                                                          ') end @@ -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 -
                                                                            +
                                                                            • h1
                                                                                @@ -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{

                                                                                .+

                                                                                }m, html) - assert_match(%r{

                                                                                .+

                                                                                }m, html) - assert_match(%r{
                                                                                .+
                                                                                }m, html) + assert_match(%r{

                                                                                .+

                                                                                }m, html) + assert_match(%r{

                                                                                .+

                                                                                }m, html) + assert_match(%r{
                                                                                .+
                                                                                }m, html) assert_includes(html, '

                                                                                h2

                                                                                ') assert_includes(html, '

                                                                                h4

                                                                                ') assert_includes(html, '
                                                                                h5
                                                                                ') @@ -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 -
                                                                                  +
                                                                                  • h1
                                                                                      @@ -363,9 +363,9 @@ def test_multiple_no_toc_section_classes assert_equal(expected, actual) html = parser.inject_anchors_into_html - assert_match(%r{

                                                                                      .+

                                                                                      }m, html) - assert_match(%r{

                                                                                      .+

                                                                                      }m, html) - assert_match(%r{
                                                                                      .+
                                                                                      }m, html) + assert_match(%r{

                                                                                      .+

                                                                                      }m, html) + assert_match(%r{

                                                                                      .+

                                                                                      }m, html) + assert_match(%r{
                                                                                      .+
                                                                                      }m, html) assert_includes(html, '

                                                                                      h2

                                                                                      ') assert_includes(html, '

                                                                                      h4

                                                                                      ') assert_includes(html, '
                                                                                      h5
                                                                                      ') @@ -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 -
                                                                                        +
                                                                                        • h1
                                                                                        • h2
                                                                                        • h3
                                                                                        • @@ -406,7 +406,7 @@ def test_anchor_is_uniq parser = Jekyll::TableOfContents::Parser.new(TEST_UNIQ_ID) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                                                                            +
                                                                                            • h1
                                                                                            • h1
                                                                                            • h1
                                                                                            • @@ -423,7 +423,7 @@ def test_custom_css_classes ) doc = Nokogiri::HTML(parser.toc) expected = <<~HTML -
                                                                                                +
                                                                                                • h1
                                                                                                    diff --git a/test/test_jekyll-toc.rb b/test/test_jekyll-toc.rb index 34fed46..cfdf9c2 100644 --- a/test/test_jekyll-toc.rb +++ b/test/test_jekyll-toc.rb @@ -24,7 +24,7 @@ def test_toc def test_toc_only2 @context = enable_toc_context - assert_equal "
                                                                                                      \n
                                                                                                    ", toc_only(DUMMY_HTML) + assert_equal "
                                                                                                      \n
                                                                                                    ", toc_only(DUMMY_HTML) end def test_inject_anchors2 @@ -34,7 +34,7 @@ def test_inject_anchors2 def test_toc2 @context = enable_toc_context - assert_equal "
                                                                                                      \n
                                                                                                    #{DUMMY_HTML}", toc(DUMMY_HTML) + assert_equal "
                                                                                                      \n
                                                                                                    #{DUMMY_HTML}", toc(DUMMY_HTML) end private From bf32752bd2670c54ea2fe0afc404dcfe9a19a37f Mon Sep 17 00:00:00 2001 From: "whitesource-bolt-for-github[bot]" <42819689+whitesource-bolt-for-github[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2020 02:45:13 +0000 Subject: [PATCH 105/112] Add .whitesource configuration file --- .whitesource | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .whitesource diff --git a/.whitesource b/.whitesource new file mode 100644 index 0000000..e0aaa3e --- /dev/null +++ b/.whitesource @@ -0,0 +1,8 @@ +{ + "checkRunSettings": { + "vulnerableCheckRunConclusionLevel": "failure" + }, + "issueSettings": { + "minSeverityLevel": "LOW" + } +} \ No newline at end of file From 6ff175af4c8c3700de0336397fa5f778cc3cdbe5 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 05:16:48 +0200 Subject: [PATCH 106/112] Update Gem Specs to n13.org --- jekyll-toc.gemspec | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index c687805..a5ac286 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -5,14 +5,14 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'version' Gem::Specification.new do |spec| - spec.name = 'jekyll-toc' + spec.name = 'jekyll-toc-navtotop' spec.version = JekyllToc::VERSION - spec.summary = 'Jekyll Table of Contents plugin' - spec.description = 'Jekyll (Ruby static website generator) plugin which generates a table of contents.' - spec.authors = %w(toshimaru torbjoernk) - spec.email = 'me@toshimaru.net' + spec.summary = 'Jekyll Table of Contents plugin with navigation to top' + spec.description = 'Jekyll (Ruby static website generator) plugin which generates a table of contents and a navigation to top.' + spec.authors = ["n13.org", "KargWare", "N7K4", "toshimaru torbjoernk"] + spec.email = 'rubygems.org@n13.org' spec.files = `git ls-files -z`.split("\x0") - spec.homepage = 'https://github.com/toshimaru/jekyll-toc' + spec.homepage = 'https://github.com/n13org/jekyll-toc-navtotop' spec.license = 'MIT' spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] From 66309ad71c90fe3bae0939835eda58b32a959d0d Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 07:00:59 +0200 Subject: [PATCH 107/112] Delete jekyll_3.6.gemfile only jekyll_4.0 stays --- gemfiles/jekyll_3.6.gemfile | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 gemfiles/jekyll_3.6.gemfile diff --git a/gemfiles/jekyll_3.6.gemfile b/gemfiles/jekyll_3.6.gemfile deleted file mode 100644 index 510edb0..0000000 --- a/gemfiles/jekyll_3.6.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "jekyll", "3.6" - -gemspec path: "../" From e7000f7d1b7e002b98ad5a2a5c1685ad09058dd3 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 07:01:15 +0200 Subject: [PATCH 108/112] Delete jekyll_3.7.gemfile only jekyll_4.0 stays --- gemfiles/jekyll_3.7.gemfile | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 gemfiles/jekyll_3.7.gemfile diff --git a/gemfiles/jekyll_3.7.gemfile b/gemfiles/jekyll_3.7.gemfile deleted file mode 100644 index c551ac2..0000000 --- a/gemfiles/jekyll_3.7.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "jekyll", "3.7" - -gemspec path: "../" From ebe1deeb1b6f660396adbd14b35e0261606a5c51 Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 07:01:27 +0200 Subject: [PATCH 109/112] Delete jekyll_3.8.gemfile only jekyll_4.0 stays --- gemfiles/jekyll_3.8.gemfile | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 gemfiles/jekyll_3.8.gemfile diff --git a/gemfiles/jekyll_3.8.gemfile b/gemfiles/jekyll_3.8.gemfile deleted file mode 100644 index 32635d8..0000000 --- a/gemfiles/jekyll_3.8.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "jekyll", "3.8" - -gemspec path: "../" From 153a41ee0cb4405b7a0d5699c234d07bc7b9b01d Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 07:13:30 +0200 Subject: [PATCH 110/112] Move include inside the module --- lib/table_of_contents/parser.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 3a2cf98..59d34b2 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -include ERB::Util # Jekyll Modul, the root of everything module Jekyll # Module to wrap the classes for TOC creation From e910a1ee14c9f314f439f95b62850637e8631daa Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 08:34:04 +0200 Subject: [PATCH 111/112] Resolve conflicts --- Appraisals | 10 +- LICENSE.md | 2 +- README.md | 516 +++++++++++----------- jekyll-toc.gemspec | 66 +-- lib/table_of_contents/parser.rb | 290 ++++++------ lib/version.rb | 10 +- test/parser/test_inject_anchors_filter.rb | 46 +- test/parser/test_toc_filter.rb | 72 +-- 8 files changed, 506 insertions(+), 506 deletions(-) diff --git a/Appraisals b/Appraisals index 0d96b2b..049a0a8 100644 --- a/Appraisals +++ b/Appraisals @@ -1,5 +1,5 @@ -# frozen_string_literal: true - -appraise 'jekyll-4.0' do - gem 'jekyll', '4.0' -end +# frozen_string_literal: true + +appraise 'jekyll-4.0' do + gem 'jekyll', '4.0' +end diff --git a/LICENSE.md b/LICENSE.md index 5763175..d27c0bd 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2020 Toshimaru +Copyright (c) 2020 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 5844b86..e8cdf60 100644 --- a/README.md +++ b/README.md @@ -1,258 +1,258 @@ -# jekyll-toc - -![CI](https://github.com/n13org/jekyll-toc-navtotop/workflows/CI/badge.svg) -[![Gem Version](https://badge.fury.io/rb/jekyll-toc-navtotop.svg)](http://badge.fury.io/rb/jekyll-toc-navtotop) -[![Code Climate](https://codeclimate.com/github/n13org/jekyll-toc-navtotop/badges/gpa.svg)](https://codeclimate.com/github/n13org/jekyll-toc-navtotop) - - -## Table of Contents - -- [Installation](#installation) -- [Usage](#usage) - - [1. Basic Usage](#1-basic-usage) - - [2. Advanced Usage](#2-advanced-usage) -- [Generated HTML](#generated-html) -- [Default Configuration](#default-configuration) -- [Customization](#customization) - - [TOC levels](#toc-levels) - - [Skip TOC](#skip-toc) - - [Skip TOC Section](#skip-toc-section) - - [CSS Styling](#css-styling) - - [Custom CSS Class](#custom-css-class) - -## Installation - -Add jekyll-toc plugin in your site's `Gemfile`, and run `bundle install`. - -```ruby -gem 'jekyll-toc' -``` - -Add jekyll-toc to the `gems:` section in your site's `_config.yml`. - -```yml -plugins: - - jekyll-toc -``` - -Set `toc: true` in posts for which you want the TOC to appear. - -```yml ---- -layout: post -title: "Welcome to Jekyll!" -toc: true ---- -``` - -## Usage - -There are three Liquid filters, which can be applied to HTML content, -e.g. the Liquid variable `content` available in Jekyll's templates. - -### 1. Basic Usage - -#### `toc` filter - -Add the `toc` filter to your site's `{{ content }}` (e.g. `_layouts/post.html`). - -```liquid -{{ content | toc }} -``` - -This filter places the TOC directly above the content. - -### 2. Advanced Usage - -If you'd like separated TOC and content, you can use `{% toc %}` tag (or `toc_only` filter) and `inject_anchors` filter. - -### `toc_only` filter - -⚠️ ~~Please use `{% toc %}` instead of `{{ content | toc_only }}`.~~ - -Generates the TOC itself as described [below](#generated-html). -Mostly useful in cases where the TOC should _not_ be placed immediately -above the content but at some other place of the page, i.e. an aside. - -```html -
                                                                                                    -
                                                                                                    - {% toc %} -
                                                                                                    -
                                                                                                    - {{ content }} -
                                                                                                    -
                                                                                                    -``` - -:warning: **`{% toc %}` Tag Limitation** -#### Current Limitation -`{% toc %}` can be available only in [Jekyll Posts](https://jekyllrb.com/docs/step-by-step/08-blogging/) and [Jekyll Collections](https://jekyllrb.com/docs/collections/). If you'd like to use `{% toc %}` except posts or collections, please use `toc_only` filter as described below. -**`{% toc %}` can be available only in [Jekyll Posts](https://jekyllrb.com/docs/step-by-step/08-blogging/) and [Jekyll Collections](https://jekyllrb.com/docs/collections/). If any concern or issue, please report it on [issue](https://github.com/toshimaru/jekyll-toc/issues/new).** -```html -
                                                                                                    -
                                                                                                    - {{ content | toc_only }} -
                                                                                                    -
                                                                                                    - {{ content | inject_anchors }} -
                                                                                                    -
                                                                                                    -``` - -#### `inject_anchors` filter - -Injects HTML anchors into the content without actually outputting the TOC itself. -They are of the form: - -```html - -``` - -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. - -```html - -``` - -![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) - -## Default Configuration - -```yml -toc: - min_level: 1 - max_level: 6 - no_toc_section_class: no_toc_section - list_class: section-nav - sublist_class: '' - item_class: toc-entry - item_prefix: toc- - anchor_id_url_encoded: false -``` - -## Customization - -### TOC levels - -The toc levels can be configured on `_config.yml`: - -```yml -toc: - min_level: 2 # default: 1 - max_level: 5 # default: 6 -``` - -The default level range is `

                                                                                                    ` to `

                                                                                                    `. - -### Skip TOC - -The heading is ignored in the toc when you add `no_toc` to the class. - -```html -

                                                                                                    h1

                                                                                                    -

                                                                                                    This heading is ignored in the toc

                                                                                                    -

                                                                                                    h2

                                                                                                    -``` - -### Skip TOC Section - -The headings are ignored inside the element which has `no_toc_section` class. - -```html -

                                                                                                    h1

                                                                                                    -
                                                                                                    -

                                                                                                    This heading is ignored in the toc

                                                                                                    -

                                                                                                    This heading is ignored in the toc

                                                                                                    -
                                                                                                    -

                                                                                                    h4

                                                                                                    -``` - -Which would result in only the `

                                                                                                    ` & `

                                                                                                    ` within the example being included in the TOC. - -The class can be configured on `_config.yml`: - -```yml -toc: - no_toc_section_class: exclude # default: no_toc_section -``` - -Configuring multiple classes for `no_toc_section_class` is allowed: - -```yml -toc: - no_toc_section_class: - - no_toc_section - - exclude - - your_custom_skip_class_name -``` - -### CSS Styling - -The toc can be modified with CSS. The sample CSS is the following. - -```css -.section-nav { - background-color: #fff; - margin: 5px 0; - padding: 10px 30px; - border: 1px solid #e8e8e8; - border-radius: 3px; -} -``` - -![screenshot](https://user-images.githubusercontent.com/803398/28401455-0ba60868-6d55-11e7-8159-0ae7591aee66.png) - -Each TOC `li` entry has two CSS classes for further styling. The general `toc-entry` is applied to all `li` elements in the `ul.section-nav`. - -Depending on the heading level each specific entry refers to, it has a second CSS class `toc-XX`, where `XX` is the HTML heading tag name. For example, the TOC entry linking to a heading `

                                                                                                    ...

                                                                                                    ` (a single -`#` in Markdown) will get the CSS class `toc-h1`. - -### Custom CSS Class - -You can apply custom CSS classes to the generated `
                                                                                                      ` and `
                                                                                                    • ` tags. - -```yml -toc: - # Default is "section-nav": - list_class: my-list-class - # Default is no class for sublists: - sublist_class: my-sublist-class - # Default is "toc-entry": - item_class: my-item-class - # Default is "toc-": - item_prefix: item- -``` +# jekyll-toc + +![CI](https://github.com/n13org/jekyll-toc-navtotop/workflows/CI/badge.svg) +[![Gem Version](https://badge.fury.io/rb/jekyll-toc-navtotop.svg)](http://badge.fury.io/rb/jekyll-toc-navtotop) +[![Code Climate](https://codeclimate.com/github/n13org/jekyll-toc-navtotop/badges/gpa.svg)](https://codeclimate.com/github/n13org/jekyll-toc-navtotop) + + +## Table of Contents + +- [Installation](#installation) +- [Usage](#usage) + - [1. Basic Usage](#1-basic-usage) + - [2. Advanced Usage](#2-advanced-usage) +- [Generated HTML](#generated-html) +- [Default Configuration](#default-configuration) +- [Customization](#customization) + - [TOC levels](#toc-levels) + - [Skip TOC](#skip-toc) + - [Skip TOC Section](#skip-toc-section) + - [CSS Styling](#css-styling) + - [Custom CSS Class](#custom-css-class) + +## Installation + +Add jekyll-toc plugin in your site's `Gemfile`, and run `bundle install`. + +```ruby +gem 'jekyll-toc' +``` + +Add jekyll-toc to the `gems:` section in your site's `_config.yml`. + +```yml +plugins: + - jekyll-toc +``` + +Set `toc: true` in posts for which you want the TOC to appear. + +```yml +--- +layout: post +title: "Welcome to Jekyll!" +toc: true +--- +``` + +## Usage + +There are three Liquid filters, which can be applied to HTML content, +e.g. the Liquid variable `content` available in Jekyll's templates. + +### 1. Basic Usage + +#### `toc` filter + +Add the `toc` filter to your site's `{{ content }}` (e.g. `_layouts/post.html`). + +```liquid +{{ content | toc }} +``` + +This filter places the TOC directly above the content. + +### 2. Advanced Usage + +If you'd like separated TOC and content, you can use `{% toc %}` tag (or `toc_only` filter) and `inject_anchors` filter. + +### `toc_only` filter + +⚠️ ~~Please use `{% toc %}` instead of `{{ content | toc_only }}`.~~ + +Generates the TOC itself as described [below](#generated-html). +Mostly useful in cases where the TOC should _not_ be placed immediately +above the content but at some other place of the page, i.e. an aside. + +```html +
                                                                                                      +
                                                                                                      + {% toc %} +
                                                                                                      +
                                                                                                      + {{ content }} +
                                                                                                      +
                                                                                                      +``` + +:warning: **`{% toc %}` Tag Limitation** +#### Current Limitation +`{% toc %}` can be available only in [Jekyll Posts](https://jekyllrb.com/docs/step-by-step/08-blogging/) and [Jekyll Collections](https://jekyllrb.com/docs/collections/). If you'd like to use `{% toc %}` except posts or collections, please use `toc_only` filter as described below. +**`{% toc %}` can be available only in [Jekyll Posts](https://jekyllrb.com/docs/step-by-step/08-blogging/) and [Jekyll Collections](https://jekyllrb.com/docs/collections/). If any concern or issue, please report it on [issue](https://github.com/toshimaru/jekyll-toc/issues/new).** +```html +
                                                                                                      +
                                                                                                      + {{ content | toc_only }} +
                                                                                                      +
                                                                                                      + {{ content | inject_anchors }} +
                                                                                                      +
                                                                                                      +``` + +#### `inject_anchors` filter + +Injects HTML anchors into the content without actually outputting the TOC itself. +They are of the form: + +```html + +``` + +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. + +```html + +``` + +![screenshot](https://user-images.githubusercontent.com/803398/28401295-0dcfb7ca-6d54-11e7-892b-2f2e6ca755a7.png) + +## Default Configuration + +```yml +toc: + min_level: 1 + max_level: 6 + no_toc_section_class: no_toc_section + list_class: section-nav + sublist_class: '' + item_class: toc-entry + item_prefix: toc- + anchor_id_url_encoded: false +``` + +## Customization + +### TOC levels + +The toc levels can be configured on `_config.yml`: + +```yml +toc: + min_level: 2 # default: 1 + max_level: 5 # default: 6 +``` + +The default level range is `

                                                                                                      ` to `

                                                                                                      `. + +### Skip TOC + +The heading is ignored in the toc when you add `no_toc` to the class. + +```html +

                                                                                                      h1

                                                                                                      +

                                                                                                      This heading is ignored in the toc

                                                                                                      +

                                                                                                      h2

                                                                                                      +``` + +### Skip TOC Section + +The headings are ignored inside the element which has `no_toc_section` class. + +```html +

                                                                                                      h1

                                                                                                      +
                                                                                                      +

                                                                                                      This heading is ignored in the toc

                                                                                                      +

                                                                                                      This heading is ignored in the toc

                                                                                                      +
                                                                                                      +

                                                                                                      h4

                                                                                                      +``` + +Which would result in only the `

                                                                                                      ` & `

                                                                                                      ` within the example being included in the TOC. + +The class can be configured on `_config.yml`: + +```yml +toc: + no_toc_section_class: exclude # default: no_toc_section +``` + +Configuring multiple classes for `no_toc_section_class` is allowed: + +```yml +toc: + no_toc_section_class: + - no_toc_section + - exclude + - your_custom_skip_class_name +``` + +### CSS Styling + +The toc can be modified with CSS. The sample CSS is the following. + +```css +.section-nav { + background-color: #fff; + margin: 5px 0; + padding: 10px 30px; + border: 1px solid #e8e8e8; + border-radius: 3px; +} +``` + +![screenshot](https://user-images.githubusercontent.com/803398/28401455-0ba60868-6d55-11e7-8159-0ae7591aee66.png) + +Each TOC `li` entry has two CSS classes for further styling. The general `toc-entry` is applied to all `li` elements in the `ul.section-nav`. + +Depending on the heading level each specific entry refers to, it has a second CSS class `toc-XX`, where `XX` is the HTML heading tag name. For example, the TOC entry linking to a heading `

                                                                                                      ...

                                                                                                      ` (a single +`#` in Markdown) will get the CSS class `toc-h1`. + +### Custom CSS Class + +You can apply custom CSS classes to the generated `
                                                                                                        ` and `
                                                                                                      • ` tags. + +```yml +toc: + # Default is "section-nav": + list_class: my-list-class + # Default is no class for sublists: + sublist_class: my-sublist-class + # Default is "toc-entry": + item_class: my-item-class + # Default is "toc-": + item_prefix: item- +``` diff --git a/jekyll-toc.gemspec b/jekyll-toc.gemspec index 6f18ff4..97c6c8c 100644 --- a/jekyll-toc.gemspec +++ b/jekyll-toc.gemspec @@ -1,33 +1,33 @@ -# frozen_string_literal: true - -lib = File.expand_path('../lib', __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'version' - -Gem::Specification.new do |spec| - spec.name = 'jekyll-toc-navtotop' - spec.version = JekyllToc::VERSION - spec.summary = 'Jekyll Table of Contents plugin with navigation to top' - spec.description = 'Jekyll (Ruby static website generator) plugin which generates a table of contents and a navigation to top.' - spec.authors = ["n13.org", "KargWare", "N7K4", "toshimaru torbjoernk"] - spec.email = 'rubygems.org@n13.org' - spec.files = `git ls-files -z`.split("\x0") - spec.homepage = 'https://github.com/n13org/jekyll-toc-navtotop' - spec.license = 'MIT' - spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) - spec.require_paths = ['lib'] - - spec.required_ruby_version = '>= 2.1.0' - - spec.add_runtime_dependency 'nokogiri', '~> 1.9' - - spec.add_development_dependency 'appraisal' - spec.add_development_dependency 'jekyll', '>= 3.5' - spec.add_development_dependency 'minitest', '~> 5.11' - spec.add_development_dependency 'minitest-reporters' - spec.add_development_dependency 'pry' - spec.add_development_dependency 'rake' - spec.add_development_dependency 'rubocop' - spec.add_development_dependency 'simplecov' - -end +# frozen_string_literal: true + +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'version' + +Gem::Specification.new do |spec| + spec.name = 'jekyll-toc-navtotop' + spec.version = JekyllToc::VERSION + spec.summary = 'Jekyll Table of Contents plugin with navigation to top' + spec.description = 'Jekyll (Ruby static website generator) plugin which generates a table of contents and a navigation to top.' + spec.authors = ["n13.org", "KargWare", "N7K4", "toshimaru torbjoernk"] + spec.email = 'rubygems.org@n13.org' + spec.files = `git ls-files -z`.split("\x0") + spec.homepage = 'https://github.com/n13org/jekyll-toc-navtotop' + spec.license = 'MIT' + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ['lib'] + + spec.required_ruby_version = '>= 2.1.0' + + spec.add_runtime_dependency 'nokogiri', '~> 1.9' + + spec.add_development_dependency 'appraisal' + spec.add_development_dependency 'jekyll', '>= 3.5' + spec.add_development_dependency 'minitest', '~> 5.11' + spec.add_development_dependency 'minitest-reporters' + spec.add_development_dependency 'pry' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'rubocop' + spec.add_development_dependency 'simplecov' + +end diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb index 59d34b2..1f6d419 100644 --- a/lib/table_of_contents/parser.rb +++ b/lib/table_of_contents/parser.rb @@ -1,145 +1,145 @@ -# frozen_string_literal: true - -# 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.freeze - - def initialize(html, options = {}) - @doc = Nokogiri::HTML::DocumentFragment.parse(html) - @configuration = Configuration.new(options) - @entries = parse_content - end - - def toc - build_toc + inject_anchors_into_html - end - - def build_toc - %(
                                                                                                          \n#{build_toc_list(@entries, last_ul_used: true)}
                                                                                                        ) - end - - def inject_anchors_into_html - @entries.each do |entry| - # 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( - %() - ) - - # 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( - %() - ) - end - - @doc.inner_html - end - - private - - # parse logic is from html-pipeline toc_filter - # https://github.com/jch/html-pipeline/blob/v1.1.0/lib/html/pipeline/toc_filter.rb - def parse_content - headers = Hash.new(0) - - (@doc.css(toc_headings) - @doc.css(toc_headings_in_no_toc_section)) - .reject { |n| n.classes.include?(@configuration.no_toc_class) } - .inject([]) do |entries, node| - text = node.text - id = node.attribute('id') || text - .downcase - .gsub(PUNCTUATION_REGEXP, '') # remove punctuation - .tr(' ', '-') # replace spaces with dash - if (@configuration.anchor_id_url_encoded) - id = url_encode(id) - end - - suffix_num = headers[id] - headers[id] += 1 - - entries << { - 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 - } - end - end - - # Returns the list items for entries - def build_toc_list(entries) - i = 0 - toc_list = +'' - min_h_num = entries.map { |e| e[:h_num] }.min - - while i < entries.count - entry = entries[i] - if entry[:h_num] == min_h_num - # If the current entry should not be indented in the list, add the entry to the list - toc_list << %(
                                                                                                      • #{entry[:text]}) - # If the next entry should be indented in the list, generate a sublist - next_i = i + 1 - if next_i < entries.count && entries[next_i][:h_num] > min_h_num - nest_entries = get_nest_entries(entries[next_i, entries.count], min_h_num) - toc_list << %(\n\n#{build_toc_list(nest_entries)}
                                                                                                      \n) - i += nest_entries.count - end - # Add the closing tag for the current entry in the list - toc_list << %(
                                                                                                    • \n) - elsif entry[:h_num] > min_h_num - # If the current entry should be indented in the list, generate a sublist - nest_entries = get_nest_entries(entries[i, entries.count], min_h_num) - toc_list << build_toc_list(nest_entries) - i += nest_entries.count - 1 - end - i += 1 - end - - toc_list - end - - # Returns the entries in a nested list - # The nested list starts at the first entry in entries (inclusive) - # The nested list ends at the first entry in entries with depth min_h_num or greater (exclusive) - def get_nest_entries(entries, min_h_num) - entries.inject([]) do |nest_entries, entry| - break nest_entries if entry[:h_num] == min_h_num - - nest_entries << entry - end - end - - def toc_headings - @configuration.toc_levels.map { |level| "h#{level}" }.join(',') - end - - def toc_headings_in_no_toc_section - if @configuration.no_toc_section_class.is_a? Array - @configuration.no_toc_section_class.map { |cls| toc_headings_within(cls) }.join(',') - else - toc_headings_within(@configuration.no_toc_section_class) - end - end - - def toc_headings_within(class_name) - @configuration.toc_levels.map { |level| ".#{class_name} h#{level}" }.join(',') - end - - def ul_attributes - @ul_attributes ||= @configuration.sublist_class.empty? ? '' : %( class="#{@configuration.sublist_class}") - end - end - end -end +# frozen_string_literal: true + +# 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.freeze + + def initialize(html, options = {}) + @doc = Nokogiri::HTML::DocumentFragment.parse(html) + @configuration = Configuration.new(options) + @entries = parse_content + end + + def toc + build_toc + inject_anchors_into_html + end + + def build_toc + %(
                                                                                                        \n#{build_toc_list(@entries, last_ul_used: true)}
                                                                                                      ) + end + + def inject_anchors_into_html + @entries.each do |entry| + # 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( + %() + ) + + # 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( + %() + ) + end + + @doc.inner_html + end + + private + + # parse logic is from html-pipeline toc_filter + # https://github.com/jch/html-pipeline/blob/v1.1.0/lib/html/pipeline/toc_filter.rb + def parse_content + headers = Hash.new(0) + + (@doc.css(toc_headings) - @doc.css(toc_headings_in_no_toc_section)) + .reject { |n| n.classes.include?(@configuration.no_toc_class) } + .inject([]) do |entries, node| + text = node.text + id = node.attribute('id') || text + .downcase + .gsub(PUNCTUATION_REGEXP, '') # remove punctuation + .tr(' ', '-') # replace spaces with dash + if (@configuration.anchor_id_url_encoded) + id = url_encode(id) + end + + suffix_num = headers[id] + headers[id] += 1 + + entries << { + 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 + } + end + end + + # Returns the list items for entries + def build_toc_list(entries) + i = 0 + toc_list = +'' + min_h_num = entries.map { |e| e[:h_num] }.min + + while i < entries.count + entry = entries[i] + if entry[:h_num] == min_h_num + # If the current entry should not be indented in the list, add the entry to the list + toc_list << %(
                                                                                                    • #{entry[:text]}) + # If the next entry should be indented in the list, generate a sublist + next_i = i + 1 + if next_i < entries.count && entries[next_i][:h_num] > min_h_num + nest_entries = get_nest_entries(entries[next_i, entries.count], min_h_num) + toc_list << %(\n\n#{build_toc_list(nest_entries)}
                                                                                                    \n) + i += nest_entries.count + end + # Add the closing tag for the current entry in the list + toc_list << %(\n) + elsif entry[:h_num] > min_h_num + # If the current entry should be indented in the list, generate a sublist + nest_entries = get_nest_entries(entries[i, entries.count], min_h_num) + toc_list << build_toc_list(nest_entries) + i += nest_entries.count - 1 + end + i += 1 + end + + toc_list + end + + # Returns the entries in a nested list + # The nested list starts at the first entry in entries (inclusive) + # The nested list ends at the first entry in entries with depth min_h_num or greater (exclusive) + def get_nest_entries(entries, min_h_num) + entries.inject([]) do |nest_entries, entry| + break nest_entries if entry[:h_num] == min_h_num + + nest_entries << entry + end + end + + def toc_headings + @configuration.toc_levels.map { |level| "h#{level}" }.join(',') + end + + def toc_headings_in_no_toc_section + if @configuration.no_toc_section_class.is_a? Array + @configuration.no_toc_section_class.map { |cls| toc_headings_within(cls) }.join(',') + else + toc_headings_within(@configuration.no_toc_section_class) + end + end + + def toc_headings_within(class_name) + @configuration.toc_levels.map { |level| ".#{class_name} h#{level}" }.join(',') + end + + def ul_attributes + @ul_attributes ||= @configuration.sublist_class.empty? ? '' : %( class="#{@configuration.sublist_class}") + end + end + end +end diff --git a/lib/version.rb b/lib/version.rb index 6a935cf..f9292c0 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -1,5 +1,5 @@ -# frozen_string_literal: true - -module JekyllToc - VERSION = '0.13.1' -end +# frozen_string_literal: true + +module JekyllToc + VERSION = '0.13.1' +end diff --git a/test/parser/test_inject_anchors_filter.rb b/test/parser/test_inject_anchors_filter.rb index 8c55aa0..9228a90 100644 --- a/test/parser/test_inject_anchors_filter.rb +++ b/test/parser/test_inject_anchors_filter.rb @@ -1,23 +1,23 @@ -# frozen_string_literal: true - -require 'test_helper' - -class TestInjectAnchorsFilter < Minitest::Test - include TestHelpers - - def setup - read_html_and_create_parser - end - - def test_injects_anchors_into_content - html = @parser.inject_anchors_into_html - - assert_match(%r{}, html) - end - - def test_does_not_inject_toc - html = @parser.inject_anchors_into_html - - assert_nil(/
                                                                                                      / =~ html) - end -end +# frozen_string_literal: true + +require 'test_helper' + +class TestInjectAnchorsFilter < Minitest::Test + include TestHelpers + + def setup + read_html_and_create_parser + end + + def test_injects_anchors_into_content + html = @parser.inject_anchors_into_html + + assert_match(%r{}, html) + end + + def test_does_not_inject_toc + html = @parser.inject_anchors_into_html + + assert_nil(/
                                                                                                        / =~ html) + end +end diff --git a/test/parser/test_toc_filter.rb b/test/parser/test_toc_filter.rb index 5d44b90..4081b72 100644 --- a/test/parser/test_toc_filter.rb +++ b/test/parser/test_toc_filter.rb @@ -1,36 +1,36 @@ -# frozen_string_literal: true - -require 'test_helper' - -class TestTOCFilter < Minitest::Test - include TestHelpers - - def setup - read_html_and_create_parser - end - - def test_injects_anchors - html = @parser.toc - - assert_match(%r{}, html) - end - - def test_nested_toc - doc = Nokogiri::HTML(@parser.toc) - nested_h6_text = doc.css('ul.section-nav') - .css('li.toc-h1') - .css('li.toc-h2') - .css('li.toc-h3') - .css('li.toc-h4') - .css('li.toc-h5') - .css('li.toc-h6') - .text - assert_equal('Simple H6', nested_h6_text) - end - - def test_injects_toc_container - html = @parser.toc - - assert_match(/
                                                                                                          /, html) - end -end +# frozen_string_literal: true + +require 'test_helper' + +class TestTOCFilter < Minitest::Test + include TestHelpers + + def setup + read_html_and_create_parser + end + + def test_injects_anchors + html = @parser.toc + + assert_match(%r{}, html) + end + + def test_nested_toc + doc = Nokogiri::HTML(@parser.toc) + nested_h6_text = doc.css('ul.section-nav') + .css('li.toc-h1') + .css('li.toc-h2') + .css('li.toc-h3') + .css('li.toc-h4') + .css('li.toc-h5') + .css('li.toc-h6') + .text + assert_equal('Simple H6', nested_h6_text) + end + + def test_injects_toc_container + html = @parser.toc + + assert_match(/
                                                                                                            /, html) + end +end From 2ab708cebedbdcb8527734586b7d78be25e0437e Mon Sep 17 00:00:00 2001 From: Nicolas Karg <50399433+N7K4@users.noreply.github.com> Date: Tue, 28 Apr 2020 08:35:31 +0200 Subject: [PATCH 112/112] Drop support for jekyll v3.0 --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bf76132..a360a55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,8 +7,6 @@ jobs: ruby: [2.4, 2.5, 2.6, 2.7] gemfile: - gemfiles/jekyll_4.0.gemfile - - gemfiles/jekyll_3.8.gemfile - - gemfiles/jekyll_3.7.gemfile exclude: - ruby: 2.4 gemfile: gemfiles/jekyll_4.0.gemfile