desc: web page for the Internet code: | # load the String#to_xhtml and String#to_inline_xhtml methods require 'erbook/to_xhtml' class String # Transforms this UTF-8 string into XML entities. def to_xml_entities unpack('U*').map! {|c| "&##{c};"}.join end # Transforms this string into a valid URI fragment. # See http://www.nmt.edu/tcc/help/pubs/xhtml/id-type.html def to_uri_fragment # remove XML tags from the input buf = gsub(/<.*?>/, '') # The first or only character must be a letter. buf.insert(0, 'a') unless buf[0,1] =~ /[[:alpha:]]/ # The remaining characters must be letters, digits, hyphens (-), # underscores (_), colons (:), or periods (.) or Unicode characters buf.unpack('U*').map! do |code| if code > 0xFF or code.chr =~ /[[:alnum:]\-_:\.]/ code else 32 # ASCII character code for a single space end end.pack('U*').strip.gsub(/[[:space:]-]+/, '-') end end class Hash # Transforms this hash into a string of XML attribute key="value" pairs. def to_xml_atts inject([]) {|s,(k,v)| s << %( #{k}="#{v}") }.join end end module ERBook class Template # Protects the given content from the text-to-XHTML conversion process. def verbatim aContent ERB::Util.html_escape aContent end # Returns XHTML for a hyperlink to the given # URL of the given label and mouse-hover title. def hyperlink aUrl, aLabel = aUrl, aTitle = nil %{#{aLabel}} end # Returns an tag that embeds the given image file. # # aPath:: path to the image file # aFormat:: format of the image file (e.g. PNG, JPEG, GIF, etc.) # aAtts:: additional attributes for the tag # def embed_image_file aPath, aFormat = aPath[/\w+/], aAtts = {} data = ERBook.base_64_encode File.read(aPath) embed_image_data data, aFormat, aAtts end # Returns an tag that embeds the given raw image data. # # aData:: raw image data # aFormat:: format of the image file (e.g. PNG, JPEG, GIF, etc.) # aAtts:: additional attributes for the tag # def embed_image_data aData, aFormat, aAtts = {} aAtts[:src] = ERBook.base_64_embed_image_data(aData, aFormat) "" end end class Node # Returns the user-defined title for this node's content. def title @title ||= args[0] end # Returns the user-defined indentifer for this node. def id @id ||= args[1] end ## # utility methods # def type_label #:nodoc: type.to_s.capitalize end def type_label_here_link #:nodoc: s = type_label here_link s, s end # Returns the title of this node as XHTML. def title_xhtml title.to_s.to_inline_xhtml end # Returns the content of this node as XHTML. def content_xhtml content.to_s.to_xhtml end # Returns the content of this node as XHTML inside a
. def content_xhtml_div #:nodoc: %{
#{content_xhtml}
} end # Returns a hyperlink to this node containing its title. def title_link aTitle = nil here_link here_frag, aTitle || title_xhtml end # Returns a hyperlink to this node # containing its LaTeX-style index number. def index_link list_link here_frag, list_frag, index end # Returns a hyperlink to this node containing its occurrence number. def number_link list_link here_frag, list_frag, [type_label, number].compact.join(' ') end # Returns a hyperlink to this node containing # its ocurrence number and its title. def number_and_title_link #:nodoc: "#{number_link}.  #{title_link}" end # Returns a hyperlink to this node containing # its LaTeX-style index number and its title. def index_and_title_link #:nodoc: "#{index_link}  #{title_link}" end ## # URI fragments # @@frags = [] # Returns a unique URI fragment for this node. def here_frag #:nodoc: unless defined? @here_frag salt = object_id.abs frag = (id || title || salt).to_s.to_uri_fragment # make it unique while @@frags.include? frag frag << '-' << (index || number || salt).to_s end @@frags << frag @here_frag = frag end @here_frag end # Returns the URI fragment for the location in the table # of contents / list of figures that points this node. def list_frag #:nodoc: @list_frag ||= "rev:#{here_frag}" end private def here_link aHereFrag, aLabel #:nodoc: %{#{aLabel}} end def list_link aHereFrag, aListFrag, aLabel #:nodoc: %{#{aLabel}} end end # Encodes the given input in base64 format. def ERBook.base_64_encode aInput #:nodoc: [aInput].pack('m') end # Returns a string denoting embedded, base64 encoded data. def ERBook.base_64_embed aData, aFormat #:nodoc: "data:#{aFormat.to_s.downcase};base64,#{aData.tr("\n", '')}" end # Returns a string denoting embedded, base64 encoded image data. # aFormat:: format of the image data (e.g. PNG, JPEG, GIF, etc.) def ERBook.base_64_embed_image_data aData, aFormat #:nodoc: base_64_embed aData, "image/#{aFormat}" end ## # load admonition icons # ICONS_DIR = File.join(ERBook::FORMATS_DIR, 'xhtml.icons') ICON_DEFS = YAML.load_file File.join(ICONS_DIR, 'index.yaml') Icon = Struct.new(:origin, :path, :name, :format, :data) class Icon #:nodoc: # Returns a data URI containing embedded image data. def data_uri ERBook.base_64_embed_image_data self.data, self.format end # Returns a CSS url() containing embedded image data. def data_css %{url("#{data_uri}")} end # Returns a XML entity reference (to this icon's # embedded image data) ready for insertion into XML. def entity_xml "&#{entity_name};" end # Returns the name of the XML entity whose # value contains embedded image data. def entity_name "icon_#{name}" end # Returns an tag that renders the image # data embedded as an ENTITY in the html DOCTYPE. def to_xhtml aAtts = {} aAtts[:alt] ||= name aAtts[:src] = entity_xml aAtts[:class] = :icon "" end end ICON_BY_NAME = {} ICON_DEFS.each_pair do |name, path| format = File.extname(path).sub('.', '') origin = path[/^\w+/] path = File.join(ICONS_DIR, path) # make the path absolute data = base_64_encode File.open(path, 'rb') {|f| f.read } ICON_BY_NAME[name] = Icon.new(origin, path, name, format, data) end ICONS = ICON_BY_NAME.values end nodes: ## # Structure # header: &header toc: false lof: false index: false number: false silent: true output: <%= @node.content_xhtml %> header_outside_above: &header_insert toc: false lof: false index: false number: false silent: true output:
<%= @node.content_xhtml %>
header_inside_above: *header_insert header_inside_below: *header_insert header_outside_below: *header_insert footer: *header footer_outside_above: *header_insert footer_inside_above: *header_insert footer_inside_below: *header_insert footer_outside_below: *header_insert abstract: toc: false lof: false index: false number: false silent: true output: |

<%= @node.type_label_here_link %>

<%= @node.content_xhtml_div %>
## # Organization # part: &latex toc: true lof: false index: true number: true output: |

<%= @node.type_label %> <%= @node.index_link %>
<%= @node.title_link %>

<%= @node.content_xhtml_div %>
chapter: *latex section: toc: true lof: false index: true number: true output: | <% depth = [6, @node.depth + 1].min %>
class="title"> <%= @node.index_and_title_link %> > <%= @node.content_xhtml_div %>
paragraph: toc: false lof: false index: false number: false output: |

<%= @node.title_link %>

<%= @node.content_xhtml_div %>
## # Admonitions # tip: &admonition toc: false lof: true index: false number: true output: |

<%= @node.number_and_title_link %>

<%= ICON_BY_NAME[@node.type].to_xhtml %><%= @node.content_xhtml %>
note: *admonition caution: *admonition warning: *admonition important: *admonition ## # Auxilary materials (formal blocks) # see http://www.sagehill.net/docbookxsl/FormalTitles.html # figure: &formal toc: false lof: true index: false number: true output: |

<%= @node.number_and_title_link %>

<%= @node.content_xhtml_div %>
table: *formal example: *formal equation: *formal procedure: *formal ## # cross-references # xref: toc: false lof: false index: false number: false output: | <%= scope = @nodes.select {|n| n.content} target = scope.find {|n| n.id == @node.args[0]} || # id has 1st priority scope.find {|n| n.title == @node.args[0]} if target prefix = "#{target.type_label} #{target.index || target.number}" title_text = if target.type == 'reference' prefix else [prefix, target.title].compact.join('. ') end title_auto = @node.args.length < 2 title_xhtml = if title_auto title_text else @node.args[1].to_s end.to_inline_xhtml %{#{title_xhtml}} else raise ArgumentError, "invalid cross-reference to #{@node.title.inspect}", @node.trace end %> ## # Bibliography # reference: toc: false lof: false index: false number: true silent: true cite: toc: false lof: false index: false number: false output: | <%= target = @types['reference'].find {|n| n.title == @node.args[0]} if target '[%s]' % [ '%s' % [ @node.type, target.here_frag, target.number ], *@node.args[1..-1] ].join(', ') else raise ArgumentError, "invalid citation for #{@node.title.inspect}", @node.trace end %> output: | <% # set default parameter values $title = '$title' unless defined? $title $authors = {'$authors' => nil} unless defined? $authors $date = Time.now.strftime("%d %B %Y") unless defined? $date abstract = @types['abstract'].first references = @types['reference'] if references.empty? references = nil end # compute table of contents toc_builder = lambda do |n| if @spec['nodes'][n.type]['toc'] entry = '%s%s' % [ (n.index.to_s + '  ' if n.index), n.list_frag, n.here_frag, n.title.to_s.to_inline_xhtml ] nested = n.children.inject('') {|s,c| s << toc_builder[c] } %{
  • #{entry}#{ "
      #{nested}
    " unless nested.empty? }
  • } else '' end end toc = @roots.inject('') {|s,n| s << toc_builder[n] } # compute list of figures lof_enums = {} # type => nodes @spec['nodes'].each_pair do |name, info| if info['lof'] nodes = @types[name] lof_enums[name] = nodes unless nodes.empty? end end lof_sections = [] lof = lof_enums.sort.map do |(type, nodes)| nested = nodes.map do |n| %{
  • #{n.title.to_s.to_inline_xhtml}
  • } end label = type.capitalize << 's' # TODO: pluralize this properly lof_sections << label %{

    #{label}

      #{nested}
    } end %> "<%= icon.data_uri %>"> <% end %> ]> <%= $title.to_s.to_inline_xhtml %> <% if $feeds %> <% $feeds.each_pair do |url, fmt| %> <% end %> <% end %> <% @spec['styles'].each_pair do |media, style| %> <% end %> <% # menu of links to link sections nav = [ ('Abstract' if abstract), 'Contents', lof_sections, ('References' if references) ].flatten.compact if nav.length > 1 %> <% end %>


    <%= node = @types['header_outside_above'].first and node.output %> <%= node = @types['header_outside_below'].first and node.output %> <%= abstract.output if abstract %>


    <% unless toc.empty? %>

    Contents

      <%= toc %> <% if references %>
    • References
    • <% end %>
    <% end %> <% unless lof.empty? %>
    <%= lof %>
    <% end %>


    <%= @content %>
    <% if references %>

    References

      <% references.each do |n| %>
    1. <%= n.content_xhtml %>
    2. <% end %>
    <% end %>


    <%= node = @types['footer_outside_above'].first and node.output %> <%= node = @types['footer_outside_below'].first and node.output %> styles: all: | body { color : #000000; background-color : #FFFFFF; line-height : 1.5em; font-family : Calibri, Verdana, sans-serif; } /* emphasis */ blockquote { color : #333; font-style : italic; } em { } hr { height : 0; border : 0; border-top : 2px solid #FF0000; } /* source code */ tt, code, pre { font-family : Monaco, Consolas, "Lucida Console", monospace; font-size : 100%; /* appears like "size: small" otherwise */ } /* hyperlinks */ a > img { border : none; } a img { _border : none; /* for IE6 */ } /* lists */ #content li:first-child { margin-top : 1em; } #content li { margin-bottom : 1em; } /* headings */ h1, h2, h3, h4, h5, h6, .title { font-weight : lighter; font-family : Constantia, "Book Antiqua", "URW Bookman L", serif; } #lof h1, #lof h2, #lof h3, #lof h4, #lof h5, #lof h6 { margin-top : 1.25em; } #content h1, #content h2, #content h3, #content h4, #content h5, #content h6 { margin-top : 2.5em; line-height : 1.25em; } #content h1 { font-size : 2.0em; } #content h2 { font-size : 1.8em; } #content h3 { font-size : 1.6em; } #content h4 { font-size : 1.4em; } #content h5 { font-size : 1.2em; } #content h6 { font-size : 1.0em; } /* tables */ table { border-collapse : collapse; /* no spacing between cell borders */ margin : auto; /* center horizontally */ margin-top : 1em; } th, td { padding : 1em; border : 1px solid #bbb; vertical-align : top; background-color : inherit; _background-color : #FFFFFF; /* for IE6 */ } th { background-color : #F5F5F5; } /* document structure */ #nav { text-align : center; margin-bottom : 4em; } #header { text-align : center; } .header_outside_above, #header, .header_outside_below { margin-bottom : 5em; } .footer_outside_above, #footer, .footer_outside_below { margin-top : 5em; } #header .header_inside_above, #footer .footer_inside_above { margin-bottom : 4em; } #header .header_inside_below, #footer .footer_inside_below { margin-top : 4em; } #Abstract { margin-bottom : 5em; } #toc li { list-style-type : none; } #toc li ul { padding-bottom : 1em; border-left : thick solid #F5F5F5; _border-left : none; /* for IE6 */ } #toc li ul:hover { border-color : #DCDCDC; } #toc > ul { padding-left : 1em; } #bib { margin-top : 5em; } #footer { border-top : thick dotted #DCDCDC; padding-top : 1em; text-align : center; } #footer-credits { margin-top : 2em; margin-bottom : 2em; } /* document nodes */ .part > .title, .chapter > .title { padding-bottom : 0.5em; } .part > .title > big, .chapter > .title > big { display : block; margin-top : 0.25em; } .part .title big, .chapter .title big { _display : block; /* for IE6 */ _margin-top : 0.25em; /* for IE6 */ _margin-bottom : 0.75em; /* for IE6 */ } .paragraph > .title, .tip > .title, .note > .title, .caution > .title, .warning > .title, .important > .title, .figure > .title, .table > .title, .example > .title, .equation > .title, .procedure > .title { font-size : large; margin-top : 2em; } .paragraph .title, .tip .title, .note .title, .caution .title, .warning .title, .important .title, .figure .title, .table .title, .example .title, .equation .title, .procedure .title { _font-size : large; /* for IE6 */ _font-weight : bold; /* large is not bold in IE6 */ _margin-top : 2em; /* for IE6 */ } .tip , .note , .caution , .warning , .important, .figure , .table , .example , .equation , .procedure { margin : 3em; } .tip > .content, .note > .content, .caution > .content, .warning > .content, .important > .content, .figure > .content, .table > .content, .example > .content, .equation > .content, .procedure > .content { min-height : 48px; /* 48px is height of icon */ } .tip > .content > .icon, .note > .content > .icon, .caution > .content > .icon, .warning > .content > .icon, .important > .content > .icon { float : left; margin : 0 1em 1em 0; /* top right bottom left */ } .tip .content .icon, .note .content .icon, .caution .content .icon, .warning .content .icon, .important .content .icon { _display : none; /* IE6 cannot display embedded images */ } .figure > .title { text-align : center; } .figure .title { _text-align : center; /* for IE6 */ } .figure > .content img { display : block; margin : auto; } .figure .content img { _display : block; /* for IE6 */ _margin : auto; /* for IE6 */ } screen: | body { margin : auto; max-width : 36em; padding : 0.5em; } /* source code */ tt { background-color : #F0F8FF; } pre { cursor : text; line-height : normal; border : 1px solid #b1d827; background-color : #F5FFDF; padding : 1em; overflow : auto; } /* output of the syntax coloring library */ pre.code { background-color : #FFFFE8; border-color : #EEDD88; } /* hyperlinks */ a { text-decoration : none; } a:hover { text-decoration : underline; } a:link { color : #002BB8; } a:visited { color : #5A3696; } a.here, a.list { color : #000000; } a:target, a:target *, *:target a.list { background-color : #FF4500 !important; color : #FFFFFF !important; } a:target, *:target a.list { padding : 0.1em; font-weight : bolder; text-decoration : none; } print: | /* source code */ tt { font-weight : normal; } pre { border : none; } /* headings */ h1, h2, h3, h4, h5, h6 { font-weight : normal; clear : both; } /* hyperlinks */ /* blend all hyperlinks with normal text */ a:link, a:visited { color : #000000; text-decoration : none; } /* emphasize external and cross-reference hyperlinks */ a:not([href^="#"]):link, a:not([href^="#"]):visited, a.xref[title]:link, a.xref[title]:visited { color : #0000FF; text-decoration : underline; font-weight : bolder; } /* show URL of destination for external hyperlinks */ a:not([href^="#"]):after { content : " " attr(href); font-family : Monaco, Consolas, "Lucida Console", monospace; } /* show name of destination for cross-references */ a.xref[title]:after { content : " " attr(title); } a:after { font-weight : normal; font-size : smaller; } /* document structure */ #nav, #lof { display : none; } #toc, .part, .chapter, #bib { page-break-before : always; } /* document nodes */ .part > .title > big, .chapter > .title > big { padding-bottom : 0.5em; } .part .title big, .chapter .title big { _padding-bottom : 0.5em; /* for IE6 */ }