diff --git a/.travis.yml b/.travis.yml
index 912323b..3b1ba50 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,8 +5,9 @@ rvm:
- 2.2
- 2.3.1
- 2.4.0
-# Put this in your .travis.yml
+# gemfile is generated by appraisal
gemfile:
+ - gemfiles/jekyll_3.4.gemfile
- gemfiles/jekyll_3.3.gemfile
- gemfiles/jekyll_3.2.gemfile
- gemfiles/jekyll_3.1.gemfile
diff --git a/README.md b/README.md
index cbaa1c6..a1992fb 100644
--- a/README.md
+++ b/README.md
@@ -37,19 +37,19 @@ There are three Liquid filters available now, which all should be applied
to some HTML content, e.g. the Liquid variable `content` available in
Jekyll's templates.
-## Basic Usage
+## 1. Basic Usage
### `toc` filter
Add `toc` filter to your site's `{{ content }}` (e.g. `_layouts/post.html`).
-```
+```liquid
{{ content | toc }}
```
This filter places the TOC directly above the content.
-## Advanced Usage
+## 2. Advanced Usage
If you'd like separated TOC and content, you can use `toc_only` and `inject_anchors` filters.
diff --git a/lib/table_of_contents/parser.rb b/lib/table_of_contents/parser.rb
index 34b149f..17e9795 100644
--- a/lib/table_of_contents/parser.rb
+++ b/lib/table_of_contents/parser.rb
@@ -1,7 +1,8 @@
module Jekyll
module TableOfContents
+ # Parse html contents and generate table of contents
class Parser
- PUNCTUATION_REGEXP = RUBY_VERSION > '1.9' ? /[^\p{Word}\- ]/u : /[^\w\- ]/
+ PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u
attr_reader :doc
@@ -11,11 +12,11 @@ def initialize(html)
end
def build_toc
- toc = %Q{
\n}
+ toc = %(\n)
min_h_num = 6
@entries.each do |entry|
- h_num = entry[:node_name].delete("h").to_i
+ h_num = entry[:node_name].delete('h').to_i
min_h_num = [min_h_num, h_num].min
end
toc << build_lis(@entries, min_h_num)
@@ -23,42 +24,81 @@ def build_toc
toc << '
'
end
+ def inject_anchors_into_html
+ @entries.each do |entry|
+ entry[:content_node].add_previous_sibling(%())
+ end
+
+ @doc.inner_html
+ end
+
+ def toc
+ build_toc + inject_anchors_into_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
+ entries = []
+ headers = Hash.new(0)
+
+ @doc.css('h1, h2, h3, h4, h5, h6').each do |node|
+ text = node.text
+ id = text.downcase
+ id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
+ id.gsub!(' ', '-') # replace spaces with dash
+
+ uniq = headers[id] > 0 ? "-#{headers[id]}" : ''
+ headers[id] += 1
+ header_content = node.children.first
+ next unless header_content
+
+ entries << {
+ id: id,
+ uniq: uniq,
+ text: text,
+ node_name: node.name,
+ content_node: header_content
+ }
+ end
+
+ entries
+ end
+
# Returns the list items for entries
def build_lis(entries, min_h_num)
- lis = ""
+ lis = ''
i = 0
- while i < entries.length do
+ while i < entries.length
entry = entries[i]
- curr_h_num = entry[:node_name].delete("h").to_i
+ curr_h_num = entry[:node_name].delete('h').to_i
if curr_h_num == min_h_num
-
# If the current entry should not be indented in the list, add the entry to the list
- lis << %Q{- #{entry[:text]}}
+ lis << %(
- #{entry[:text]})
# If the next entry should be indented in the list, generate a sublist
if i + 1 < entries.length
next_entry = entries[i + 1]
- next_h_num = next_entry[:node_name].delete("h").to_i
+ next_h_num = next_entry[:node_name].delete('h').to_i
if next_h_num > min_h_num
- lis << %Q{\n}
- lis << %Q{
\n}
+ lis << %(\n)
+ lis << %(\n)
nest_entries = get_nest_entries(entries[i + 1, entries.length], min_h_num)
lis << build_lis(nest_entries, min_h_num + 1)
- lis << %Q{
\n}
+ lis << %(
\n)
i += nest_entries.length
end
end
# Add the closing tag for the current entry in the list
- lis << %Q{ \n}
-
+ lis << %(\n)
elsif curr_h_num > min_h_num
-
# If the current entry should be indented in the list, generate a sublist
- lis << %Q{\n}
+ lis << %(\n)
nest_entries = get_nest_entries(entries[i, entries.length], min_h_num)
lis << build_lis(nest_entries, min_h_num + 1)
- lis << %Q{
\n}
+ lis << %(
\n)
i += nest_entries.length - 1
-
end
i += 1
end
@@ -70,59 +110,14 @@ def build_lis(entries, min_h_num)
# 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)
nest_entries = []
- for i in 0..(entries.length - 1)
+ (0..(entries.length - 1)).each do |i|
nest_entry = entries[i]
- nest_h_num = nest_entry[:node_name].delete("h").to_i
- if nest_h_num > min_h_num
- nest_entries.push(nest_entry)
- else
- break
- end
+ nest_h_num = nest_entry[:node_name].delete('h').to_i
+ break unless nest_h_num > min_h_num
+ nest_entries.push(nest_entry)
end
nest_entries
end
-
- def inject_anchors_into_html
- @entries.each do |entry|
- entry[:content_node].add_previous_sibling(%Q{})
- end
-
- @doc.inner_html
- end
-
- def toc
- build_toc + inject_anchors_into_html
- end
-
- # parse logic is from html-pipeline toc_filter
- # https://github.com/jch/html-pipeline/blob/v1.1.0/lib/html/pipeline/toc_filter.rb
- private
-
- def parse_content
- entries = []
- headers = Hash.new(0)
-
- @doc.css('h1, h2, h3, h4, h5, h6').each do |node|
- text = node.text
- id = text.downcase
- id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
- id.gsub!(' ', '-') # replace spaces with dash
-
- uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
- headers[id] += 1
- if header_content = node.children.first
- entries << {
- id: id,
- uniq: uniq,
- text: text,
- node_name: node.name,
- content_node: header_content
- }
- end
- end
-
- entries
- end
end
end
end
diff --git a/lib/version.rb b/lib/version.rb
index 628843c..62bb2b8 100644
--- a/lib/version.rb
+++ b/lib/version.rb
@@ -1,3 +1,3 @@
module JekyllToc
- VERSION = '0.2.1'
+ VERSION = '0.3.0.pre1'
end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 54398f9..bd15e2f 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -4,14 +4,14 @@
require 'jekyll'
require 'minitest/autorun'
-SIMPLE_HTML = <Simple H1
Simple H2
Simple H3
Simple H4
Simple H5
Simple H6
-EOL
+HTML
module TestHelpers
def read_html_and_create_parser