/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

  1. module 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. def call
  19. return doc if context[:no_header_anchors]
  20. result[:toc] = ""
  21. headers = Hash.new(0)
  22. doc.css('h1, h2, h3, h4, h5, h6').each do |node|
  23. text = node.text
  24. id = text.downcase
  25. id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
  26. id.tr!(' ', '-') # replace spaces with dash
  27. id.squeeze!('-') # replace multiple dashes with one
  28. uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
  29. headers[id] += 1
  30. if header_content = node.children.first
  31. href = "#{id}#{uniq}"
  32. push_toc(href, text)
  33. header_content.add_previous_sibling(anchor_tag(href))
  34. end
  35. end
  36. result[:toc] = %Q{<ul class="section-nav">\n#{result[:toc]}</ul>} unless result[:toc].empty?
  37. doc
  38. end
  39. private
  40. def anchor_tag(href)
  41. %Q{<a id="#{href}" class="anchor" href="##{href}" aria-hidden="true"></a>}
  42. end
  43. def push_toc(href, text)
  44. result[:toc] << %Q{<li><a href="##{href}">#{text}</a></li>\n}
  45. end
  46. end
  47. end
  48. end