Commit cccb0218 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Extract GuideTocEntry class.

To handle the more complex nesting logic of the guide headings
and rendering of HTML, keeping the GuideToc class itself a lot cleaner.
parent 2d18dcd2
Loading
Loading
Loading
Loading
+5 −37
Original line number Diff line number Diff line
require 'jsduck/util/html'
require 'jsduck/guide_toc_entry'

module JsDuck

@@ -11,18 +12,13 @@ module JsDuck
      @min_level = 2
      @max_level = max_level

      # Count the number of heading increments we've seen so far.
      @heading_counts = Array.new(@max_level+1) { 0 }

      @toc = []
      @toc = GuideTocEntry.new
      @new_html = []
    end

    # Inserts table of contents at the top of guide HTML by looking
    # for headings at or below the specified maximum level.
    def inject!
      prev_level = @min_level-1

      @html.each_line do |line|
        if line =~ /^\s*<h([1-6])>(.*?)<\/h[1-6]>$/
          level = $1.to_i
@@ -30,16 +26,7 @@ module JsDuck
          id = title_to_id(text)

          if include_to_toc?(level)
            increment_heading_count!(level)
            if level > prev_level
              list_tags = "<ul><li>" * (level - prev_level)
            elsif prev_level > level
              list_tags = "</li></ul></li><li>" * (prev_level - level)
            else
              list_tags = "</li><li>"
            end
            @toc << list_tags + toc_entry(level, id, text)
            prev_level = level
            @toc.add(level, id, text)
          end

          @new_html << "<h#{level} id='#{id}'>#{text}</h#{level}>\n"
@@ -48,10 +35,6 @@ module JsDuck
        end
      end

      if @toc.length > 0
        @toc[@toc.length-1] += "</li></ul>" * (prev_level - @min_level + 1)
      end

      inject_toc!

      @new_html.flatten.join
@@ -63,33 +46,18 @@ module JsDuck
      (@min_level..@max_level).include?(level)
    end

    # Increments count of current heading level.
    # Resets counts of all the subheadings.
    def increment_heading_count!(level)
      @heading_counts[level] += 1
      ((level+1)..@max_level).each { |i| @heading_counts[i] = 0 }
    end

    def toc_entry(level, id, text)
      "#{toc_prefix(level)}. <a href='#!/guide/#{id}'>#{text}</a>\n"
    end

    def toc_prefix(level)
      @heading_counts.slice(@min_level..level).join('.')
    end

    def title_to_id(title)
      @guide_name + "-section-" + CGI::escape(title.downcase.gsub(/ /, "-"))
    end

    # Injects TOC below first heading if at least 2 items in TOC
    def inject_toc!
      return if @toc.length < 2
      return if @toc.count < 2

      @new_html.insert(1, [
        "<div class='toc'>\n",
          "<p><strong>Contents</strong></p>\n",
          @toc,
          @toc.to_html,
        "</div>\n",
      ])
    end
+54 −0
Original line number Diff line number Diff line
require 'jsduck/util/html'

module JsDuck

  # Manages the single TOC entry (with possible subentries).
  class GuideTocEntry
    attr_accessor :label, :items

    def initialize(parent=nil)
      @parent = parent
      @label = ""
      @items = []
      @min_level = 2
    end

    # Adds entry at the corresponding heading level.
    def add(level, id, text)
      if level == @min_level
        @items << GuideTocEntry.new(self)
        @items.last.label = "#{prefix} <a href='#!/guide/#{id}'>#{text}</a>\n"
      else
        if @items.empty?
          @items << GuideTocEntry.new(self)
        end
        @items.last.add(level-1, id, text)
      end
    end

    # Generates the heading counter, like "1.5.4."
    def prefix
      (@parent ? @parent.prefix : "") + "#{@items.length}."
    end

    # Total number of headings in TOC
    def count
      @items.map {|item| 1 + item.count}.reduce(0, :+)
    end

    # Converts to nested HTML list.
    def to_html
      return if @items.empty?

      return [
        "<ul>",
          @items.map do |item|
            "<li>#{item.label} #{item.to_html}</li>"
          end,
        "</ul>",
      ].flatten.compact.join("\n")
    end

  end

end