maiku 0.6.1.maiku

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/lib/maruku.rb +141 -0
  2. data/lib/maruku/attributes.rb +175 -0
  3. data/lib/maruku/defaults.rb +71 -0
  4. data/lib/maruku/errors_management.rb +92 -0
  5. data/lib/maruku/ext/div.rb +133 -0
  6. data/lib/maruku/ext/math.rb +41 -0
  7. data/lib/maruku/ext/math/elements.rb +27 -0
  8. data/lib/maruku/ext/math/latex_fix.rb +12 -0
  9. data/lib/maruku/ext/math/mathml_engines/blahtex.rb +107 -0
  10. data/lib/maruku/ext/math/mathml_engines/itex2mml.rb +29 -0
  11. data/lib/maruku/ext/math/mathml_engines/none.rb +20 -0
  12. data/lib/maruku/ext/math/mathml_engines/ritex.rb +24 -0
  13. data/lib/maruku/ext/math/parsing.rb +119 -0
  14. data/lib/maruku/ext/math/to_html.rb +187 -0
  15. data/lib/maruku/ext/math/to_latex.rb +26 -0
  16. data/lib/maruku/helpers.rb +260 -0
  17. data/lib/maruku/input/charsource.rb +326 -0
  18. data/lib/maruku/input/extensions.rb +69 -0
  19. data/lib/maruku/input/html_helper.rb +189 -0
  20. data/lib/maruku/input/linesource.rb +111 -0
  21. data/lib/maruku/input/parse_block.rb +616 -0
  22. data/lib/maruku/input/parse_doc.rb +232 -0
  23. data/lib/maruku/input/parse_span_better.rb +746 -0
  24. data/lib/maruku/input/rubypants.rb +225 -0
  25. data/lib/maruku/input/type_detection.rb +147 -0
  26. data/lib/maruku/input_textile2/t2_parser.rb +163 -0
  27. data/lib/maruku/maruku.rb +33 -0
  28. data/lib/maruku/output/s5/fancy.rb +756 -0
  29. data/lib/maruku/output/s5/to_s5.rb +138 -0
  30. data/lib/maruku/output/to_html.rb +991 -0
  31. data/lib/maruku/output/to_latex.rb +590 -0
  32. data/lib/maruku/output/to_latex_entities.rb +367 -0
  33. data/lib/maruku/output/to_latex_strings.rb +64 -0
  34. data/lib/maruku/output/to_markdown.rb +164 -0
  35. data/lib/maruku/output/to_s.rb +56 -0
  36. data/lib/maruku/string_utils.rb +201 -0
  37. data/lib/maruku/structures.rb +167 -0
  38. data/lib/maruku/structures_inspect.rb +87 -0
  39. data/lib/maruku/structures_iterators.rb +61 -0
  40. data/lib/maruku/textile2.rb +1 -0
  41. data/lib/maruku/toc.rb +199 -0
  42. data/lib/maruku/usage/example1.rb +33 -0
  43. data/lib/maruku/version.rb +39 -0
  44. metadata +167 -0
@@ -0,0 +1,138 @@
1
+ # This module groups all functions related to HTML export.
2
+ module MaRuKu
3
+
4
+ begin
5
+ require 'rexml/formatters/pretty'
6
+ require 'rexml/formatters/default'
7
+ $rexml_new_version = true
8
+ rescue LoadError
9
+ $rexml_new_version = false
10
+ end
11
+
12
+ class MDDocument
13
+
14
+ def s5_theme
15
+ html_escape(self.attributes[:slide_theme] || "default")
16
+ end
17
+
18
+ def html_escape(string)
19
+ string.gsub( /&/, "&" ).
20
+ gsub( /</, "&lt;" ).
21
+ gsub( />/, "&gt;" ).
22
+ gsub( /'/, "&#39;" ).
23
+ gsub( /"/, "&quot;" )
24
+ end
25
+
26
+ # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
27
+ def to_s5(context={})
28
+ indent = context[:indent] || -1
29
+ ie_hack = !context[:ie_hack].kind_of?(FalseClass)
30
+ content_only = !context[:content_only].kind_of?(FalseClass)
31
+
32
+ doc = Document.new(nil,{:respect_whitespace =>:all})
33
+
34
+ if content_only
35
+ body = Element.new('div', doc)
36
+ else
37
+ html = Element.new('html', doc)
38
+ html.add_namespace('http://www.w3.org/1999/xhtml')
39
+ html.add_namespace('svg', "http://www.w3.org/2000/svg" )
40
+
41
+ head = Element.new('head', html)
42
+ me = Element.new 'meta', head
43
+ me.attributes['http-equiv'] = 'Content-type'
44
+ me.attributes['content'] = 'text/html;charset=utf-8'
45
+
46
+ # Create title element
47
+ doc_title = self.attributes[:title] || self.attributes[:subject] || ""
48
+ title = Element.new 'title', head
49
+ title << Text.new(doc_title)
50
+ body = Element.new('body', html)
51
+
52
+ end
53
+
54
+ slide_header = self.attributes[:slide_header]
55
+ slide_footer = self.attributes[:slide_footer]
56
+ slide_subfooter = self.attributes[:slide_subfooter]
57
+ slide_topleft = self.attributes[:slide_topleft]
58
+ slide_topright = self.attributes[:slide_topright]
59
+ slide_bottomleft = self.attributes[:slide_bottomleft]
60
+ slide_bottomright = self.attributes[:slide_bottomright]
61
+
62
+ dummy_layout_slide =
63
+ "
64
+ <div class='layout'>
65
+ <div id='controls'> </div>
66
+ <div id='currentSlide'> </div>
67
+ <div id='header'> #{slide_header}</div>
68
+ <div id='footer'>
69
+ <h1>#{slide_footer}</h1>
70
+ <h2>#{slide_subfooter}</h2>
71
+ </div>
72
+ <div class='topleft'> #{slide_topleft}</div>
73
+ <div class='topright'> #{slide_topright}</div>
74
+ <div class='bottomleft'> #{slide_bottomleft}</div>
75
+ <div class='bottomright'> #{slide_bottomright}</div>
76
+ </div>
77
+ "
78
+ body.add_element Document.new(dummy_layout_slide, {:respect_whitespace =>:all}).root
79
+
80
+ presentation = Element.new 'div', body
81
+ presentation.attributes['class'] = 'presentation'
82
+
83
+ first_slide="
84
+ <div class='slide'>
85
+ <h1> #{self.attributes[:title] ||context[:title]}</h1>
86
+ <h2> #{self.attributes[:subtitle] ||context[:subtitle]}</h2>
87
+ <h3> #{self.attributes[:author] ||context[:author]}</h3>
88
+ <h4> #{self.attributes[:company] ||context[:company]}</h4>
89
+ </div>
90
+ "
91
+ presentation.add_element Document.new(first_slide).root
92
+
93
+ slide_num = 0
94
+ self.toc.section_children.each do |slide|
95
+ slide_num += 1
96
+ @doc.attributes[:doc_prefix] = "s#{slide_num}"
97
+
98
+ puts "Slide #{slide_num}: " + slide.header_element.to_s
99
+ div = Element.new('div', presentation)
100
+ div.attributes['class'] = 'slide'
101
+
102
+ h1 = Element.new 'h1', div
103
+ slide.header_element.children_to_html.each do |e| h1 << e; end
104
+
105
+ array_to_html(slide.immediate_children).each do |e| div << e end
106
+
107
+ # render footnotes
108
+ if @doc.footnotes_order.size > 0
109
+ div << render_footnotes
110
+ @doc.footnotes_order = []
111
+ end
112
+ end
113
+
114
+ xml = ""
115
+ if (content_only)
116
+ if $rexml_new_version
117
+ formatter = REXML::Formatters::Default.new(ie_hack)
118
+ formatter.write(body, xml)
119
+ else
120
+ body.write(xml,indent,transitive=true,ie_hack);
121
+ end
122
+ else
123
+ doc2 = Document.new("<div>"+S5_external+"</div>",{:respect_whitespace =>:all})
124
+ doc2.root.children.each{ |child| head << child }
125
+
126
+ add_css_to(head)
127
+
128
+ # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
129
+ # containing code.
130
+ html.write(xml,indent,transitive=true,ie_hack);
131
+ Xhtml11_mathml2_svg11 + xml
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+
138
+ end
@@ -0,0 +1,991 @@
1
+ #--
2
+ # Copyright (C) 2006 Andrea Censi <andrea (at) rubyforge.org>
3
+ #
4
+ # This file is part of Maruku.
5
+ #
6
+ # Maruku is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Maruku is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Maruku; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #++
20
+
21
+ require 'rexml/document'
22
+
23
+ begin
24
+ require 'rexml/formatters/pretty'
25
+ require 'rexml/formatters/default'
26
+ $rexml_new_version = true
27
+ rescue LoadError
28
+ $rexml_new_version = false
29
+ end
30
+
31
+ class String
32
+ # A string is rendered into HTML by creating
33
+ # a REXML::Text node. REXML takes care of all the encoding.
34
+ def to_html
35
+ REXML::Text.new(self)
36
+ end
37
+ end
38
+
39
+
40
+ # This module groups all functions related to HTML export.
41
+ module MaRuKu; module Out; module HTML
42
+ include REXML
43
+
44
+ # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
45
+ def to_html(context={})
46
+ indent = context[:indent] || -1
47
+ ie_hack = context[:ie_hack] || true
48
+
49
+ div = Element.new 'dummy'
50
+ children_to_html.each do |e|
51
+ div << e
52
+ end
53
+
54
+ # render footnotes
55
+ if @doc.footnotes_order.size > 0
56
+ div << render_footnotes
57
+ end
58
+
59
+ doc = Document.new(nil,{:respect_whitespace =>:all})
60
+ doc << div
61
+
62
+ # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
63
+ # containing code.
64
+ xml =""
65
+
66
+ if $rexml_new_version
67
+ formatter = if indent > -1
68
+ REXML::Formatters::Pretty.new( indent, ie_hack )
69
+ else
70
+ REXML::Formatters::Default.new( ie_hack )
71
+ end
72
+ formatter.write( div, xml)
73
+ else
74
+ div.write(xml,indent,transitive=true,ie_hack)
75
+ end
76
+
77
+ xml.gsub!(/\A<dummy>\s*/,'')
78
+ xml.gsub!(/\s*<\/dummy>\Z/,'')
79
+ xml.gsub!(/\A<dummy\s*\/>/,'')
80
+ xml
81
+ end
82
+
83
+ # Render to a complete HTML document (returns a string)
84
+ def to_html_document(context={})
85
+ indent = context[:indent] || -1
86
+ ie_hack = context[:ie_hack] ||true
87
+ doc = to_html_document_tree
88
+ xml = ""
89
+
90
+ # REXML Bug? if indent!=-1 whitespace is not respected for 'pre' elements
91
+ # containing code.
92
+ doc.write(xml,indent,transitive=true,ie_hack);
93
+
94
+ Xhtml11_mathml2_svg11 + xml
95
+ end
96
+
97
+
98
+ Xhtml10strict =
99
+ "<?xml version='1.0' encoding='utf-8'?>
100
+ <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
101
+ 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>\n"
102
+
103
+ Xhtml11strict_mathml2 = '<?xml version="1.0" encoding="utf-8"?>
104
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"
105
+ "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd" [
106
+ <!ENTITY mathml "http://www.w3.org/1998/Math/MathML">
107
+ ]>
108
+ '
109
+
110
+ Xhtml11_mathml2_svg11 =
111
+ '<?xml version="1.0" encoding="utf-8"?>
112
+ <!DOCTYPE html PUBLIC
113
+ "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
114
+ "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
115
+ '
116
+
117
+
118
+ def xml_newline() Text.new("\n") end
119
+
120
+
121
+ =begin maruku_doc
122
+ Attribute: title
123
+ Scope: document
124
+
125
+ Sets the title of the document.
126
+ If a title is not specified, the first header will be used.
127
+
128
+ These should be equivalent:
129
+
130
+ Title: my document
131
+
132
+ Content
133
+
134
+ and
135
+
136
+ my document
137
+ ===========
138
+
139
+ Content
140
+
141
+ In both cases, the title is set to "my document".
142
+ =end
143
+
144
+ =begin maruku_doc
145
+ Attribute: doc_prefix
146
+ Scope: document
147
+
148
+ String to disambiguate footnote links.
149
+ =end
150
+
151
+
152
+ =begin maruku_doc
153
+ Attribute: subject
154
+ Scope: document
155
+
156
+ Synonim for `title`.
157
+ =end
158
+
159
+
160
+ # Render to an HTML fragment (returns a REXML document tree)
161
+ def to_html_tree
162
+ div = Element.new 'div'
163
+ div.attributes['class'] = 'maruku_wrapper_div'
164
+ children_to_html.each do |e|
165
+ div << e
166
+ end
167
+
168
+ # render footnotes
169
+ if @doc.footnotes_order.size > 0
170
+ div << render_footnotes
171
+ end
172
+
173
+ doc = Document.new(nil,{:respect_whitespace =>:all})
174
+ doc << div
175
+ end
176
+
177
+ =begin maruku_doc
178
+ Attribute: css
179
+ Scope: document
180
+ Output: HTML
181
+ Summary: Activates CSS stylesheets for HTML.
182
+
183
+ `css` should be a space-separated list of urls.
184
+
185
+ Example:
186
+
187
+ CSS: style.css math.css
188
+
189
+ =end
190
+
191
+ METAS = %w{description keywords author revised}
192
+
193
+ # Render to a complete HTML document (returns a REXML document tree)
194
+ def to_html_document_tree
195
+ doc = Document.new(nil,{:respect_whitespace =>:all})
196
+ # doc << XMLDecl.new
197
+
198
+ root = Element.new('html', doc)
199
+ root.add_namespace('http://www.w3.org/1999/xhtml')
200
+ root.add_namespace('svg', "http://www.w3.org/2000/svg" )
201
+ lang = self.attributes[:lang] || 'en'
202
+ root.attributes['xml:lang'] = lang
203
+
204
+ root << xml_newline
205
+ head = Element.new 'head', root
206
+
207
+ #<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
208
+ me = Element.new 'meta', head
209
+ me.attributes['http-equiv'] = 'Content-type'
210
+ # me.attributes['content'] = 'text/html;charset=utf-8'
211
+ me.attributes['content'] = 'application/xhtml+xml;charset=utf-8'
212
+
213
+ METAS.each do |m|
214
+ if value = self.attributes[m.to_sym]
215
+ meta = Element.new 'meta', head
216
+ meta.attributes['name'] = m
217
+ meta.attributes['content'] = value.to_s
218
+ end
219
+ end
220
+
221
+
222
+ self.attributes.each do |k,v|
223
+ if k.to_s =~ /\Ameta-(.*)\Z/
224
+ meta = Element.new 'meta', head
225
+ meta.attributes['name'] = $1
226
+ meta.attributes['content'] = v.to_s
227
+ end
228
+ end
229
+
230
+
231
+
232
+ # Create title element
233
+ doc_title = self.attributes[:title] || self.attributes[:subject] || ""
234
+ title = Element.new 'title', head
235
+ title << Text.new(doc_title)
236
+
237
+ add_css_to(head)
238
+
239
+
240
+ root << xml_newline
241
+
242
+ body = Element.new 'body'
243
+
244
+ children_to_html.each do |e|
245
+ body << e
246
+ end
247
+
248
+ # render footnotes
249
+ if @doc.footnotes_order.size > 0
250
+ body << render_footnotes
251
+ end
252
+
253
+ # When we are rendering a whole document, we add a signature
254
+ # at the bottom.
255
+ if get_setting(:maruku_signature)
256
+ body << maruku_html_signature
257
+ end
258
+
259
+ root << body
260
+
261
+ doc
262
+ end
263
+
264
+ def add_css_to(head)
265
+ if css_list = self.attributes[:css]
266
+ css_list.split.each do |css|
267
+ # <link type="text/css" rel="stylesheet" href="..." />
268
+ link = Element.new 'link'
269
+ link.attributes['type'] = 'text/css'
270
+ link.attributes['rel'] = 'stylesheet'
271
+ link.attributes['href'] = css
272
+ head << link
273
+ head << xml_newline
274
+ end
275
+ end
276
+ end
277
+
278
+ # returns "st","nd","rd" or "th" as appropriate
279
+ def day_suffix(day)
280
+ s = {
281
+ 1 => 'st',
282
+ 2 => 'nd',
283
+ 3 => 'rd',
284
+ 21 => 'st',
285
+ 22 => 'nd',
286
+ 23 => 'rd',
287
+ 31 => 'st'
288
+ }
289
+ return s[day] || 'th';
290
+ end
291
+
292
+ # formats a nice date
293
+ def nice_date
294
+ t = Time.now
295
+ t.strftime(" at %H:%M on ")+
296
+ t.strftime("%A, %B %d")+
297
+ day_suffix(t.day)+
298
+ t.strftime(", %Y")
299
+ end
300
+
301
+ def maruku_html_signature
302
+ div = Element.new 'div'
303
+ div.attributes['class'] = 'maruku_signature'
304
+ Element.new 'hr', div
305
+ span = Element.new 'span', div
306
+ span.attributes['style'] = 'font-size: small; font-style: italic'
307
+ span << Text.new('Created by ')
308
+ a = Element.new('a', span)
309
+ a.attributes['href'] = 'http://maruku.rubyforge.org'
310
+ a.attributes['title'] = 'Maruku: a Markdown-superset interpreter for Ruby'
311
+ a << Text.new('Maruku')
312
+ span << Text.new(nice_date+".")
313
+ div
314
+ end
315
+
316
+ def render_footnotes()
317
+ div = Element.new 'div'
318
+ div.attributes['class'] = 'footnotes'
319
+ div << Element.new('hr')
320
+ ol = Element.new 'ol'
321
+ @doc.footnotes_order.each_with_index do |fid, i| num = i+1
322
+ f = self.footnotes[fid]
323
+ if f
324
+ li = f.wrap_as_element('li')
325
+ li.attributes['id'] = "#{get_setting(:doc_prefix)}fn:#{num}"
326
+
327
+ a = Element.new 'a'
328
+ a.attributes['href'] = "\##{get_setting(:doc_prefix)}fnref:#{num}"
329
+ a.attributes['rev'] = 'footnote'
330
+ a<< Text.new('&#8617;', true, nil, true)
331
+ li.insert_after(li.children.last, a)
332
+ ol << li
333
+ else
334
+ maruku_error "Could not find footnote id '#{fid}' among ["+
335
+ self.footnotes.keys.map{|s|"'"+s+"'"}.join(', ')+"]."
336
+ end
337
+ end
338
+ div << ol
339
+ div
340
+ end
341
+
342
+
343
+ def to_html_hrule; create_html_element 'hr' end
344
+ def to_html_linebreak; Element.new 'br' end
345
+
346
+ # renders children as html and wraps into an element of given name
347
+ #
348
+ # Sets 'id' if meta is set
349
+ def wrap_as_element(name, attributes_to_copy=[])
350
+ m = create_html_element(name, attributes_to_copy)
351
+ children_to_html.each do |e| m << e; end
352
+
353
+ # m << Comment.new( "{"+self.al.to_md+"}") if not self.al.empty?
354
+ # m << Comment.new( @attributes.inspect) if not @attributes.empty?
355
+ m
356
+ end
357
+
358
+ =begin maruku_doc
359
+ Attribute: id
360
+ Scope: element
361
+ Output: LaTeX, HTML
362
+
363
+ It is copied as a standard HTML attribute.
364
+
365
+ Moreover, it used as a label name for hyperlinks in both HTML and
366
+ in PDF.
367
+
368
+ =end
369
+
370
+ =begin maruku_doc
371
+ Attribute: class
372
+ Scope: element
373
+ Output: HTML
374
+
375
+ It is copied as a standard HTML attribute.
376
+ =end
377
+
378
+ =begin maruku_doc
379
+ Attribute: style
380
+ Scope: element
381
+ Output: HTML
382
+
383
+ It is copied as a standard HTML attribute.
384
+ =end
385
+
386
+
387
+
388
+
389
+
390
+ HTML4Attributes = {}
391
+
392
+ coreattrs = [:id, :class, :style, :title]
393
+ i18n = [:lang, 'xml:lang'.to_sym]
394
+ events = [
395
+ :onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover,
396
+ :onmousemove, :onmouseout,
397
+ :onkeypress, :onkeydown, :onkeyup]
398
+ attrs = coreattrs + i18n + events
399
+ cellhalign = [:align, :char, :charoff]
400
+ cellvalign = [:valign]
401
+ [
402
+ ['body', attrs + [:onload, :onunload]],
403
+ ['address', attrs],
404
+ ['div', attrs],
405
+ ['a', attrs+[:charset, :type, :name, :rel, :rev, :accesskey, :shape, :coords, :tabindex,
406
+ :onfocus,:onblur]],
407
+ ['img', attrs + [:longdesc, :name, :height, :width, :alt] ],
408
+ ['p', attrs],
409
+ [['h1','h2','h3','h4','h5','h6'], attrs],
410
+ [['pre'], attrs],
411
+ [['q', 'blockquote'], attrs+[:cite]],
412
+ [['ins','del'], attrs+[:cite,:datetime]],
413
+ [['ol','ul','li'], attrs],
414
+ ['table',attrs+[:summary, :width, :frame, :rules, :border, :cellspacing, :cellpadding]],
415
+ ['caption',attrs],
416
+ [['colgroup','col'],attrs+[:span, :width]+cellhalign+cellvalign],
417
+ [['thead','tbody','tfoot'], attrs+cellhalign+cellvalign],
418
+ [['td','td','th'], attrs+[:abbr, :axis, :headers, :scope, :rowspan, :colspan, :cellvalign, :cellhalign]],
419
+
420
+ # altri
421
+ [['em','code','strong','hr','span','dl','dd','dt'], attrs]
422
+ ].each do |el, a| [*el].each do |e| HTML4Attributes[e] = a end end
423
+
424
+
425
+ def create_html_element(name, attributes_to_copy=[])
426
+ m = Element.new name
427
+ if atts = HTML4Attributes[name] then
428
+ atts.each do |att|
429
+ if v = @attributes[att] then
430
+ m.attributes[att.to_s] = v.to_s
431
+ end
432
+ end
433
+ else
434
+ # puts "not atts for #{name.inspect}"
435
+ end
436
+ m
437
+ end
438
+
439
+
440
+ def to_html_ul
441
+ if @attributes[:toc]
442
+ # render toc
443
+ html_toc = @doc.toc.to_html
444
+ return html_toc
445
+ else
446
+ add_ws wrap_as_element('ul')
447
+ end
448
+ end
449
+
450
+
451
+ def to_html_paragraph; add_ws wrap_as_element('p') end
452
+ def to_html_ol; add_ws wrap_as_element('ol') end
453
+ def to_html_li; add_ws wrap_as_element('li') end
454
+ def to_html_li_span; add_ws wrap_as_element('li') end
455
+ def to_html_quote; add_ws wrap_as_element('blockquote') end
456
+ def to_html_strong; wrap_as_element('strong') end
457
+ def to_html_emphasis; wrap_as_element('em') end
458
+
459
+ =begin maruku_doc
460
+ Attribute: use_numbered_headers
461
+ Scope: document
462
+ Summary: Activates the numbering of headers.
463
+
464
+ If `true`, section headers will be numbered.
465
+
466
+ In LaTeX export, the numbering of headers is managed
467
+ by Maruku, to have the same results in both HTML and LaTeX.
468
+ =end
469
+
470
+ # nil if not applicable, else string
471
+ def section_number
472
+ return nil if not get_setting(:use_numbered_headers)
473
+
474
+ n = @attributes[:section_number]
475
+ if n && (not n.empty?)
476
+ n.join('.')+". "
477
+ else
478
+ nil
479
+ end
480
+ end
481
+
482
+ # nil if not applicable, else SPAN element
483
+ def render_section_number
484
+ # if we are bound to a section, add section number
485
+ if num = section_number
486
+ span = Element.new 'span'
487
+ span.attributes['class'] = 'maruku_section_number'
488
+ span << Text.new(section_number)
489
+ span
490
+ else
491
+ nil
492
+ end
493
+ end
494
+
495
+ def to_html_header
496
+ element_name = "h#{self.level}"
497
+ h = wrap_as_element element_name
498
+
499
+ if span = render_section_number
500
+ h.insert_before(h.children.first, span)
501
+ end
502
+ add_ws h
503
+ end
504
+
505
+ def source2html(source)
506
+ # source = source.gsub(/&/,'&amp;')
507
+ source = Text.normalize(source)
508
+ source = source.gsub(/\&apos;/,'&#39;') # IE bug
509
+ source = source.gsub(/'/,'&#39;') # IE bug
510
+ Text.new(source, true, nil, true )
511
+ end
512
+
513
+ =begin maruku_doc
514
+ Attribute: html_use_syntax
515
+ Scope: global, document, element
516
+ Output: HTML
517
+ Summary: Enables the use of the `syntax` package.
518
+ Related: lang, code_lang
519
+ Default: <?mrk md_code(Globals[:html_use_syntax].to_s) ?>
520
+
521
+ If true, the `syntax` package is used. It supports the `ruby` and `xml`
522
+ languages. Remember to set the `lang` attribute of the code block.
523
+
524
+ Examples:
525
+
526
+ require 'maruku'
527
+ {:lang=ruby html_use_syntax=true}
528
+
529
+ and
530
+
531
+ <div style="text-align:center">Div</div>
532
+ {:lang=html html_use_syntax=true}
533
+
534
+ produces:
535
+
536
+ require 'maruku'
537
+ {:lang=ruby html_use_syntax=true}
538
+
539
+ and
540
+
541
+ <div style="text-align:center">Div</div>
542
+ {:lang=html html_use_syntax=true}
543
+
544
+ =end
545
+
546
+ $syntax_loaded = false
547
+ def to_html_code;
548
+ source = self.raw_code
549
+
550
+ lang = self.attributes[:lang] || @doc.attributes[:code_lang]
551
+
552
+ lang = 'xml' if lang=='html'
553
+
554
+ use_syntax = get_setting :html_use_syntax
555
+
556
+ element =
557
+ if use_syntax && lang
558
+ begin
559
+ if not $syntax_loaded
560
+ require 'rubygems'
561
+ require 'syntax'
562
+ require 'syntax/convertors/html'
563
+ $syntax_loaded = true
564
+ end
565
+ convertor = Syntax::Convertors::HTML.for_syntax lang
566
+
567
+ # eliminate trailing newlines otherwise Syntax crashes
568
+ source = source.gsub(/\n*\Z/,'')
569
+
570
+ html = convertor.convert( source )
571
+ html = html.gsub(/\&apos;/,'&#39;') # IE bug
572
+ html = html.gsub(/'/,'&#39;') # IE bug
573
+ # html = html.gsub(/&/,'&amp;')
574
+
575
+ code = Document.new(html, {:respect_whitespace =>:all}).root
576
+ code.name = 'code'
577
+ code.attributes['class'] = lang
578
+ code.attributes['lang'] = lang
579
+
580
+ pre = Element.new 'pre'
581
+ pre << code
582
+ pre
583
+ rescue LoadError => e
584
+ maruku_error "Could not load package 'syntax'.\n"+
585
+ "Please install it, for example using 'gem install syntax'."
586
+ to_html_code_using_pre(source)
587
+ rescue Object => e
588
+ maruku_error"Error while using the syntax library for code:\n#{source.inspect}"+
589
+ "Lang is #{lang} object is: \n"+
590
+ self.inspect +
591
+ "\nException: #{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
592
+
593
+ tell_user("Using normal PRE because the syntax library did not work.")
594
+ to_html_code_using_pre(source)
595
+ end
596
+ else
597
+ to_html_code_using_pre(source)
598
+ end
599
+
600
+ color = get_setting(:code_background_color)
601
+ if color != Globals[:code_background_color]
602
+ element.attributes['style'] = "background-color: #{color};"
603
+ end
604
+ add_ws element
605
+ end
606
+
607
+ =begin maruku_doc
608
+ Attribute: code_background_color
609
+ Scope: global, document, element
610
+ Summary: Background color for code blocks.
611
+
612
+ The format is either a named color (`green`, `red`) or a CSS color
613
+ of the form `#ff00ff`.
614
+
615
+ * for **HTML output**, the value is put straight in the `background-color` CSS
616
+ property of the block.
617
+
618
+ * for **LaTeX output**, if it is a named color, it must be a color accepted
619
+ by the LaTeX `color` packages. If it is of the form `#ff00ff`, Maruku
620
+ defines a color using the `\color[rgb]{r,g,b}` macro.
621
+
622
+ For example, for `#0000ff`, the macro is called as: `\color[rgb]{0,0,1}`.
623
+
624
+ =end
625
+
626
+
627
+ def to_html_code_using_pre(source)
628
+ pre = create_html_element 'pre'
629
+ code = Element.new 'code', pre
630
+ s = source
631
+
632
+ # s = s.gsub(/&/,'&amp;')
633
+ s = Text.normalize(s)
634
+ s = s.gsub(/\&apos;/,'&#39;') # IE bug
635
+ s = s.gsub(/'/,'&#39;') # IE bug
636
+
637
+ if get_setting(:code_show_spaces)
638
+ # 187 = raquo
639
+ # 160 = nbsp
640
+ # 172 = not
641
+ s.gsub!(/\t/,'&#187;'+'&#160;'*3)
642
+ s.gsub!(/ /,'&#172;')
643
+ end
644
+
645
+ text = Text.new(s, respect_ws=true, parent=nil, raw=true )
646
+
647
+ if lang = self.attributes[:lang]
648
+ code.attributes['lang'] = lang
649
+ code.attributes['class'] = lang
650
+ end
651
+ code << text
652
+ pre
653
+ end
654
+
655
+ def to_html_inline_code;
656
+ pre = create_html_element 'code'
657
+ source = self.raw_code
658
+ pre << source2html(source)
659
+
660
+ color = get_setting(:code_background_color)
661
+ if color != Globals[:code_background_color]
662
+ pre.attributes['style'] = "background-color: #{color};"+(pre.attributes['style']||"")
663
+ end
664
+
665
+ pre
666
+ end
667
+
668
+ def add_class_to(el, cl)
669
+ el.attributes['class'] =
670
+ if already = el.attributes['class']
671
+ already + " " + cl
672
+ else
673
+ cl
674
+ end
675
+ end
676
+
677
+ def add_class_to_link(a)
678
+ return # not ready yet
679
+
680
+ # url = a.attributes['href']
681
+ # return if not url
682
+ #
683
+ # if url =~ /^#/
684
+ # add_class_to(a, 'maruku-link-samedoc')
685
+ # elsif url =~ /^http:/
686
+ # add_class_to(a, 'maruku-link-external')
687
+ # else
688
+ # add_class_to(a, 'maruku-link-local')
689
+ # end
690
+ #
691
+ # puts a.attributes['class']
692
+ end
693
+
694
+
695
+ def to_html_immediate_link
696
+ a = create_html_element 'a'
697
+ url = self.url
698
+ text = url.gsub(/^mailto:/,'') # don't show mailto
699
+ a << Text.new(text)
700
+ a.attributes['href'] = url
701
+ add_class_to_link(a)
702
+ a
703
+ end
704
+
705
+ def to_html_link
706
+ a = wrap_as_element 'a'
707
+ id = self.ref_id
708
+
709
+ if ref = @doc.refs[id]
710
+ url = ref[:url]
711
+ title = ref[:title]
712
+ a.attributes['href'] = url if url
713
+ a.attributes['title'] = title if title
714
+ else
715
+ maruku_error "Could not find ref_id = #{id.inspect} for #{self.inspect}\n"+
716
+ "Available refs are #{@doc.refs.keys.inspect}"
717
+ tell_user "Not creating a link for ref_id = #{id.inspect}."
718
+ return wrap_as_element('span')
719
+ end
720
+
721
+ # add_class_to_link(a)
722
+ return a
723
+ end
724
+
725
+ def to_html_im_link
726
+ if url = self.url
727
+ title = self.title
728
+ a = wrap_as_element 'a'
729
+ a.attributes['href'] = url
730
+ a.attributes['title'] = title if title
731
+ return a
732
+ else
733
+ maruku_error"Could not find url in #{self.inspect}"
734
+ tell_user "Not creating a link for ref_id = #{id.inspect}."
735
+ return wrap_as_element('span')
736
+ end
737
+ end
738
+
739
+ def add_ws(e)
740
+ [Text.new("\n"), e, Text.new("\n")]
741
+ end
742
+ ##### Email address
743
+
744
+ def obfuscate(s)
745
+ res = ''
746
+ s.each_byte do |char|
747
+ res += "&#%03d;" % char
748
+ end
749
+ res
750
+ end
751
+
752
+ def to_html_email_address
753
+ email = self.email
754
+ a = create_html_element 'a'
755
+ #a.attributes['href'] = Text.new("mailto:"+obfuscate(email),false,nil,true)
756
+ #a.attributes.add Attribute.new('href',Text.new(
757
+ #"mailto:"+obfuscate(email),false,nil,true))
758
+ # Sorry, for the moment it doesn't work
759
+ a.attributes['href'] = "mailto:#{email}"
760
+
761
+ a << Text.new(obfuscate(email),false,nil,true)
762
+ a
763
+ end
764
+
765
+ ##### Images
766
+
767
+ def to_html_image
768
+ a = create_html_element 'img'
769
+ id = self.ref_id
770
+ if ref = @doc.refs[id]
771
+ url = ref[:url]
772
+ title = ref[:title]
773
+ a.attributes['src'] = url.to_s
774
+ a.attributes['alt'] = children_to_s
775
+ else
776
+ maruku_error"Could not find id = #{id.inspect} for\n #{self.inspect}"
777
+ tell_user "Could not create image with ref_id = #{id.inspect};"+
778
+ " Using SPAN element as replacement."
779
+ return wrap_as_element('span')
780
+ end
781
+ return a
782
+ end
783
+
784
+ def to_html_im_image
785
+ if not url = self.url
786
+ maruku_error "Image with no url: #{self.inspect}"
787
+ tell_user "Could not create image with ref_id = #{id.inspect};"+
788
+ " Using SPAN element as replacement."
789
+ return wrap_as_element('span')
790
+ end
791
+ title = self.title
792
+ a = create_html_element 'img'
793
+ a.attributes['src'] = url.to_s
794
+ a.attributes['alt'] = children_to_s
795
+ return a
796
+ end
797
+
798
+ =begin maruku_doc
799
+ Attribute: filter_html
800
+ Scope: document
801
+
802
+ If true, raw HTML is discarded from the output.
803
+
804
+ =end
805
+
806
+ def to_html_raw_html
807
+ return [] if get_setting(:filter_html)
808
+
809
+ raw_html = self.raw_html
810
+ if rexml_doc = @parsed_html
811
+ root = rexml_doc.root
812
+ if root.nil?
813
+ s = "Bug in REXML: root() of Document is nil: \n#{rexml_doc.inspect}\n"+
814
+ "Raw HTML:\n#{raw_html.inspect}"
815
+ maruku_error s
816
+ tell_user 'The REXML version you have has a bug, omitting HTML'
817
+ div = Element.new 'div'
818
+ #div << Text.new(s)
819
+ return div
820
+ end
821
+
822
+ # copies the @children array (FIXME is it deep?)
823
+ elements = root.to_a
824
+ return elements
825
+ else # invalid
826
+ # Creates red box with offending HTML
827
+ tell_user "Wrapping bad html in a PRE with class 'markdown-html-error'\n"+
828
+ add_tabs(raw_html,1,'|')
829
+ pre = Element.new('pre')
830
+ pre.attributes['style'] = 'border: solid 3px red; background-color: pink'
831
+ pre.attributes['class'] = 'markdown-html-error'
832
+ pre << Text.new("REXML could not parse this XML/HTML: \n#{raw_html}", true)
833
+ return pre
834
+ end
835
+ end
836
+
837
+ def to_html_abbr
838
+ abbr = Element.new 'abbr'
839
+ abbr << Text.new(children[0])
840
+ abbr.attributes['title'] = self.title if self.title
841
+ abbr
842
+ end
843
+
844
+ def to_html_footnote_reference
845
+ id = self.footnote_id
846
+
847
+ # save the order of used footnotes
848
+ order = @doc.footnotes_order
849
+
850
+ if order.include? id
851
+ # footnote has already been used
852
+ return []
853
+ end
854
+
855
+ if not @doc.footnotes[id]
856
+ return []
857
+ end
858
+
859
+ # take next number
860
+ order << id
861
+
862
+ #num = order.size;
863
+ num = order.index(id) + 1
864
+
865
+ sup = Element.new 'sup'
866
+ sup.attributes['id'] = "#{get_setting(:doc_prefix)}fnref:#{num}"
867
+ a = Element.new 'a'
868
+ a << Text.new(num.to_s)
869
+ a.attributes['href'] = "\##{get_setting(:doc_prefix)}fn:#{num}"
870
+ a.attributes['rel'] = 'footnote'
871
+ sup << a
872
+
873
+ sup
874
+ end
875
+
876
+ ## Definition lists ###
877
+ def to_html_definition_list() add_ws wrap_as_element('dl') end
878
+ def to_html_definition() children_to_html end
879
+ def to_html_definition_term() add_ws wrap_as_element('dt') end
880
+ def to_html_definition_data() add_ws wrap_as_element('dd') end
881
+
882
+ # FIXME: Ugly code
883
+ def to_html_table
884
+ align = self.align
885
+ num_columns = align.size
886
+
887
+ head = @children.slice(0, num_columns)
888
+ rows = []
889
+ i = num_columns
890
+ while i<@children.size
891
+ rows << @children.slice(i, num_columns)
892
+ i += num_columns
893
+ end
894
+
895
+ table = create_html_element 'table'
896
+ thead = Element.new 'thead'
897
+ tr = Element.new 'tr'
898
+ array_to_html(head).each do |x| tr<<x end
899
+ thead << tr
900
+ table << thead
901
+
902
+ tbody = Element.new 'tbody'
903
+ rows.each do |row|
904
+ tr = Element.new 'tr'
905
+ array_to_html(row).each_with_index do |x,i|
906
+ x.attributes['style'] ="text-align: #{align[i].to_s};"
907
+ tr<<x
908
+ end
909
+
910
+ tbody << tr << Text.new("\n")
911
+ end
912
+ table << tbody
913
+ table
914
+ end
915
+
916
+ def to_html_head_cell; wrap_as_element('th') end
917
+ def to_html_cell
918
+ if @attributes[:scope]
919
+ wrap_as_element('th', [:scope])
920
+ else
921
+ wrap_as_element('td')
922
+ end
923
+ end
924
+
925
+ def to_html_entity
926
+ MaRuKu::Out::Latex.need_entity_table
927
+
928
+ entity_name = self.entity_name
929
+
930
+ if (e = MaRuKu::Out::Latex::ENTITY_TABLE[entity_name]) && e.html_num
931
+ entity_name = e.html_num
932
+ end
933
+
934
+ # Fix for Internet Explorer
935
+ if entity_name == 'apos'
936
+ entity_name = 39
937
+ end
938
+
939
+
940
+ if entity_name.kind_of? Fixnum
941
+ # Entity.new(entity_name)
942
+ Text.new('&#%d;' % [entity_name], false, nil, true)
943
+ else
944
+ Text.new('&%s;' % [entity_name], false, nil, true)
945
+ end
946
+ end
947
+
948
+ def to_html_xml_instr
949
+ target = self.target || ''
950
+ code = self.code || ''
951
+ REXML::Instruction.new(target, code)
952
+ end
953
+
954
+ # Convert each child to html
955
+ def children_to_html
956
+ array_to_html(@children)
957
+ end
958
+
959
+ def array_to_html(array)
960
+ e = []
961
+ array.each do |c|
962
+ method = c.kind_of?(MDElement) ?
963
+ "to_html_#{c.node_type}" : "to_html"
964
+
965
+ if not c.respond_to?(method)
966
+ #raise "Object does not answer to #{method}: #{c.class} #{c.inspect}"
967
+ next
968
+ end
969
+
970
+ h = c.send(method)
971
+
972
+ if h.nil?
973
+ raise "Nil html created by method #{method}:\n#{h.inspect}\n"+
974
+ " for object #{c.inspect[0,300]}"
975
+ end
976
+
977
+ if h.kind_of?Array
978
+ e = e + h #h.each do |hh| e << hh end
979
+ else
980
+ e << h
981
+ end
982
+ end
983
+ e
984
+ end
985
+
986
+ def to_html_ref_definition; [] end
987
+ def to_latex_ref_definition; [] end
988
+
989
+ end # HTML
990
+ end # out
991
+ end # MaRuKu