PageRenderTime 36ms CodeModel.GetById 11ms app.highlight 20ms RepoModel.GetById 2ms app.codeStats 0ms

/lib/banzai/filter/table_of_contents_filter.rb

https://gitlab.com/vicvega/gitlab-ce
Ruby | 60 lines | 35 code | 12 blank | 13 comment | 2 complexity | 98dce5d29457e4d0b21b87f04a657c5f MD5 | raw file
 1module Banzai
 2  module Filter
 3    # HTML filter that adds an anchor child element to all Headers in a
 4    # document, so that they can be linked to.
 5    #
 6    # Generates the Table of Contents with links to each header. See Results.
 7    #
 8    # Based on HTML::Pipeline::TableOfContentsFilter.
 9    #
10    # Context options:
11    #   :no_header_anchors - Skips all processing done by this filter.
12    #
13    # Results:
14    #   :toc - String containing Table of Contents data as a `ul` element with
15    #          `li` child elements.
16    class TableOfContentsFilter < HTML::Pipeline::Filter
17      PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u
18
19      def call
20        return doc if context[:no_header_anchors]
21
22        result[:toc] = ""
23
24        headers = Hash.new(0)
25
26        doc.css('h1, h2, h3, h4, h5, h6').each do |node|
27          text = node.text
28
29          id = text.downcase
30          id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
31          id.tr!(' ', '-') # replace spaces with dash
32          id.squeeze!('-') # replace multiple dashes with one
33
34          uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
35          headers[id] += 1
36
37          if header_content = node.children.first
38            href = "#{id}#{uniq}"
39            push_toc(href, text)
40            header_content.add_previous_sibling(anchor_tag(href))
41          end
42        end
43
44        result[:toc] = %Q{<ul class="section-nav">\n#{result[:toc]}</ul>} unless result[:toc].empty?
45
46        doc
47      end
48
49      private
50
51      def anchor_tag(href)
52        %Q{<a id="#{href}" class="anchor" href="##{href}" aria-hidden="true"></a>}
53      end
54
55      def push_toc(href, text)
56        result[:toc] << %Q{<li><a href="##{href}">#{text}</a></li>\n}
57      end
58    end
59  end
60end