maruku 0.6.1 → 0.7.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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