maruku 0.6.0 → 0.7.3

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