class Amber::Render::TableOfContents

TABLE OF CONTENTS

Public Class Methods

new(html, options = {}) click to toggle source

options:

:content_selector (css selector for headings, nokogiri backend only)
:href_base -- use this href for the toc links
:numeric_prefix  -- prefix toc entries and headings with numeric counter (e.g. 1.1.0, 1.2.0, ...)
# File lib/amber/render/table_of_contents.rb, line 23
def initialize(html, options = {})
  @html = html
  @toc = TocItem.new
  @levels = {"h1" => 0, "h2" => 0, "h3" => 0, "h4" => 0}
  @heading_anchors = {}
  @options = options
  @options[:tag] ||= 'ol'
  @parsed = nil
end

Public Instance Methods

to_html() click to toggle source
# File lib/amber/render/table_of_contents.rb, line 33
def to_html
  parse_doc unless @parsed
  # override this!
end
to_toc() click to toggle source
# File lib/amber/render/table_of_contents.rb, line 38
def to_toc
  parse_doc unless @parsed
  # override this!
end

Private Instance Methods

anchor_text(heading_text) click to toggle source

returns anchor text from heading text. e.g. First Heading! => first-heading

if there are duplicates, they get numbered:

heading => heading
heading => heading-2
heading => heading-3
# File lib/amber/render/table_of_contents.rb, line 68
def anchor_text(heading_text)
  text = nameize(strip_html_tags(heading_text))
  text_with_suffix = text
  i = 2
  while @heading_anchors[text_with_suffix]
    text_with_suffix = "#{text}-#{i}"
    i+=1
  end
  @heading_anchors[text_with_suffix] = true
  text_with_suffix
end
each_heading(html, &block) click to toggle source
# File lib/amber/render/table_of_contents.rb, line 128
def each_heading(html, &block)
  raise 'override me'
end
increment_level(heading) click to toggle source

keeps a counter of the latest heading at each level

# File lib/amber/render/table_of_contents.rb, line 121
def increment_level(heading)
  @levels[heading] += 1
  @levels["h2"] = 0 if heading == "h1"
  @levels["h3"] = 0 if heading == "h1" || heading == "h2"
  @levels["h4"] = 0 if heading == "h1" || heading == "h2" || heading == "h3"
end
level_text() click to toggle source

prefix headings with text like 1.2.1, if :numeric_prefix => true

# File lib/amber/render/table_of_contents.rb, line 114
def level_text
  [@levels["h1"], @levels["h2"], @levels["h3"], @levels["h4"]].join(".").gsub(/\.0/, "")
end
nameize(str) click to toggle source

convert any string to one suitable for a url. resist the urge to translit non-ascii slugs to ascii. it is always much better to keep strings as utf8.

# File lib/amber/render/table_of_contents.rb, line 85
def nameize(str)
  str = str.dup
  str.gsub!(/&(\w{2,6}?|#[0-9A-Fa-f]{2,6});/,'') # remove html entitities
  str.gsub!(/[^- [[:word:]]]/u, '') # remove non-word characters (using unicode definition of a word char)
  str.strip!
  str.downcase!          # upper case characters in urls are confusing
  str.gsub!(/\ +/u, '-') # spaces to dashes, preferred separator char everywhere
  CGI.escape(str)
end
parse_doc() click to toggle source
# File lib/amber/render/table_of_contents.rb, line 45
def parse_doc
  each_heading(@html) do |heading, heading_text|
    heading_anchor = anchor_text(heading_text)
    heading_text   = strip_anchors(heading_text)
    if @options[:numeric_prefix]
      increment_level(heading)
      heading_text = level_text + " " + heading_text
    end
    @toc.add_heading(heading, heading_text, heading_anchor)
    '<a name="%s"></a>%s' % [heading_anchor, heading_text]
  end
  @parsed = true
end
strip_anchors(html) click to toggle source

remove <a name='x'></a> from html, but leaves all other tags in place.

# File lib/amber/render/table_of_contents.rb, line 101
def strip_anchors(html)
  Nokogiri::HTML::DocumentFragment.parse(html, 'UTF-8').children.collect{|child|
    if child.name == "text"
      child.inner_text
    elsif child.name != 'a' || !child.attributes.detect{|atr| atr[0] == 'name'}
      child.to_s
    end
  }.join
end
strip_html_tags(html) click to toggle source

removes all html markup

# File lib/amber/render/table_of_contents.rb, line 96
def strip_html_tags(html)
  Nokogiri::HTML::DocumentFragment.parse(html, 'UTF-8').children.collect{|child| child.inner_text}.join
end