source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/rdoc/markup/simple_markup/to_html.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 7.0 KB
Line 
1require 'rdoc/markup/simple_markup/fragments'
2require 'rdoc/markup/simple_markup/inline'
3
4require 'cgi'
5
6module SM
7
8 class ToHtml
9
10 LIST_TYPE_TO_HTML = {
11 ListBase::BULLET => [ "<ul>", "</ul>" ],
12 ListBase::NUMBER => [ "<ol>", "</ol>" ],
13 ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
14 ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
15 ListBase::LABELED => [ "<dl>", "</dl>" ],
16 ListBase::NOTE => [ "<table>", "</table>" ],
17 }
18
19 InlineTag = Struct.new(:bit, :on, :off)
20
21 def initialize
22 init_tags
23 end
24
25 ##
26 # Set up the standard mapping of attributes to HTML tags
27 #
28 def init_tags
29 @attr_tags = [
30 InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
31 InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
32 InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
33 ]
34 end
35
36 ##
37 # Add a new set of HTML tags for an attribute. We allow
38 # separate start and end tags for flexibility
39 #
40 def add_tag(name, start, stop)
41 @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
42 end
43
44 ##
45 # Given an HTML tag, decorate it with class information
46 # and the like if required. This is a no-op in the base
47 # class, but is overridden in HTML output classes that
48 # implement style sheets
49
50 def annotate(tag)
51 tag
52 end
53
54 ##
55 # Here's the client side of the visitor pattern
56
57 def start_accepting
58 @res = ""
59 @in_list_entry = []
60 end
61
62 def end_accepting
63 @res
64 end
65
66 def accept_paragraph(am, fragment)
67 @res << annotate("<p>") + "\n"
68 @res << wrap(convert_flow(am.flow(fragment.txt)))
69 @res << annotate("</p>") + "\n"
70 end
71
72 def accept_verbatim(am, fragment)
73 @res << annotate("<pre>") + "\n"
74 @res << CGI.escapeHTML(fragment.txt)
75 @res << annotate("</pre>") << "\n"
76 end
77
78 def accept_rule(am, fragment)
79 size = fragment.param
80 size = 10 if size > 10
81 @res << "<hr size=\"#{size}\"></hr>"
82 end
83
84 def accept_list_start(am, fragment)
85 @res << html_list_name(fragment.type, true) <<"\n"
86 @in_list_entry.push false
87 end
88
89 def accept_list_end(am, fragment)
90 if tag = @in_list_entry.pop
91 @res << annotate(tag) << "\n"
92 end
93 @res << html_list_name(fragment.type, false) <<"\n"
94 end
95
96 def accept_list_item(am, fragment)
97 if tag = @in_list_entry.last
98 @res << annotate(tag) << "\n"
99 end
100 @res << list_item_start(am, fragment)
101 @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
102 @in_list_entry[-1] = list_end_for(fragment.type)
103 end
104
105 def accept_blank_line(am, fragment)
106 # @res << annotate("<p />") << "\n"
107 end
108
109 def accept_heading(am, fragment)
110 @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
111 end
112
113 # This is a higher speed (if messier) version of wrap
114
115 def wrap(txt, line_len = 76)
116 res = ""
117 sp = 0
118 ep = txt.length
119 while sp < ep
120 # scan back for a space
121 p = sp + line_len - 1
122 if p >= ep
123 p = ep
124 else
125 while p > sp and txt[p] != ?\s
126 p -= 1
127 end
128 if p <= sp
129 p = sp + line_len
130 while p < ep and txt[p] != ?\s
131 p += 1
132 end
133 end
134 end
135 res << txt[sp...p] << "\n"
136 sp = p
137 sp += 1 while sp < ep and txt[sp] == ?\s
138 end
139 res
140 end
141
142 #######################################################################
143
144 private
145
146 #######################################################################
147
148 def on_tags(res, item)
149 attr_mask = item.turn_on
150 return if attr_mask.zero?
151
152 @attr_tags.each do |tag|
153 if attr_mask & tag.bit != 0
154 res << annotate(tag.on)
155 end
156 end
157 end
158
159 def off_tags(res, item)
160 attr_mask = item.turn_off
161 return if attr_mask.zero?
162
163 @attr_tags.reverse_each do |tag|
164 if attr_mask & tag.bit != 0
165 res << annotate(tag.off)
166 end
167 end
168 end
169
170 def convert_flow(flow)
171 res = ""
172 flow.each do |item|
173 case item
174 when String
175 res << convert_string(item)
176 when AttrChanger
177 off_tags(res, item)
178 on_tags(res, item)
179 when Special
180 res << convert_special(item)
181 else
182 raise "Unknown flow element: #{item.inspect}"
183 end
184 end
185 res
186 end
187
188 # some of these patterns are taken from SmartyPants...
189
190 def convert_string(item)
191 CGI.escapeHTML(item).
192
193
194 # convert -- to em-dash, (-- to en-dash)
195 gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
196
197 # convert ... to elipsis (and make sure .... becomes .<elipsis>)
198 gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
199
200 # convert single closing quote
201 gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1&#8217;" }.
202 gsub(%r{\'(?=\W|s\b)}) { "&#8217;" }.
203
204 # convert single opening quote
205 gsub(/'/, '&#8216;').
206
207 # convert double closing quote
208 gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1&#8221;" }.
209
210 # convert double opening quote
211 gsub(/'/, '&#8220;').
212
213 # convert copyright
214 gsub(/\(c\)/, '&#169;').
215
216 # convert and registered trademark
217 gsub(/\(r\)/, '&#174;')
218
219 end
220
221 def convert_special(special)
222 handled = false
223 Attribute.each_name_of(special.type) do |name|
224 method_name = "handle_special_#{name}"
225 if self.respond_to? method_name
226 special.text = send(method_name, special)
227 handled = true
228 end
229 end
230 raise "Unhandled special: #{special}" unless handled
231 special.text
232 end
233
234 def convert_heading(level, flow)
235 res =
236 annotate("<h#{level}>") +
237 convert_flow(flow) +
238 annotate("</h#{level}>\n")
239 end
240
241 def html_list_name(list_type, is_open_tag)
242 tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
243 annotate(tags[ is_open_tag ? 0 : 1])
244 end
245
246 def list_item_start(am, fragment)
247 case fragment.type
248 when ListBase::BULLET, ListBase::NUMBER
249 annotate("<li>")
250
251 when ListBase::UPPERALPHA
252 annotate("<li type=\"A\">")
253
254 when ListBase::LOWERALPHA
255 annotate("<li type=\"a\">")
256
257 when ListBase::LABELED
258 annotate("<dt>") +
259 convert_flow(am.flow(fragment.param)) +
260 annotate("</dt>") +
261 annotate("<dd>")
262
263 when ListBase::NOTE
264 annotate("<tr>") +
265 annotate("<td valign=\"top\">") +
266 convert_flow(am.flow(fragment.param)) +
267 annotate("</td>") +
268 annotate("<td>")
269 else
270 raise "Invalid list type"
271 end
272 end
273
274 def list_end_for(fragment_type)
275 case fragment_type
276 when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA
277 "</li>"
278 when ListBase::LABELED
279 "</dd>"
280 when ListBase::NOTE
281 "</td></tr>"
282 else
283 raise "Invalid list type"
284 end
285 end
286
287 end
288
289end
Note: See TracBrowser for help on using the repository browser.