# $Id: outline.rb 124 2008-02-03 00:24:10Z tim_pease $ require 'hpricot' module Webby module Filters # The Outline filter is used to insert outline numbering into HTML heading # tags (h1, h2, h3, etc.) and to generate a table of contents based on the # heading tags. The table of contents is inserted into the page at the # location of the tag. If there is no tag, then a table of # contents will not be created but outline numbering will still take place. # # If a table of contents is desired without outline number being inserted # into the heading tags, this can be specified in the attibutes of the # tag itself. # # # # This will generate a table of contents, but not insert outline numbering # into the heading tags. # # The Outline filter will only work on valid HTML or XHTML pages. Therefore # it should be used after any markup langauge filters (textile, markdown, # etc.). # class Outline class Error < StandardError; end # :nodoc: # call-seq: # Outline.new( html ) # # Creates a new outline filter that will operate on the given # _html_ string. # def initialize( str ) @str = str @cur_level, @base_level, @cur_depth = nil @level = [0] * 6 @h_rgxp = %r/^h(\d)$/o @toc = [] @outline_numbering = true end # call-seq: # filter => html # # Process the original html document passed to the filter when it was # created. The document will be scanned for heading tags (h1, h2, etc.) # and outline numbering and id attributes will be inserted. A table of # contents will also be created and inserted into the page if a # tag is found. # # For example, if there is a heading tag # #

Get Fuzzy

# # somewhere in a page about comic strips, the tag might be altered as such # #

'heading-num')} end elem['id'] = "h#{lbl.tr('.','_')}" if elem['id'].nil? return [text, elem['id']] end # Set the current heading level. This will set the label and depth as # well. An error will be raised if the _level_ is less than the base # heading level. # # The base heading level will be set to the _level_ if it has not already # been set. Therefore, the first heading tag encountered defines the base # heading level. # def current_level=( level ) @base_level ||= level @cur_level ||= level if level < @base_level raise Error, "heading tags are not in order, cannot outline" end if level == @cur_level @level[level-1] += 1 elsif level > @cur_level @cur_level.upto(level-1) {|ii| @level[ii] += 1} else @cur_level.downto(level+1) {|ii| @level[ii-1] = 0} @level[level-1] += 1 end @cur_level = level end # Return the label string for the current heading level. # def label rv = @level.dup rv.delete(0) rv.join('.') end # Return the nesting depth of the current heading level with respect to the # base heading level. This is a one-based number. # def depth @cur_level - @base_level + 1 end # Add the given text and id reference to the table of contents. # def add_to_toc( text, id ) str = '#' * depth str << ' ' << "\"#{text}\":##{id}" @toc << str end # Returns the table of contents as a collection of nested ordered lists. # This is fully formatted HTML. # def toc RedCloth.new(@toc.join("\n"), %w(no_span_caps)).to_html end # Returns +true+ if outline numbering should be inserted into the heading # tags. Returns +false+ otherwise. # def outline_numbering? @outline_numbering end end # class Outline # Generate a outline numbering and/or a table of contents in the input HTML # text. # register :outline do |input| Outline.new(input).filter end end # module Filters end # module Webby # EOF