maiku 0.6.1.maiku

Sign up to get free protection for your applications and to get access to all the features.
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