lib/jekyll-toc.rb in jekyll-toc-0.0.4 vs lib/jekyll-toc.rb in jekyll-toc-0.1.0
- old
+ new
@@ -1,36 +1,91 @@
require 'nokogiri'
module Jekyll
- # parse logic is from html-pipeline toc_filter
- # https://github.com/jch/html-pipeline/blob/v1.1.0/lib/html/pipeline/toc_filter.rb
- module TableOfContentsFilter
- PUNCTUATION_REGEXP = RUBY_VERSION > "1.9" ? /[^\p{Word}\- ]/u : /[^\w\- ]/
+ module TableOfContents
+ PUNCTUATION_REGEXP = RUBY_VERSION > '1.9' ? /[^\p{Word}\- ]/u : /[^\w\- ]/
- def toc(html)
- page = @context.registers[:page]
- return html unless page["toc"]
+ class Parser
+ attr_reader :doc
- toc = ""
- doc = Nokogiri::HTML::DocumentFragment.parse(html)
- headers = Hash.new(0)
+ def initialize(html)
+ @doc = Nokogiri::HTML::DocumentFragment.parse(html)
+ @entries = parse_content
+ end
- 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
+ def build_toc
+ toc = %Q{<ul class="section-nav">\n}
- uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
- headers[id] += 1
- if header_content = node.children.first
- toc << %Q{<li><a href="##{id}#{uniq}">#{text}</a></li>\n}
- header_content.add_previous_sibling(%Q{<a id="#{id}#{uniq}" class="anchor" href="##{id}#{uniq}" aria-hidden="true"><span class="octicon octicon-link"></span></a>})
+ @entries.each do |entry|
+ toc << %Q{<li class="toc-entry toc-#{entry[:node_name]}"><a href="##{entry[:id]}#{entry[:uniq]}">#{entry[:text]}</a></li>\n}
end
+
+ toc << '</ul>'
end
- toc = %Q{<ul class="section-nav">\n#{toc}</ul>} unless toc.empty?
- toc + doc.inner_html
+ def inject_anchors_into_html
+ @entries.each do |entry|
+ entry[:content_node].add_previous_sibling(%Q{<a id="#{entry[:id]}#{entry[:uniq]}" class="anchor" href="##{entry[:id]}#{entry[:uniq]}" aria-hidden="true"><span class="octicon octicon-link"></span></a>})
+ 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
+
+ module TableOfContentsFilter
+ def toc_only(html)
+ page = @context.registers[:page]
+ return html unless page['toc']
+
+ Jekyll::TableOfContents::Parser.new(html).build_toc
+ end
+
+ def inject_anchors(html)
+ page = @context.registers[:page]
+ return html unless page['toc']
+
+ Jekyll::TableOfContents::Parser.new(html).inject_anchors_into_html
+ end
+
+ def toc(html)
+ page = @context.registers[:page]
+ return html unless page['toc']
+
+ Jekyll::TableOfContents::Parser.new(html).toc
end
end
end
Liquid::Template.register_filter(Jekyll::TableOfContentsFilter)