remi-maruku 0.5.9

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