1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
require 'rdoc/markup/simple_markup/fragments'
require 'rdoc/markup/simple_markup/inline'
require 'cgi'
module SM
module Flow
P = Struct.new(:body)
VERB = Struct.new(:body)
RULE = Struct.new(:width)
class LIST
attr_reader :type, :contents
def initialize(type)
@type = type
@contents = []
end
def <<(stuff)
@contents << stuff
end
end
LI = Struct.new(:label, :body)
H = Struct.new(:level, :text)
end
class ToFlow
LIST_TYPE_TO_HTML = {
SM::ListBase::BULLET => [ "<ul>", "</ul>" ],
SM::ListBase::NUMBER => [ "<ol>", "</ol>" ],
SM::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
SM::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
SM::ListBase::LABELED => [ "<dl>", "</dl>" ],
SM::ListBase::NOTE => [ "<table>", "</table>" ],
}
InlineTag = Struct.new(:bit, :on, :off)
def initialize
init_tags
end
##
# Set up the standard mapping of attributes to HTML tags
#
def init_tags
@attr_tags = [
InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
]
end
##
# Add a new set of HTML tags for an attribute. We allow
# separate start and end tags for flexibility
#
def add_tag(name, start, stop)
@attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
end
##
# Given an HTML tag, decorate it with class information
# and the like if required. This is a no-op in the base
# class, but is overridden in HTML output classes that
# implement style sheets
def annotate(tag)
tag
end
##
# Here's the client side of the visitor pattern
def start_accepting
@res = []
@list_stack = []
end
def end_accepting
@res
end
def accept_paragraph(am, fragment)
@res << Flow::P.new((convert_flow(am.flow(fragment.txt))))
end
def accept_verbatim(am, fragment)
@res << Flow::VERB.new((convert_flow(am.flow(fragment.txt))))
end
def accept_rule(am, fragment)
size = fragment.param
size = 10 if size > 10
@res << Flow::RULE.new(size)
end
def accept_list_start(am, fragment)
@list_stack.push(@res)
list = Flow::LIST.new(fragment.type)
@res << list
@res = list
end
def accept_list_end(am, fragment)
@res = @list_stack.pop
end
def accept_list_item(am, fragment)
@res << Flow::LI.new(fragment.param, convert_flow(am.flow(fragment.txt)))
end
def accept_blank_line(am, fragment)
# @res << annotate("<p />") << "\n"
end
def accept_heading(am, fragment)
@res << Flow::H.new(fragment.head_level, convert_flow(am.flow(fragment.txt)))
end
#######################################################################
private
#######################################################################
def on_tags(res, item)
attr_mask = item.turn_on
return if attr_mask.zero?
@attr_tags.each do |tag|
if attr_mask & tag.bit != 0
res << annotate(tag.on)
end
end
end
def off_tags(res, item)
attr_mask = item.turn_off
return if attr_mask.zero?
@attr_tags.reverse_each do |tag|
if attr_mask & tag.bit != 0
res << annotate(tag.off)
end
end
end
def convert_flow(flow)
res = ""
flow.each do |item|
case item
when String
res << convert_string(item)
when AttrChanger
off_tags(res, item)
on_tags(res, item)
when Special
res << convert_special(item)
else
raise "Unknown flow element: #{item.inspect}"
end
end
res
end
# some of these patterns are taken from SmartyPants...
def convert_string(item)
CGI.escapeHTML(item)
end
def convert_special(special)
handled = false
Attribute.each_name_of(special.type) do |name|
method_name = "handle_special_#{name}"
if self.respond_to? method_name
special.text = send(method_name, special)
handled = true
end
end
raise "Unhandled special: #{special}" unless handled
special.text
end
end
end
|