maruku 0.6.1 → 0.7.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (263) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/MIT-LICENSE.txt +20 -0
  5. data/bin/maruku +153 -152
  6. data/bin/marutex +2 -29
  7. data/data/entities.xml +261 -0
  8. data/docs/math.md +14 -18
  9. data/lib/maruku.rb +65 -77
  10. data/lib/maruku/attributes.rb +109 -214
  11. data/lib/maruku/defaults.rb +45 -67
  12. data/lib/maruku/document.rb +43 -0
  13. data/lib/maruku/element.rb +112 -0
  14. data/lib/maruku/errors.rb +71 -0
  15. data/lib/maruku/ext/div.rb +105 -113
  16. data/lib/maruku/ext/fenced_code.rb +97 -0
  17. data/lib/maruku/ext/math.rb +22 -26
  18. data/lib/maruku/ext/math/elements.rb +20 -26
  19. data/lib/maruku/ext/math/mathml_engines/blahtex.rb +92 -104
  20. data/lib/maruku/ext/math/mathml_engines/itex2mml.rb +33 -26
  21. data/lib/maruku/ext/math/mathml_engines/none.rb +11 -19
  22. data/lib/maruku/ext/math/mathml_engines/ritex.rb +2 -4
  23. data/lib/maruku/ext/math/parsing.rb +107 -113
  24. data/lib/maruku/ext/math/to_html.rb +184 -187
  25. data/lib/maruku/ext/math/to_latex.rb +30 -21
  26. data/lib/maruku/helpers.rb +158 -257
  27. data/lib/maruku/html.rb +254 -0
  28. data/lib/maruku/input/charsource.rb +272 -319
  29. data/lib/maruku/input/extensions.rb +62 -63
  30. data/lib/maruku/input/html_helper.rb +220 -189
  31. data/lib/maruku/input/linesource.rb +90 -110
  32. data/lib/maruku/input/mdline.rb +129 -0
  33. data/lib/maruku/input/parse_block.rb +618 -612
  34. data/lib/maruku/input/parse_doc.rb +145 -215
  35. data/lib/maruku/input/parse_span.rb +658 -0
  36. data/lib/maruku/input/rubypants.rb +200 -128
  37. data/lib/maruku/inspect_element.rb +60 -0
  38. data/lib/maruku/maruku.rb +10 -31
  39. data/lib/maruku/output/entity_table.rb +33 -0
  40. data/lib/maruku/output/s5/fancy.rb +462 -462
  41. data/lib/maruku/output/s5/to_s5.rb +115 -135
  42. data/lib/maruku/output/to_html.rb +898 -983
  43. data/lib/maruku/output/to_latex.rb +561 -560
  44. data/lib/maruku/output/to_markdown.rb +207 -162
  45. data/lib/maruku/output/to_s.rb +11 -52
  46. data/lib/maruku/string_utils.rb +129 -179
  47. data/lib/maruku/toc.rb +185 -196
  48. data/lib/maruku/version.rb +33 -38
  49. data/spec/block_docs/abbrev.md +776 -0
  50. data/{tests/unittest → spec/block_docs}/abbreviations.md +11 -20
  51. data/{tests/unittest → spec/block_docs}/alt.md +2 -14
  52. data/{tests/unittest/pending → spec/block_docs}/amps.md +1 -13
  53. data/{tests/unittest → spec/block_docs}/attributes/att2.md +0 -12
  54. data/{tests/unittest → spec/block_docs}/attributes/att3.md +2 -14
  55. data/{tests/unittest → spec/block_docs}/attributes/attributes.md +12 -16
  56. data/{tests/unittest → spec/block_docs}/attributes/circular.md +0 -12
  57. data/{tests/unittest → spec/block_docs}/attributes/default.md +1 -13
  58. data/{tests/unittest → spec/block_docs}/blank.md +0 -12
  59. data/{tests/unittest → spec/block_docs}/blanks_in_code.md +16 -15
  60. data/{tests/unittest/loss.md → spec/block_docs/bug_def.md} +6 -18
  61. data/{tests/unittest → spec/block_docs}/bug_table.md +3 -15
  62. data/{tests/unittest → spec/block_docs}/code.md +7 -14
  63. data/{tests/unittest → spec/block_docs}/code2.md +4 -14
  64. data/{tests/unittest → spec/block_docs}/code3.md +12 -16
  65. data/{tests/unittest → spec/block_docs}/data_loss.md +2 -14
  66. data/{tests/unittest → spec/block_docs}/divs/div1.md +0 -12
  67. data/{tests/unittest → spec/block_docs}/divs/div2.md +0 -12
  68. data/{tests/unittest → spec/block_docs}/divs/div3_nest.md +3 -15
  69. data/{tests/unittest → spec/block_docs}/easy.md +1 -13
  70. data/spec/block_docs/email.md +29 -0
  71. data/{tests/unittest/pending → spec/block_docs}/empty_cells.md +3 -15
  72. data/{tests/unittest → spec/block_docs}/encoding/iso-8859-1.md +1 -14
  73. data/{tests/unittest → spec/block_docs}/encoding/utf-8.md +0 -12
  74. data/{tests/unittest → spec/block_docs}/entities.md +27 -29
  75. data/{tests/unittest/notyet → spec/block_docs}/escape.md +2 -14
  76. data/{tests/unittest → spec/block_docs}/escaping.md +11 -22
  77. data/{tests/unittest → spec/block_docs}/extra_dl.md +2 -13
  78. data/{tests/unittest → spec/block_docs}/extra_header_id.md +14 -20
  79. data/{tests/unittest → spec/block_docs}/extra_table1.md +3 -15
  80. data/spec/block_docs/fenced_code_blocks.md +66 -0
  81. data/spec/block_docs/fenced_code_blocks_highlighted.md +18 -0
  82. data/{tests/unittest → spec/block_docs}/footnotes.md +12 -24
  83. data/spec/block_docs/footnotes2.md +78 -0
  84. data/spec/block_docs/hard.md +25 -0
  85. data/spec/block_docs/header_after_par.md +62 -0
  86. data/{tests/unittest → spec/block_docs}/headers.md +10 -18
  87. data/{tests/unittest → spec/block_docs}/hex_entities.md +7 -18
  88. data/{tests/unittest → spec/block_docs}/hrule.md +5 -12
  89. data/{tests/unittest → spec/block_docs}/html3.md +1 -13
  90. data/{tests/unittest → spec/block_docs}/html4.md +2 -14
  91. data/{tests/unittest → spec/block_docs}/html5.md +2 -14
  92. data/spec/block_docs/html_block_in_para.md +22 -0
  93. data/spec/block_docs/html_inline.md +25 -0
  94. data/spec/block_docs/html_trailing.md +31 -0
  95. data/spec/block_docs/ie.md +62 -0
  96. data/spec/block_docs/iframe.md +29 -0
  97. data/{tests/unittest → spec/block_docs}/images.md +22 -28
  98. data/{tests/unittest → spec/block_docs}/images2.md +7 -17
  99. data/{tests/unittest → spec/block_docs}/inline_html.md +37 -67
  100. data/{tests/unittest → spec/block_docs}/inline_html2.md +1 -13
  101. data/spec/block_docs/inline_html_beginning.md +10 -0
  102. data/spec/block_docs/issue20.md +9 -0
  103. data/spec/block_docs/issue26.md +22 -0
  104. data/spec/block_docs/issue29.md +9 -0
  105. data/spec/block_docs/issue30.md +30 -0
  106. data/spec/block_docs/issue31.md +25 -0
  107. data/spec/block_docs/issue40.md +40 -0
  108. data/spec/block_docs/issue64.md +55 -0
  109. data/spec/block_docs/issue67.md +19 -0
  110. data/spec/block_docs/issue70.md +11 -0
  111. data/spec/block_docs/issue72.md +17 -0
  112. data/spec/block_docs/issue74.md +38 -0
  113. data/spec/block_docs/issue79.md +15 -0
  114. data/spec/block_docs/issue83.md +13 -0
  115. data/spec/block_docs/issue85.md +25 -0
  116. data/spec/block_docs/issue88.md +19 -0
  117. data/spec/block_docs/issue89.md +12 -0
  118. data/spec/block_docs/issue90.md +38 -0
  119. data/{tests/unittest/pending → spec/block_docs}/link.md +21 -18
  120. data/{tests/unittest → spec/block_docs}/links.md +33 -32
  121. data/spec/block_docs/links2.md +21 -0
  122. data/{tests/unittest → spec/block_docs}/list1.md +0 -12
  123. data/{tests/unittest → spec/block_docs}/list12.md +2 -14
  124. data/{tests/unittest → spec/block_docs}/list2.md +2 -14
  125. data/spec/block_docs/list_multipara.md +42 -0
  126. data/{tests/unittest → spec/block_docs}/lists.md +28 -29
  127. data/{tests/unittest → spec/block_docs}/lists10.md +2 -14
  128. data/spec/block_docs/lists11.md +23 -0
  129. data/spec/block_docs/lists12.md +43 -0
  130. data/spec/block_docs/lists13.md +55 -0
  131. data/spec/block_docs/lists14.md +61 -0
  132. data/spec/block_docs/lists15.md +36 -0
  133. data/spec/block_docs/lists6.md +88 -0
  134. data/spec/block_docs/lists7b.md +58 -0
  135. data/spec/block_docs/lists9.md +53 -0
  136. data/{tests/unittest → spec/block_docs}/lists_after_paragraph.md +19 -25
  137. data/spec/block_docs/lists_blank.md +35 -0
  138. data/{tests/unittest/list3.md → spec/block_docs/lists_blockquote_code.md} +2 -14
  139. data/{tests/unittest/list4.md → spec/block_docs/lists_need_blank_line.md} +50 -21
  140. data/spec/block_docs/lists_nested.md +44 -0
  141. data/spec/block_docs/lists_nested_blankline.md +28 -0
  142. data/spec/block_docs/lists_nested_deep.md +43 -0
  143. data/{tests/unittest → spec/block_docs}/lists_ol.md +37 -54
  144. data/spec/block_docs/lists_paraindent.md +47 -0
  145. data/spec/block_docs/lists_tab.md +54 -0
  146. data/spec/block_docs/loss.md +17 -0
  147. data/spec/block_docs/math-blahtex/equations.md +30 -0
  148. data/spec/block_docs/math-blahtex/inline.md +48 -0
  149. data/spec/block_docs/math-blahtex/math2.md +45 -0
  150. data/spec/block_docs/math-blahtex/table.md +25 -0
  151. data/spec/block_docs/math/embedded_invalid_svg.md +79 -0
  152. data/spec/block_docs/math/embedded_svg.md +97 -0
  153. data/spec/block_docs/math/equations.md +44 -0
  154. data/{tests/unittest → spec/block_docs}/math/inline.md +7 -19
  155. data/spec/block_docs/math/math2.md +45 -0
  156. data/{tests/unittest → spec/block_docs}/math/notmath.md +0 -12
  157. data/spec/block_docs/math/raw_mathml.md +87 -0
  158. data/spec/block_docs/math/table.md +25 -0
  159. data/{tests/unittest → spec/block_docs}/math/table2.md +5 -17
  160. data/{tests/unittest → spec/block_docs}/misc_sw.md +181 -118
  161. data/{tests/unittest → spec/block_docs}/olist.md +6 -18
  162. data/{tests/unittest → spec/block_docs}/one.md +0 -12
  163. data/{tests/unittest → spec/block_docs}/paragraph.md +0 -12
  164. data/{tests/unittest → spec/block_docs}/paragraph_rules/dont_merge_ref.md +4 -12
  165. data/{tests/unittest → spec/block_docs}/paragraph_rules/tab_is_blank.md +0 -12
  166. data/{tests/unittest → spec/block_docs}/paragraphs.md +1 -13
  167. data/{tests/unittest → spec/block_docs}/recover/recover_links.md +4 -16
  168. data/{tests/unittest/pending/ref.md → spec/block_docs/ref_with_period.md} +7 -16
  169. data/spec/block_docs/ref_with_title.md +22 -0
  170. data/{tests/unittest → spec/block_docs}/references/long_example.md +16 -23
  171. data/{tests/unittest → spec/block_docs}/references/spaces_and_numbers.md +0 -12
  172. data/{tests/unittest → spec/block_docs}/smartypants.md +24 -31
  173. data/{tests/unittest → spec/block_docs}/syntax_hl.md +13 -17
  174. data/{tests/unittest → spec/block_docs}/table_attributes.md +2 -14
  175. data/spec/block_docs/tables.md +58 -0
  176. data/{tests/unittest → spec/block_docs}/test.md +1 -13
  177. data/{tests/unittest/notyet → spec/block_docs}/ticks.md +1 -13
  178. data/spec/block_docs/toc.md +87 -0
  179. data/{tests/unittest/notyet → spec/block_docs}/triggering.md +14 -25
  180. data/{tests/unittest → spec/block_docs}/underscore_in_words.md +0 -12
  181. data/{tests/unittest → spec/block_docs}/wrapping.md +4 -16
  182. data/spec/block_docs/xml.md +33 -0
  183. data/{tests/unittest → spec/block_docs}/xml2.md +0 -12
  184. data/spec/block_docs/xml3.md +24 -0
  185. data/{tests/unittest → spec/block_docs}/xml_instruction.md +9 -20
  186. data/spec/block_spec.rb +110 -0
  187. data/spec/cli_spec.rb +8 -0
  188. data/spec/span_spec.rb +256 -0
  189. data/spec/spec_helper.rb +2 -0
  190. data/spec/to_html_utf8_spec.rb +13 -0
  191. metadata +205 -243
  192. metadata.gz.sig +3 -0
  193. data/Rakefile +0 -48
  194. data/bin/marudown +0 -29
  195. data/bin/marutest +0 -345
  196. data/docs/changelog.md +0 -334
  197. data/lib/maruku/errors_management.rb +0 -92
  198. data/lib/maruku/ext/math/latex_fix.rb +0 -12
  199. data/lib/maruku/input/parse_span_better.rb +0 -746
  200. data/lib/maruku/input/type_detection.rb +0 -147
  201. data/lib/maruku/output/to_latex_entities.rb +0 -367
  202. data/lib/maruku/output/to_latex_strings.rb +0 -64
  203. data/lib/maruku/structures.rb +0 -167
  204. data/lib/maruku/structures_inspect.rb +0 -87
  205. data/lib/maruku/structures_iterators.rb +0 -61
  206. data/lib/maruku/tests/benchmark.rb +0 -82
  207. data/lib/maruku/tests/new_parser.rb +0 -373
  208. data/lib/maruku/tests/tests.rb +0 -136
  209. data/lib/maruku/usage/example1.rb +0 -33
  210. data/tests/bugs/code_in_links.md +0 -101
  211. data/tests/bugs/complex_escaping.md +0 -38
  212. data/tests/math/syntax.md +0 -46
  213. data/tests/math_usage/document.md +0 -13
  214. data/tests/others/abbreviations.md +0 -11
  215. data/tests/others/blank.md +0 -4
  216. data/tests/others/code.md +0 -5
  217. data/tests/others/code2.md +0 -8
  218. data/tests/others/code3.md +0 -16
  219. data/tests/others/email.md +0 -4
  220. data/tests/others/entities.md +0 -19
  221. data/tests/others/escaping.md +0 -16
  222. data/tests/others/extra_dl.md +0 -101
  223. data/tests/others/extra_header_id.md +0 -13
  224. data/tests/others/extra_table1.md +0 -40
  225. data/tests/others/footnotes.md +0 -17
  226. data/tests/others/headers.md +0 -10
  227. data/tests/others/hrule.md +0 -10
  228. data/tests/others/images.md +0 -20
  229. data/tests/others/inline_html.md +0 -42
  230. data/tests/others/links.md +0 -38
  231. data/tests/others/list1.md +0 -4
  232. data/tests/others/list2.md +0 -5
  233. data/tests/others/list3.md +0 -8
  234. data/tests/others/lists.md +0 -32
  235. data/tests/others/lists_after_paragraph.md +0 -44
  236. data/tests/others/lists_ol.md +0 -39
  237. data/tests/others/misc_sw.md +0 -105
  238. data/tests/others/one.md +0 -1
  239. data/tests/others/paragraphs.md +0 -13
  240. data/tests/others/sss06.md +0 -352
  241. data/tests/others/test.md +0 -4
  242. data/tests/s5/s5profiling.md +0 -48
  243. data/tests/unittest/bug_def.md +0 -28
  244. data/tests/unittest/email.md +0 -32
  245. data/tests/unittest/html2.md +0 -34
  246. data/tests/unittest/ie.md +0 -61
  247. data/tests/unittest/links2.md +0 -34
  248. data/tests/unittest/lists11.md +0 -28
  249. data/tests/unittest/lists6.md +0 -53
  250. data/tests/unittest/lists9.md +0 -76
  251. data/tests/unittest/math/equations.md +0 -86
  252. data/tests/unittest/math/math2.md +0 -57
  253. data/tests/unittest/math/table.md +0 -37
  254. data/tests/unittest/notyet/header_after_par.md +0 -70
  255. data/tests/unittest/red_tests/abbrev.md +0 -1388
  256. data/tests/unittest/red_tests/lists7.md +0 -68
  257. data/tests/unittest/red_tests/lists7b.md +0 -128
  258. data/tests/unittest/red_tests/lists8.md +0 -76
  259. data/tests/unittest/red_tests/xml.md +0 -70
  260. data/tests/unittest/xml3.md +0 -38
  261. data/tests/utf8-files/simple.md +0 -1
  262. data/unit_test_block.sh +0 -5
  263. data/unit_test_span.sh +0 -3
@@ -1,138 +1,118 @@
1
- # This module groups all functions related to HTML export.
2
- module MaRuKu
1
+ require 'maruku/output/to_html'
3
2
 
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>
3
+ module MaRuKu
4
+ class MDDocument
5
+ def s5_theme
6
+ xtext(self.attributes[:slide_theme] || "default")
7
+ end
8
+
9
+ # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
10
+ def to_s5(context={})
11
+ content_only = context[:content_only] != false
12
+ print_slides = context[:print_slides]
13
+
14
+ if content_only
15
+ body = xelem('div', doc)
16
+ else
17
+ html = xelem('html')
18
+ html['xmlns'] = 'http://www.w3.org/1999/xhtml'
19
+ html['xmlns:svg'] = "http://www.w3.org/2000/svg"
20
+ html['xml:lang'] = self.attributes[:lang] || 'en'
21
+
22
+ head = xelem('head')
23
+ html << head
24
+
25
+ me = xelem('meta')
26
+ me['http-equiv'] = 'Content-type'
27
+ me['content'] = 'text/html;charset=utf-8'
28
+ head << me
29
+
30
+ # Create title element
31
+ doc_title = self.attributes[:title] || self.attributes[:subject] || ""
32
+ begin
33
+ title_content = MaRuKu::HTMLFragment.new(doc_title).to_html
34
+ rescue
35
+ title_content = xtext(doc_title)
36
+ end
37
+ title = xelem('title') << title_content
38
+ head << title
39
+
40
+ body = xelem('body')
41
+ html << body
42
+ end
43
+
44
+ slide_header = self.attributes[:slide_header]
45
+ slide_footer = self.attributes[:slide_footer]
46
+ slide_subfooter = self.attributes[:slide_subfooter]
47
+ slide_topleft = self.attributes[:slide_topleft]
48
+ slide_topright = self.attributes[:slide_topright]
49
+ slide_bottomleft = self.attributes[:slide_bottomleft]
50
+ slide_bottomright = self.attributes[:slide_bottomright]
51
+
52
+ dummy_layout_slide = "
53
+ <div class='layout'>
54
+ <div id='controls'> </div>
55
+ <div id='currentSlide'> </div>
56
+ <div id='header'> #{slide_header}</div>
57
+ <div id='footer'>
58
+ <h1>#{slide_footer}</h1>
59
+ <h2>#{slide_subfooter}</h2>
60
+ </div>
61
+ <div class='topleft'> #{slide_topleft}</div>
62
+ <div class='topright'> #{slide_topright}</div>
63
+ <div class='bottomleft'> #{slide_bottomleft}</div>
64
+ <div class='bottomright'> #{slide_bottomright}</div>
65
+ </div>
77
66
  "
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
-
67
+ body << dummy_layout_slide
68
+
69
+ presentation = xelem('div')
70
+ presentation['class'] = 'presentation'
71
+ body << presentation
72
+
73
+ first_slide = "
74
+ <div class='slide'>
75
+ <h1> #{self.attributes[:title] ||context[:title]}</h1>
76
+ <h2> #{self.attributes[:subtitle] ||context[:subtitle]}</h2>
77
+ <h3> #{self.attributes[:author] ||context[:author]}</h3>
78
+ <h4> #{self.attributes[:company] ||context[:company]}</h4>
79
+ </div>
80
+ "
81
+ presentation << first_slide
82
+
83
+ slide_num = 0
84
+ self.toc.section_children.each do |slide|
85
+ slide_num += 1
86
+ @doc.attributes[:doc_prefix] = "s#{slide_num}"
87
+
88
+ div = xelem('div')
89
+ presentation << div
90
+ div['class'] = 'slide'
91
+
92
+ h1 = xelem('h1')
93
+ puts "Slide #{slide_num}: #{slide.header_element.children_to_html.join}" if print_slides
94
+ slide.header_element.children_to_html.inject(h1, &:<<)
95
+ div << h1
96
+
97
+ array_to_html(slide.immediate_children).inject(div, &:<<)
98
+
99
+ # render footnotes
100
+ unless @doc.footnotes_order.empty?
101
+ div << render_footnotes
102
+ @doc.footnotes_order = []
103
+ end
104
+ end
105
+
106
+ if content_only
107
+ xml = body.to_html
108
+ else
109
+ head << S5_external
110
+
111
+ add_css_to(head)
112
+
113
+ xml = html.to_html
114
+ Xhtml11_mathml2_svg11 + xml
115
+ end
116
+ end
117
+ end
138
118
  end
@@ -1,991 +1,906 @@
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
1
+ require 'maruku/string_utils'
2
+ require 'cgi'
30
3
 
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
4
+ # This module groups all functions related to HTML export.
5
+ module MaRuKu::Out::HTML
6
+
7
+ # A simple class to represent an HTML element for output.
8
+ class HTMLElement
9
+ attr_accessor :name
10
+ attr_accessor :attributes
11
+ attr_accessor :children
12
+
13
+ def initialize(name, attr={}, children=[])
14
+ self.name = name
15
+ self.attributes = attr || {}
16
+ self.children = Array(children)
17
+ children << yield if block_given?
18
+ end
38
19
 
20
+ def <<(child)
21
+ children << child if children
22
+ self
23
+ end
39
24
 
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
- '
25
+ def [](key)
26
+ attributes[key.to_s]
27
+ end
28
+
29
+ def []=(key, value)
30
+ attributes[key.to_s] = value
31
+ end
32
+
33
+ def add_class(class_name)
34
+ attributes['class'] = ((attributes['class']||'').split(' ') + [class_name]).join(' ')
35
+ end
36
+
37
+ # These elements have no children and should be rendered with a self-closing tag.
38
+ # It's not an exhaustive list, but they cover everything we use.
39
+ SELF_CLOSING = Set.new %w[br hr img link meta]
40
+
41
+ def to_html
42
+ m = "<#{name}"
43
+ attributes.each do |k, v|
44
+ m << " #{k.to_s}=\"#{v.to_s}\""
45
+ end
46
+
47
+ if SELF_CLOSING.include? name
48
+ m << " />"
49
+ else
50
+ content = children.map(&:to_s)
51
+ m << ">" << content.join('') << "</#{name}>"
52
+ end
53
+ end
54
+
55
+ alias :to_str :to_html
56
+ alias :to_s :to_html
57
+ end
58
+
59
+ # Render as an HTML fragment (no head, just the content of BODY). (returns a string)
60
+ def to_html(context={})
61
+ output = ""
62
+ children_to_html.each do |e|
63
+ output << e.to_s
64
+ end
109
65
 
110
- Xhtml11_mathml2_svg11 =
111
- '<?xml version="1.0" encoding="utf-8"?>
66
+ # render footnotes
67
+ unless @doc.footnotes_order.empty?
68
+ output << render_footnotes
69
+ end
70
+
71
+ output
72
+ end
73
+
74
+ Xhtml11_mathml2_svg11 =
75
+ '<?xml version="1.0" encoding="utf-8"?>
112
76
  <!DOCTYPE html PUBLIC
113
77
  "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"
114
78
  "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">
115
79
  '
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
80
+
81
+ # Render to a complete HTML document (returns a string)
82
+ def to_html_document(context={})
83
+ doc = to_html_document_tree
84
+
85
+ xml = doc.to_s
86
+ Xhtml11_mathml2_svg11 + xml
87
+ end
88
+
89
+ # Helper to create a text node
90
+ def xtext(text)
91
+ CGI.escapeHTML(text)
92
+ end
93
+
94
+ # Helper to create an element
95
+ def xelem(type)
96
+ HTMLElement.new(type)
97
+ end
98
+
99
+ def xml_newline
100
+ "\n"
101
+ end
102
+
103
+ #=begin maruku_doc
104
+ # Attribute: title
105
+ # Scope: document
106
+ #
107
+ # Sets the title of the document.
108
+ # If a title is not specified, the first header will be used.
109
+ #
110
+ # These should be equivalent:
111
+ #
112
+ # Title: my document
113
+ #
114
+ # Content
115
+ #
116
+ # and
117
+ #
118
+ # my document
119
+ # ===========
120
+ #
121
+ # Content
122
+ #
123
+ # In both cases, the title is set to "my document".
124
+ #=end
125
+
126
+ #=begin maruku_doc
127
+ # Attribute: doc_prefix
128
+ # Scope: document
129
+ #
130
+ # String to disambiguate footnote links.
131
+ #=end
132
+
133
+
134
+ #=begin maruku_doc
135
+ # Attribute: subject
136
+ # Scope: document
137
+
138
+ # Synonym for `title`.
139
+ #=end
140
+
141
+ #=begin maruku_doc
142
+ # Attribute: css
143
+ # Scope: document
144
+ # Output: HTML
145
+ # Summary: Activates CSS stylesheets for HTML.
146
+ #
147
+ # `css` should be a space-separated list of urls.
148
+ #
149
+ # Example:
150
+ #
151
+ # CSS: style.css math.css
152
+ #
153
+ #=end
154
+
155
+ # Render to a complete HTML document (returns an HTMLElement document tree)
156
+ def to_html_document_tree
157
+ root = xelem('html')
158
+ root['xmlns'] = 'http://www.w3.org/1999/xhtml'
159
+ root['xmlns:svg'] = "http://www.w3.org/2000/svg"
160
+ root['xml:lang'] = self.attributes[:lang] || 'en'
161
+
162
+ root << xml_newline
163
+ head = xelem('head')
164
+ root << head
165
+
166
+ #<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
167
+ me = xelem('meta')
168
+ me['http-equiv'] = 'Content-type'
169
+ me['content'] = 'application/xhtml+xml;charset=utf-8'
170
+ head << me
171
+
172
+ %w(description keywords author revised).each do |m|
173
+ if value = self.attributes[m.to_sym]
174
+ meta = xelem('meta')
175
+ meta['name'] = m
176
+ meta['content'] = value.to_s
177
+ head << meta
178
+ end
179
+ end
180
+
181
+ self.attributes.each do |k,v|
182
+ if k.to_s =~ /\Ameta-(.*)\z/
183
+ meta = xelem('meta')
184
+ meta['name'] = $1
185
+ meta['content'] = v.to_s
186
+ head << meta
187
+ end
188
+ end
189
+
190
+ # Create title element
191
+ doc_title = self.attributes[:title] || self.attributes[:subject] || ""
192
+ begin
193
+ title_content = MaRuKu::HTMLFragment.new(doc_title).to_html
194
+ rescue
195
+ title_content = xtext(doc_title)
196
+ end
197
+ title = xelem('title') << title_content
198
+ head << title
199
+ add_css_to(head)
200
+
201
+ root << xml_newline
202
+
203
+ body = xelem('body')
204
+
205
+ children_to_html.each do |e|
206
+ body << e.to_s
207
+ end
208
+
209
+ # render footnotes
210
+ unless @doc.footnotes_order.empty?
211
+ body << render_footnotes(@doc)
212
+ end
213
+
214
+ # When we are rendering a whole document, we add a signature
215
+ # at the bottom.
216
+ if get_setting(:maruku_signature)
217
+ body << maruku_html_signature
218
+ end
219
+
220
+ root << body
221
+ end
222
+
223
+ def add_css_to(head)
224
+ if css_list = self.attributes[:css]
225
+ css_list.split.each do |css|
226
+ # <link type="text/css" rel="stylesheet" href="..." />
227
+ link = xelem('link')
228
+ link['type'] = 'text/css'
229
+ link['rel'] = 'stylesheet'
230
+ link['href'] = css
231
+ head << link << xml_newline
232
+ end
233
+ end
234
+ end
235
+
236
+ # returns "st","nd","rd" or "th" as appropriate
237
+ def day_suffix(day)
238
+ s = {
239
+ 1 => 'st',
240
+ 2 => 'nd',
241
+ 3 => 'rd',
242
+ 21 => 'st',
243
+ 22 => 'nd',
244
+ 23 => 'rd',
245
+ 31 => 'st'
246
+ }
247
+ s[day] || 'th';
248
+ end
249
+
250
+ # formats a nice date
251
+ def nice_date
252
+ Time.now.strftime(" at %H:%M on %A, %B %d") +
253
+ day_suffix(t.day) +
254
+ t.strftime(", %Y")
255
+ end
256
+
257
+ def maruku_html_signature
258
+ div = xelem('div')
259
+ div['class'] = 'maruku_signature'
260
+ div << xelem('hr')
261
+ span = xelem('span')
262
+ span['style'] = 'font-size: small; font-style: italic'
263
+ div << span << xtext('Created by ')
264
+ a = xelem('a')
265
+ a['href'] = MaRuKu::MARUKU_URL
266
+ a['title'] = 'Maruku: a Markdown-superset interpreter for Ruby'
267
+ a << xtext('Maruku')
268
+ span << xtext(nice_date + ".")
269
+ div
270
+ end
271
+
272
+ def render_footnotes
273
+ div = xelem('div')
274
+ div['class'] = 'footnotes'
275
+ div << xelem('hr')
276
+ ol = xelem('ol')
277
+
278
+ @doc.footnotes_order.each_with_index do |fid, i|
279
+ num = i + 1
280
+ if f = self.footnotes[fid]
281
+ li = f.wrap_as_element('li')
282
+ li['id'] = "#{get_setting(:doc_prefix)}fn:#{num}"
283
+
284
+ a = xelem('a')
285
+ a['href'] = "\##{get_setting(:doc_prefix)}fnref:#{num}"
286
+ a['rev'] = 'footnote'
287
+ a << xtext([8617].pack('U*'))
288
+
289
+ last = nil
290
+ li.children.reverse_each do |child|
291
+ if child.is_a?(HTMLElement)
292
+ last = child
293
+ break
294
+ end
295
+ end
296
+
297
+ if last && last.name == "p"
298
+ last << xtext(' ') << a
299
+ else
300
+ li.children << a
301
+ end
302
+ ol << li
303
+ else
304
+ maruku_error "Could not find footnote id '#{fid}' among [#{self.footnotes.keys.inspect}]."
305
+ end
306
+ end
307
+
308
+ div << ol
309
+ end
310
+
311
+ def to_html_hrule
312
+ xelem('hr')
313
+ end
314
+
315
+ def to_html_linebreak
316
+ xelem('br')
317
+ end
318
+
319
+ # renders children as html and wraps into an element of given name
320
+ #
321
+ # Sets 'id' if meta is set
322
+ def wrap_as_element(name, attributes={})
323
+ html_element name, children_to_html, attributes
324
+ end
325
+
326
+ #=begin maruku_doc
327
+ # Attribute: id
328
+ # Scope: element
329
+ # Output: LaTeX, HTML
330
+ #
331
+ # It is copied as a standard HTML attribute.
332
+ #
333
+ # Moreover, it used as a label name for hyperlinks in both HTML and
334
+ # in PDF.
335
+ #=end
336
+
337
+ #=begin maruku_doc
338
+ # Attribute: class
339
+ # Scope: element
340
+ # Output: HTML
341
+ #
342
+ # It is copied as a standard HTML attribute.
343
+ #=end
344
+
345
+ #=begin maruku_doc
346
+ # Attribute: style
347
+ # Scope: element
348
+ # Output: HTML
349
+ #
350
+ # It is copied as a standard HTML attribute.
351
+ #=end
352
+
353
+ HTML4Attributes = {}
354
+
355
+ coreattrs = [:id, :class, :style, :title, :accesskey, :contenteditable, :dir,
356
+ :draggable, :spellcheck, :tabindex]
357
+ i18n = [:lang, :'xml:lang']
358
+ events = [:onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover,
359
+ :onmousemove, :onmouseout,
360
+ :onkeypress, :onkeydown, :onkeyup]
361
+ common_attrs = coreattrs + i18n + events
362
+ cells = [:align, :char, :charoff, :valign]
363
+
364
+ # Each row maps a list of tags to the list of attributes beyond the common_attributes
365
+ # that are valid on those elements
366
+ [
367
+ ['body', [:onload, :onunload]],
368
+ ['a', [:charset, :type, :name, :rel, :rev, :accesskey, :shape, :coords, :tabindex,
369
+ :onfocus,:onblur]],
370
+ ['img', [:longdesc, :name, :height, :width, :alt]],
371
+ ['ol', [:reversed, :start]],
372
+ ['li', [:value]],
373
+ ['table', [:summary, :width, :frame, :rules, :border, :cellspacing, :cellpadding]],
374
+ [%w(q blockquote), [:cite]],
375
+ [%w(ins del), [:cite, :datetime]],
376
+ [%w(colgroup col), [:span, :width] + cells],
377
+ [%w(thead tbody tfoot), cells],
378
+ [%w(td td th), [:abbr, :axis, :headers, :scope, :rowspan, :colspan] + cells],
379
+ [%w(em code strong hr span dl dd dt address div p pre caption ul h1 h2 h3 h4 h5 h6), []]
380
+ ].each do |elements, attributes|
381
+ [*elements].each do |element|
382
+ HTML4Attributes[element] = common_attrs + attributes
383
+ end
384
+ end
385
+
386
+ # Pretty much the same as the HTMLElement constructor except it
387
+ # copies standard attributes out of the Maruku Element's attributes hash.
388
+ def html_element(name, content="", attributes={})
389
+ if attributes.empty? && content.is_a?(Hash)
390
+ attributes = content
391
+ end
392
+
393
+ Array(HTML4Attributes[name]).each do |att|
394
+ if v = @attributes[att]
395
+ attributes[att.to_s] = v.to_s
396
+ end
397
+ end
398
+ content = yield if block_given?
399
+
400
+ HTMLElement.new(name, attributes, content)
401
+ end
402
+
403
+ def to_html_ul
404
+ if @attributes[:toc]
405
+ # render toc
406
+ @doc.toc.to_html
407
+ else
408
+ add_ws wrap_as_element('ul')
409
+ end
410
+ end
411
+
412
+ def to_html_paragraph
413
+ add_ws wrap_as_element('p')
414
+ end
415
+
416
+ def to_html_ol
417
+ add_ws wrap_as_element('ol')
418
+ end
419
+
420
+ def to_html_li
421
+ add_ws wrap_as_element('li')
422
+ end
423
+
424
+ def to_html_quote
425
+ add_ws wrap_as_element('blockquote')
426
+ end
427
+
428
+ def to_html_strong
429
+ wrap_as_element('strong')
430
+ end
431
+
432
+ def to_html_emphasis
433
+ wrap_as_element('em')
434
+ end
435
+
436
+ #=begin maruku_doc
437
+ # Attribute: use_numbered_headers
438
+ # Scope: document
439
+ # Summary: Activates the numbering of headers.
440
+ #
441
+ # If `true`, section headers will be numbered.
442
+ #
443
+ # In LaTeX export, the numbering of headers is managed
444
+ # by Maruku, to have the same results in both HTML and LaTeX.
445
+ #=end
446
+
447
+ # nil if not applicable, else string
448
+ def section_number
449
+ return nil unless get_setting(:use_numbered_headers)
450
+
451
+ n = Array(@attributes[:section_number])
452
+ return nil if n.empty?
453
+
454
+ n.join('.') + ". "
455
+ end
456
+
457
+ # nil if not applicable, else SPAN element
458
+ def render_section_number
459
+ return nil unless section_number && !section_number.empty?
460
+
461
+ # if we are bound to a section, add section number
462
+ span = xelem('span')
463
+ span['class'] = 'maruku_section_number'
464
+ span << xtext(section_number)
465
+ end
466
+
467
+ def to_html_header
468
+ element_name = "h#{self.level}"
469
+ h = wrap_as_element element_name
470
+
471
+ if span = render_section_number
472
+ h.children.unshift(span)
473
+ end
474
+
475
+ add_ws h
476
+ end
477
+
478
+ #=begin maruku_doc
479
+ # Attribute: html_use_syntax
480
+ # Scope: global, document, element
481
+ # Output: HTML
482
+ # Summary: Enables the use of the `syntax` package.
483
+ # Related: lang, code_lang
484
+ # Default: <?mrk md_code(Globals[:html_use_syntax].to_s) ?>
485
+ #
486
+ # If true, the `syntax` package is used. It supports the `ruby` and `xml`
487
+ # languages. Remember to set the `lang` attribute of the code block.
488
+ #
489
+ # Examples:
490
+ #
491
+ # require 'maruku'
492
+ # {:lang=ruby html_use_syntax=true}
493
+ #
494
+ # and
495
+ #
496
+ # <div style="text-align:center">Div</div>
497
+ # {:lang=html html_use_syntax=true}
498
+ #
499
+ # produces:
500
+ #
501
+ # require 'maruku'
502
+ # {:lang=ruby html_use_syntax=true}
503
+ #
504
+ # and
505
+ #
506
+ # <div style="text-align:center">Div</div>
507
+ # {:lang=html html_use_syntax=true}
508
+ #
509
+ #=end
510
+
511
+ $syntax_loaded = false
512
+ def to_html_code
513
+ source = self.raw_code
514
+
515
+ code_lang = self.lang || self.attributes[:lang] || @doc.attributes[:code_lang]
516
+
517
+ code_lang = 'xml' if code_lang == 'html'
518
+ code_lang = 'css21' if code_lang == 'css'
519
+
520
+ use_syntax = get_setting :html_use_syntax
521
+
522
+ element =
523
+ if use_syntax && code_lang
524
+ begin
525
+ unless $syntax_loaded
526
+ require 'rubygems'
527
+ require 'syntax'
528
+ require 'syntax/convertors/html'
529
+ $syntax_loaded = true
530
+ end
531
+ convertor = Syntax::Convertors::HTML.for_syntax code_lang
532
+
533
+ # eliminate trailing newlines otherwise Syntax crashes
534
+ source = source.sub(/\n*\z/, '')
535
+
536
+ html = convertor.convert(source)
537
+
538
+ html.gsub!(/\&apos;|'/,'&#39;') # IE bug
539
+
540
+ d = MaRuKu::HTMLFragment.new(html)
541
+ highlighted = d.to_html.sub(/\A<pre>(.*)<\/pre>\z/m, '\1')
542
+ code = HTMLElement.new('code', { :class => code_lang }, highlighted)
543
+
544
+ pre = xelem('pre')
545
+ # add a class here, too, for compatibility with existing implementations
546
+ pre['class'] = code_lang
547
+ pre << code
548
+ pre
549
+ rescue LoadError => e
550
+ maruku_error "Could not load package 'syntax'.\n" +
551
+ "Please install it, for example using 'gem install syntax'."
552
+ to_html_code_using_pre(source, code_lang)
553
+ rescue => e
554
+ maruku_error "Error while using the syntax library for code:\n#{source.inspect}" +
555
+ "Lang is #{code_lang} object is: \n" +
556
+ self.inspect +
557
+ "\nException: #{e.class}: #{e.message}"
558
+
559
+ tell_user("Using normal PRE because the syntax library did not work.")
560
+ to_html_code_using_pre(source, code_lang)
561
+ end
562
+ else
563
+ to_html_code_using_pre(source, code_lang)
564
+ end
565
+
566
+ color = get_setting(:code_background_color)
567
+ if color != MaRuKu::Globals[:code_background_color]
568
+ element['style'] = "background-color: #{color};"
569
+ end
570
+
571
+ add_ws element
572
+ end
573
+
574
+ #=begin maruku_doc
575
+ # Attribute: code_background_color
576
+ # Scope: global, document, element
577
+ # Summary: Background color for code blocks.
578
+ #
579
+ # The format is either a named color (`green`, `red`) or a CSS color
580
+ # of the form `#ff00ff`.
581
+ #
582
+ # * for **HTML output**, the value is put straight in the `background-color` CSS
583
+ # property of the block.
584
+ #
585
+ # * for **LaTeX output**, if it is a named color, it must be a color accepted
586
+ # by the LaTeX `color` packages. If it is of the form `#ff00ff`, Maruku
587
+ # defines a color using the `\color[rgb]{r,g,b}` macro.
588
+ #
589
+ # For example, for `#0000ff`, the macro is called as: `\color[rgb]{0,0,1}`.
590
+ #=end
591
+
592
+
593
+ def to_html_code_using_pre(source, code_lang=nil)
594
+ code = xelem('code')
595
+ pre = xelem('pre')
596
+ pre << code
597
+
598
+ if get_setting(:code_show_spaces)
599
+ # 187 = raquo
600
+ # 160 = nbsp
601
+ # 172 = not
602
+ source = source.gsub(/\t/,'&#187;' + '&#160;' * 3).gsub(/ /,'&#172;')
603
+ end
604
+
605
+ code << xtext(source)
606
+
607
+ code_lang ||= self.attributes[:lang]
608
+ if code_lang
609
+ pre['class'] = code['class'] = code_lang
610
+ end
611
+
612
+ pre
613
+ end
614
+
615
+ def to_html_inline_code
616
+ code_attrs = {}
617
+ source = xtext(self.raw_code)
618
+
619
+ color = get_setting(:code_background_color)
620
+ if color != MaRuKu::Globals[:code_background_color]
621
+ code_attrs['style'] = "background-color: #{color};" + (code_attrs['style'] || "")
622
+ end
623
+
624
+ html_element('code', source, code_attrs)
625
+ end
626
+
627
+ def add_class_to(el, cl)
628
+ el['class'] =
629
+ if already = el['class']
630
+ already + " " + cl
631
+ else
632
+ cl
633
+ end
634
+ end
635
+
636
+ def to_html_immediate_link
637
+ text = self.url.gsub(/^mailto:/, '') # don't show mailto
638
+ html_element('a', text, 'href' => self.url)
639
+ end
640
+
641
+ def to_html_link
642
+ a = {}
643
+ id = self.ref_id || children_to_s
644
+
645
+ if ref = @doc.refs[sanitize_ref_id(id)] || @doc.refs[sanitize_ref_id(children_to_s)]
646
+ a['href'] = ref[:url] if ref[:url]
647
+ a['title'] = ref[:title] if ref[:title]
648
+ else
649
+ maruku_error "Could not find ref_id = #{id.inspect} for #{self.inspect}\n" +
650
+ "Available refs are #{@doc.refs.keys.inspect}"
651
+ tell_user "Not creating a link for ref_id = #{id.inspect}.\n"
652
+ if (self.ref_id)
653
+ return "[#{children_to_s}][#{id}]"
654
+ else
655
+ return "[#{children_to_s}]"
656
+ end
657
+ end
658
+
659
+ wrap_as_element('a', a)
660
+ end
661
+
662
+ def to_html_im_link
663
+ if self.url
664
+ a = {}
665
+ a['href'] = self.url
666
+ a['title'] = self.title if self.title
667
+ wrap_as_element('a', a)
668
+ else
669
+ maruku_error "Could not find url in #{self.inspect}"
670
+ tell_user "Not creating a link for ref_id = #{id.inspect}."
671
+ wrap_as_element('span')
672
+ end
673
+ end
674
+
675
+ def add_ws(e)
676
+ [xml_newline, e, xml_newline]
677
+ end
678
+
679
+ ##### Email address
680
+
681
+ def obfuscate(s)
682
+ s.bytes.inject('') do |res, char|
683
+ res << "&#%03d;" % char
684
+ end
685
+ end
686
+
687
+ def to_html_email_address
688
+ obfuscated = obfuscate(self.email)
689
+ html_element('a', obfuscated, :href => "mailto:#{obfuscated}")
690
+ end
691
+
692
+ ##### Images
693
+
694
+ def to_html_image
695
+ a = {}
696
+ id = self.ref_id
697
+ if ref = @doc.refs[sanitize_ref_id(id)] || @doc.refs[sanitize_ref_id(children_to_s)]
698
+ a['src'] = ref[:url].to_s
699
+ a['alt'] = children_to_s
700
+ a['title'] = ref[:title].to_s if ref[:title]
701
+ html_element('img', nil, a)
702
+ else
703
+ maruku_error "Could not find id = #{id.inspect} for\n #{self.inspect}"
704
+ tell_user "Could not create image with ref_id = #{id.inspect};" +
705
+ " Using SPAN element as replacement."
706
+ wrap_as_element('span')
707
+ end
708
+ end
709
+
710
+ def to_html_im_image
711
+ if self.url
712
+ attrs = {}
713
+ attrs['src'] = self.url.to_s
714
+ attrs['alt'] = children_to_s
715
+ attrs['title'] = self.title.to_s if self.title
716
+ html_element('img', nil, attrs)
717
+ else
718
+ maruku_error "Image with no url: #{self.inspect}"
719
+ tell_user "Could not create image without a source URL;" +
720
+ " Using SPAN element as replacement."
721
+ wrap_as_element('span')
722
+ end
723
+ end
724
+
725
+ #=begin maruku_doc
726
+ # Attribute: filter_html
727
+ # Scope: document
728
+ #
729
+ # If true, raw HTML is discarded from the output.
730
+ #
731
+ #=end
732
+
733
+ def to_html_raw_html
734
+ return [] if get_setting(:filter_html)
735
+ return parsed_html.to_html if parsed_html
736
+
737
+ # If there's no parsed HTML
738
+ raw_html = self.raw_html
739
+
740
+ # Creates red box with offending HTML
741
+ tell_user "Wrapping bad html in a PRE with class 'markdown-html-error'\n" +
742
+ raw_html.gsub(/^/, '|')
743
+ pre = xelem('pre')
744
+ pre['style'] = 'border: solid 3px red; background-color: pink'
745
+ pre['class'] = 'markdown-html-error'
746
+ pre << xtext("Maruku could not parse this XML/HTML: \n#{raw_html}")
747
+ end
748
+
749
+ def to_html_abbr
750
+ abbr = xelem('abbr')
751
+ abbr << xtext(children[0])
752
+ abbr['title'] = self.title if self.title
753
+ abbr
754
+ end
755
+
756
+ def to_html_footnote_reference
757
+ id = self.footnote_id
758
+
759
+ # save the order of used footnotes
760
+ order = @doc.footnotes_order
761
+
762
+ # footnote has already been used
763
+ return [] if order.include?(id)
764
+
765
+ return [] unless @doc.footnotes[id]
766
+
767
+ # take next number
768
+ order << id
769
+
770
+ num = order.index(id) + 1
771
+
772
+ sup = xelem('sup')
773
+ sup['id'] = "#{get_setting(:doc_prefix)}fnref:#{num}"
774
+ a = xelem('a')
775
+ a << xtext(num.to_s)
776
+ a['href'] = "\##{get_setting(:doc_prefix)}fn:#{num}"
777
+ a['rel'] = 'footnote'
778
+ sup << a
779
+ end
780
+
781
+ ## Definition lists ###
782
+ def to_html_definition_list
783
+ add_ws wrap_as_element('dl')
784
+ end
785
+
786
+ def to_html_definition
787
+ children_to_html
788
+ end
789
+
790
+ def to_html_definition_term
791
+ add_ws wrap_as_element('dt')
792
+ end
793
+
794
+ def to_html_definition_data
795
+ add_ws wrap_as_element('dd')
796
+ end
797
+
798
+ def to_html_table
799
+ num_columns = self.align.size
800
+
801
+ head, *rows = @children.each_slice(num_columns).to_a
802
+
803
+ table = html_element('table')
804
+ thead = xelem('thead')
805
+ tr = xelem('tr')
806
+ array_to_html(head).inject(tr, &:<<)
807
+ thead << tr
808
+ table << thead
809
+
810
+ tbody = xelem('tbody')
811
+ rows.each do |row|
812
+ tr = xelem('tr')
813
+ array_to_html(row).each_with_index do |x, i|
814
+ x['style'] ="text-align: #{self.align[i].to_s};"
815
+ tr << x
816
+ end
817
+
818
+ tbody << tr << xml_newline
819
+ end
820
+
821
+ table << tbody
822
+ end
823
+
824
+ def to_html_head_cell
825
+ wrap_as_element('th')
826
+ end
827
+
828
+ def to_html_cell
829
+ if @attributes[:scope]
830
+ wrap_as_element('th')
831
+ else
832
+ wrap_as_element('td')
833
+ end
834
+ end
835
+
836
+ def to_html_entity
837
+ entity_name = self.entity_name
838
+
839
+ if entity = MaRuKu::Out::EntityTable.instance.entity(entity_name)
840
+ entity_name = entity.html_num
841
+ end
842
+
843
+ if entity_name.kind_of? Fixnum
844
+ # Convert numeric entities to unicode characters
845
+ xtext([entity_name].pack('U*'))
846
+ else
847
+ "&#{entity_name};"
848
+ end
849
+ end
850
+
851
+ def to_html_xml_instr
852
+ target = self.target || ''
853
+ code = self.code || ''
854
+
855
+ # A blank target is invalid XML. Just create a text node?
856
+ if target.empty?
857
+ xtext("<?#{code}?>")
858
+ else
859
+ "<?#{target} #{code}?>"
860
+ end
861
+ end
862
+
863
+ # Convert each child to html
864
+ def children_to_html
865
+ array_to_html(@children)
866
+ end
867
+
868
+ def array_to_html(array)
869
+ e = []
870
+ array.each do |c|
871
+ if c.kind_of?(String)
872
+ e << xtext(c)
873
+ else
874
+ if c.kind_of?(HTMLElement)
875
+ e << c
876
+ next
877
+ end
878
+
879
+ method = c.kind_of?(MaRuKu::MDElement) ? "to_html_#{c.node_type}" : "to_html"
880
+ next unless c.respond_to?(method)
881
+
882
+ h = c.send(method)
883
+
884
+ unless h
885
+ raise "Nil html created by method #{method}:\n#{h.inspect}\n" +
886
+ " for object #{c.inspect[0,300]}"
887
+ end
888
+
889
+ if h.kind_of? Array
890
+ e.concat h
891
+ else
892
+ e << h
893
+ end
894
+ end
895
+ end
896
+ e
897
+ end
898
+
899
+ def to_html_ref_definition
900
+ []
901
+ end
902
+
903
+ def to_latex_ref_definition
904
+ []
905
+ end
906
+ end