diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2019-09-19 11:09:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-19 11:09:05 +0200 |
commit | d930eb88b671fa6e5573fe7342bcdda87501bdb7 (patch) | |
tree | a67ab76528da0060e7def3d13f5802904d215939 /app/lib | |
parent | e1066cd4319a220d5be16e51ffaf5236a2f6e866 (diff) |
Add table of contents to about page (#11885)
Move public domain blocks information to about page
Diffstat (limited to 'app/lib')
-rw-r--r-- | app/lib/toc_generator.rb | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/app/lib/toc_generator.rb b/app/lib/toc_generator.rb new file mode 100644 index 000000000..c6e179557 --- /dev/null +++ b/app/lib/toc_generator.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +class TOCGenerator + TARGET_ELEMENTS = %w(h1 h2 h3 h4 h5 h6).freeze + LISTED_ELEMENTS = %w(h2 h3).freeze + + class Section + attr_accessor :depth, :title, :children, :anchor + + def initialize(depth, title, anchor) + @depth = depth + @title = title + @children = [] + @anchor = anchor + end + + delegate :<<, to: :children + end + + def initialize(source_html) + @source_html = source_html + @processed = false + @target_html = '' + @headers = [] + @slugs = Hash.new { |h, k| h[k] = 0 } + end + + def html + parse_and_transform unless @processed + @target_html + end + + def toc + parse_and_transform unless @processed + @headers + end + + private + + def parse_and_transform + return if @source_html.blank? + + parsed_html = Nokogiri::HTML.fragment(@source_html) + + parsed_html.traverse do |node| + next unless TARGET_ELEMENTS.include?(node.name) + + anchor = node.text.parameterize + @slugs[anchor] += 1 + anchor = "#{anchor}-#{@slugs[anchor]}" if @slugs[anchor] > 1 + + node['id'] = anchor + + next unless LISTED_ELEMENTS.include?(node.name) + + depth = node.name[1..-1] + latest_section = @headers.last + + if latest_section.nil? || latest_section.depth >= depth + @headers << Section.new(depth, node.text, anchor) + else + latest_section << Section.new(depth, node.text, anchor) + end + end + + @target_html = parsed_html.to_s + @processed = true + end +end |