kramdown 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (69) hide show
  1. data/CONTRIBUTERS +2 -1
  2. data/ChangeLog +454 -0
  3. data/README +1 -1
  4. data/VERSION +1 -1
  5. data/doc/{default.less.css → default.scss.css} +12 -9
  6. data/doc/documentation.page +1 -1
  7. data/doc/index.page +37 -3
  8. data/doc/syntax.page +10 -7
  9. data/lib/kramdown/converter.rb +1 -0
  10. data/lib/kramdown/converter/html.rb +61 -67
  11. data/lib/kramdown/converter/kramdown.rb +398 -0
  12. data/lib/kramdown/converter/latex.rb +274 -276
  13. data/lib/kramdown/document.rb +2 -0
  14. data/lib/kramdown/options.rb +16 -15
  15. data/lib/kramdown/parser/base.rb +0 -1
  16. data/lib/kramdown/parser/html.rb +122 -27
  17. data/lib/kramdown/parser/kramdown.rb +2 -0
  18. data/lib/kramdown/parser/kramdown/attribute_list.rb +2 -0
  19. data/lib/kramdown/parser/kramdown/extension.rb +2 -1
  20. data/lib/kramdown/parser/kramdown/html.rb +2 -2
  21. data/lib/kramdown/parser/kramdown/html_entity.rb +1 -1
  22. data/lib/kramdown/parser/kramdown/link.rb +5 -2
  23. data/lib/kramdown/parser/kramdown/list.rb +13 -9
  24. data/lib/kramdown/parser/kramdown/math.rb +1 -1
  25. data/lib/kramdown/parser/kramdown/typographic_symbol.rb +4 -4
  26. data/lib/kramdown/utils.rb +36 -0
  27. data/lib/kramdown/utils/entities.rb +338 -0
  28. data/lib/kramdown/utils/html.rb +72 -0
  29. data/lib/kramdown/version.rb +1 -1
  30. data/man/man1/kramdown.1 +20 -17
  31. data/test/run_tests.rb +1 -1
  32. data/test/test_files.rb +60 -3
  33. data/test/testcases/block/06_codeblock/whitespace.html +2 -2
  34. data/test/testcases/block/07_horizontal_rule/error.html.19 +7 -0
  35. data/test/testcases/block/09_html/html_to_native/code.html +1 -1
  36. data/test/testcases/block/09_html/html_to_native/code.text +1 -1
  37. data/test/testcases/block/09_html/html_to_native/table_simple.html +38 -2
  38. data/test/testcases/block/09_html/html_to_native/table_simple.text +42 -0
  39. data/test/testcases/block/09_html/html_to_native/typography.html.19 +1 -0
  40. data/test/testcases/block/09_html/simple.html.19 +62 -0
  41. data/test/testcases/block/11_ial/simple.html +3 -2
  42. data/test/testcases/block/12_extension/comment.html +3 -2
  43. data/test/testcases/block/12_extension/options.html +0 -3
  44. data/test/testcases/block/12_extension/options.text +0 -6
  45. data/test/testcases/block/13_definition_list/item_ial.html +14 -0
  46. data/test/testcases/block/13_definition_list/item_ial.text +8 -0
  47. data/test/testcases/block/16_toc/no_toc_depth.html +33 -0
  48. data/test/testcases/block/16_toc/no_toc_depth.options +1 -0
  49. data/test/testcases/block/16_toc/no_toc_depth.text +16 -0
  50. data/test/testcases/block/16_toc/toc_depth_2.html +24 -0
  51. data/test/testcases/block/16_toc/toc_depth_2.options +1 -0
  52. data/test/testcases/block/16_toc/toc_depth_2.text +16 -0
  53. data/test/testcases/span/01_link/empty.html +2 -0
  54. data/test/testcases/span/01_link/empty.text +2 -0
  55. data/test/testcases/span/01_link/imagelinks.html +2 -0
  56. data/test/testcases/span/01_link/imagelinks.text +2 -0
  57. data/test/testcases/span/01_link/inline.html.19 +40 -0
  58. data/test/testcases/span/01_link/reference.html.19 +32 -0
  59. data/test/testcases/span/extension/comment.html +3 -3
  60. data/test/testcases/span/text_substitutions/entities.html.19 +4 -0
  61. data/test/testcases/span/text_substitutions/entities_numeric.html +1 -0
  62. data/test/testcases/span/text_substitutions/entities_numeric.html.19 +1 -0
  63. data/test/testcases/span/text_substitutions/entities_numeric.options +1 -0
  64. data/test/testcases/span/text_substitutions/entities_numeric.text +1 -0
  65. data/test/testcases/span/text_substitutions/typography.html.19 +18 -0
  66. metadata +30 -10
  67. data/test/testcases/block/09_html/filtered_html.html +0 -1
  68. data/test/testcases/block/09_html/filtered_html.options +0 -1
  69. data/test/testcases/block/09_html/filtered_html.text +0 -1
data/README CHANGED
@@ -21,7 +21,7 @@ kramdown has a basic *Cloth API, so using kramdown is as easy as
21
21
  Just clone the git repository as described in doc/installation.page you are good to go. You probably
22
22
  want to install `rake` so that you can use the provided rake tasks. Aside from that:
23
23
 
24
- * The `tidy` binary needs to be installed for the html-to-html tests to work.
24
+ * The `tidy` binary needs to be installed for the automatically derived tests to work.
25
25
  * The `latex` binary needs to be installed for the latex-compilation tests to work.
26
26
 
27
27
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.0
1
+ 0.9.0
@@ -1,5 +1,5 @@
1
- @text-color: #354146;
2
- @link-color: #1666A3;
1
+ $text-color: #354146;
2
+ $link-color: #1666A3;
3
3
 
4
4
  * {
5
5
  padding: 0;
@@ -32,7 +32,7 @@ body, table, code {
32
32
  }
33
33
 
34
34
  #header {
35
- .with-margin;
35
+ @extend .with-margin;
36
36
 
37
37
  position: relative;
38
38
  padding: 0 0 0 30px;
@@ -66,7 +66,7 @@ body, table, code {
66
66
  }
67
67
 
68
68
  #nav {
69
- .with-margin;
69
+ @extend .with-margin;
70
70
 
71
71
  ul {
72
72
  height: 40px;
@@ -120,7 +120,8 @@ body, table, code {
120
120
  }
121
121
 
122
122
  #intro {
123
- .with-margin;
123
+ @extend .with-margin;
124
+
124
125
  background: #e6e8e9;
125
126
  height: auto;
126
127
 
@@ -133,7 +134,7 @@ body, table, code {
133
134
  }
134
135
 
135
136
  a {
136
- color: @link-color;
137
+ color: $link-color;
137
138
  background-color: inherit;
138
139
  text-decoration: underline;
139
140
  }
@@ -146,7 +147,8 @@ body, table, code {
146
147
 
147
148
  /* content */
148
149
  #container {
149
- .with-margin;
150
+ @extend .with-margin;
151
+
150
152
  position: relative;
151
153
  clear: both;
152
154
  background-color: #fff;
@@ -154,7 +156,7 @@ body, table, code {
154
156
  background-image: -webkit-gradient(linear, 0 0, 0 200, from(#eee), to(#fff));
155
157
 
156
158
  a {
157
- color: @link-color;
159
+ color: $link-color;
158
160
  background-color: inherit;
159
161
  text-decoration: underline;
160
162
  }
@@ -462,7 +464,8 @@ body, table, code {
462
464
 
463
465
  /* footer */
464
466
  #footer {
465
- .with-margin;
467
+ @extend .with-margin;
468
+
466
469
  clear: both;
467
470
  margin-top: 20px;
468
471
  padding: 5px 20px 30px;
@@ -10,7 +10,7 @@ HTML. However, due to its modular architecture it is able to support additional
10
10
  formats. The following input and output formats are currently supported:
11
11
 
12
12
  * Input: [kramdown](parser/kramdown.html) (a superset of Markdown), [html](parser/html.html)
13
- * Output: [HTML](converter/html.html), [LaTeX](converter/latex.html)
13
+ * Output: [HTML](converter/html.html), [LaTeX](converter/latex.html), [kramdown](converter/kramdown.html)
14
14
 
15
15
 
16
16
  ## Usage
data/doc/index.page CHANGED
@@ -8,8 +8,42 @@ sort_info: 1
8
8
  If you want to get started with kramdown, have a look at the [installation page](installation.html)
9
9
  to see how you can install it on your system. Then look through the
10
10
  [documentation](documentation.html) for finding information about how to actually use kramdown and
11
- what parsers/converters it supports. The [syntax](syntax.html) provides a detailed description of
12
- the superset of Markdown which kramdown supports.
11
+ its parsers/converters. The [syntax](syntax.html) provides a detailed description of the superset of
12
+ Markdown which kramdown supports.
13
+
14
+ {tikz:: path: overview.png
15
+ img_attr: {style: 'background:transparent'}
16
+ libraries: [mindmap, trees, arrows]
17
+ transparent: true
18
+ resolution: 300 100
19
+ opts: |
20
+ mindmap, concept color=black, text=white,
21
+ root concept/.append style={font=\Large},
22
+ level 1 concept/.append style={font=\Large, minimum size=2.6cm},
23
+ level 2 concept/.append style={font=\Large},
24
+ }
25
+ \node[concept, font=\Large] (lib) {kramdown's internal representation}
26
+ child[concept color=orange, grow=150, ->] {node[concept] (i-kramdown) {kramdown}}
27
+ child[concept color=orange, grow=210] {node[concept] (i-html) {HTML}}
28
+ child[concept color=green!50!black, grow=40] {node[concept] (o-html) {HTML}}
29
+ child[concept color=green!50!black, grow=0] {node[concept] (o-kramdown) {kramdown}}
30
+ child[concept color=green!50!black, grow=-45] {
31
+ node[concept] (o-latex) {\LaTeX}
32
+ child[grow=0] {
33
+ node[concept] (o-latex-pdf) {PDF}
34
+ }
35
+ }
36
+ child[concept color=green!50!black, grow=-45] {node[concept] {\LaTeX}}
37
+ ;
38
+ \draw [dash pattern=on 0pt off 2pt,line width=5pt,arrows=-angle 60,shorten >=15pt,shorten <=10pt,color=orange]
39
+ (i-kramdown) edge(lib)
40
+ (i-html) edge (lib);
41
+ \draw [dash pattern=on 0pt off 2pt,line width=5pt,arrows=-angle 60,shorten >=10pt,shorten <=15pt,color=green!50!black]
42
+ (lib) edge(o-html)
43
+ (lib) edge (o-kramdown)
44
+ (lib) edge (o-latex);
45
+ {tikz}
46
+ {: style="text-align: center"}
13
47
 
14
48
 
15
49
  ## Bugs, Forums, Mailing Lists
@@ -55,7 +89,7 @@ It is probably the fastest pure-Ruby Markdown converter available (June 2010), b
55
89
  than [Maruku] and about 9x faster than [BlueFeather].
56
90
 
57
91
  <p class="a-center">
58
- The latest version of kramdown is <b>0.8.0</b> and it was released on <b>2010-06-08</b>.
92
+ The latest version of kramdown is <b>0.9.0</b> and it was released on <b>2010-06-23</b>.
59
93
  </p>
60
94
 
61
95
  [PHP Markdown Extra]: http://michelf.com/projects/php-markdown/extra/
data/doc/syntax.page CHANGED
@@ -530,8 +530,9 @@ after the list item marker:
530
530
  Definition lists allow you to assign one or more definitions to one or more terms.
531
531
 
532
532
  A definition list is started when a normal paragraph is followed by a line with a definition marker
533
- (a colon which may be optionally indented up to three spaces), then at least one tab or one space
534
- and then the first part of the definition. The line with the definition marker may optionally be
533
+ (a colon which may be optionally indented up to three spaces), then at least one tab or one space,
534
+ optionally followed by an [IAL](#inline-attribute-lists) that should be applied to the list item and
535
+ then the first part of the definition. The line with the definition marker may optionally be
535
536
  separated from the preceding paragraph by a blank line. The leading tabs or spaces are stripped away
536
537
  from this first line of the definition to allow for a nice alignment with the following definition
537
538
  content. Each line of the preceding paragraph is taken to be a term and the lines separately parsed
@@ -984,9 +985,9 @@ As the wording suggests, inline links provide all information inline in the text
984
985
  style links only provide the link text in the text flow and everything else is defined
985
986
  elsewhere. This also allows you to reuse link definitions.
986
987
 
987
- An inline style link can be created by surrounding the link text with square brackets, followed
988
- immediately by the link URL (and an optional title in single or double quotes preceded by at least
989
- one space) in normal parentheses. For example:
988
+ An inline style link can be created by surrounding the link text which must contain at least one
989
+ character with square brackets, followed immediately by the link URL (and an optional title in
990
+ single or double quotes preceded by at least one space) in normal parentheses. For example:
990
991
 
991
992
  This is [a link](http://rubyforge.org) to a page.
992
993
  A [link](../test "local URI") can also have a title.
@@ -1049,11 +1050,13 @@ The link definition has the following structure:
1049
1050
 
1050
1051
  Images can be specified via a syntax that is similar to the one used by links. The difference is
1051
1052
  that you have to use an exclamation mark before the first square bracket and that the link text of a
1052
- normal link becomes the alternative text of the image link. As with normal links, image links can be
1053
- written inline or reference style. For example:
1053
+ normal link, which may also be the empty string in case of image links, becomes the alternative text
1054
+ of the image link. As with normal links, image links can be written inline or reference style. For
1055
+ example:
1054
1056
 
1055
1057
  Here comes a ![smiley](../images/smiley.png)! And here
1056
1058
  ![too](../images/other.png 'Title text'). Or ![here].
1059
+ With empty alt text ![](see.jpg)
1057
1060
 
1058
1061
  The link definition for images is exactly the same as the link definition for normal links.
1059
1062
 
@@ -35,6 +35,7 @@ module Kramdown
35
35
  autoload :Base, 'kramdown/converter/base'
36
36
  autoload :Html, 'kramdown/converter/html'
37
37
  autoload :Latex, 'kramdown/converter/latex'
38
+ autoload :Kramdown, 'kramdown/converter/kramdown'
38
39
 
39
40
  end
40
41
 
@@ -29,6 +29,14 @@ module Kramdown
29
29
  # Converts a Kramdown::Document to HTML.
30
30
  class Html < Base
31
31
 
32
+ include ::Kramdown::Utils::HTML
33
+
34
+ # DEPRECATED: use #html_attributes
35
+ def options_for_element(el)
36
+ warn("DEPRECATION WARNING: this method will be deprecated in the next release, use #html_attributes instead")
37
+ html_attributes(el)
38
+ end
39
+
32
40
  # :stopdoc:
33
41
 
34
42
  # Defines the amount of indentation used when nesting HTML tags.
@@ -73,41 +81,41 @@ module Kramdown
73
81
  escape_html(el.value, :text)
74
82
  end
75
83
 
76
- def convert_eob(el, indent, opts)
77
- ''
78
- end
79
-
80
84
  def convert_p(el, indent, opts)
81
- "#{' '*indent}<p#{options_for_element(el)}>#{inner(el, indent, opts)}</p>\n"
85
+ if el.options[:transparent]
86
+ "#{inner(el, indent, opts)}"
87
+ else
88
+ "#{' '*indent}<p#{html_attributes(el)}>#{inner(el, indent, opts)}</p>\n"
89
+ end
82
90
  end
83
91
 
84
92
  def convert_codeblock(el, indent, opts)
85
- if el.value && el.options[:attr] && el.options[:attr]['lang'] && HIGHLIGHTING_AVAILABLE
93
+ if el.options[:attr] && el.options[:attr]['lang'] && HIGHLIGHTING_AVAILABLE
86
94
  el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
87
95
  opts = {:wrap => @doc.options[:coderay_wrap], :line_numbers => @doc.options[:coderay_line_numbers],
88
96
  :line_number_start => @doc.options[:coderay_line_number_start], :tab_width => @doc.options[:coderay_tab_width],
89
97
  :bold_every => @doc.options[:coderay_bold_every], :css => @doc.options[:coderay_css]}
90
98
  result = CodeRay.scan(el.value, el.options[:attr].delete('lang').to_sym).html(opts).chomp + "\n"
91
- "#{' '*indent}<div#{options_for_element(el)}>#{result}#{' '*indent}</div>\n"
99
+ "#{' '*indent}<div#{html_attributes(el)}>#{result}#{' '*indent}</div>\n"
92
100
  else
93
- result = (el.value ? escape_html(el.value) : inner(el, indent, opts))
101
+ result = escape_html(el.value)
94
102
  if el.options[:attr] && el.options[:attr].has_key?('class') && el.options[:attr]['class'] =~ /\bshow-whitespaces\b/
95
103
  result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m|
96
104
  suffix = ($1 ? '-l' : ($2 ? '-r' : ''))
97
105
  m.scan(/./).map do |c|
98
106
  case c
99
107
  when "\t" then "<span class=\"ws-tab#{suffix}\">\t</span>"
100
- when " " then "<span class=\"ws-space#{suffix}\">&sdot;</span>"
108
+ when " " then "<span class=\"ws-space#{suffix}\">&#8901;</span>"
101
109
  end
102
110
  end.join('')
103
111
  end
104
112
  end
105
- "#{' '*indent}<pre#{options_for_element(el)}><code>#{result}#{result =~ /\n\Z/ ? '' : "\n"}</code></pre>\n"
113
+ "#{' '*indent}<pre#{html_attributes(el)}><code>#{result}#{result =~ /\n\Z/ ? '' : "\n"}</code></pre>\n"
106
114
  end
107
115
  end
108
116
 
109
117
  def convert_blockquote(el, indent, opts)
110
- "#{' '*indent}<blockquote#{options_for_element(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</blockquote>\n"
118
+ "#{' '*indent}<blockquote#{html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</blockquote>\n"
111
119
  end
112
120
 
113
121
  def convert_header(el, indent, opts)
@@ -115,8 +123,12 @@ module Kramdown
115
123
  if @doc.options[:auto_ids] && !(el.options[:attr] && el.options[:attr]['id'])
116
124
  (el.options[:attr] ||= {})['id'] = generate_id(el.options[:raw_text])
117
125
  end
118
- @toc << [el.options[:level], el.options[:attr]['id'], el.children] if el.options[:attr] && el.options[:attr]['id']
119
- "#{' '*indent}<h#{el.options[:level]}#{options_for_element(el)}>#{inner(el, indent, opts)}</h#{el.options[:level]}>\n"
126
+ @toc << [el.options[:level], el.options[:attr]['id'], el.children] if el.options[:attr] && el.options[:attr]['id'] && within_toc_depth?(el)
127
+ "#{' '*indent}<h#{el.options[:level]}#{html_attributes(el)}>#{inner(el, indent, opts)}</h#{el.options[:level]}>\n"
128
+ end
129
+
130
+ def within_toc_depth?(el)
131
+ @doc.options[:toc_depth] <= 0 || el.options[:level] <= @doc.options[:toc_depth]
120
132
  end
121
133
 
122
134
  def convert_hr(el, indent, opts)
@@ -128,16 +140,16 @@ module Kramdown
128
140
  @toc_code = [el.type, el.options[:attr], (0..128).to_a.map{|a| rand(36).to_s(36)}.join]
129
141
  @toc_code.last
130
142
  else
131
- "#{' '*indent}<#{el.type}#{options_for_element(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</#{el.type}>\n"
143
+ "#{' '*indent}<#{el.type}#{html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</#{el.type}>\n"
132
144
  end
133
145
  end
134
146
  alias :convert_ol :convert_ul
135
147
  alias :convert_dl :convert_ul
136
148
 
137
149
  def convert_li(el, indent, opts)
138
- output = ' '*indent << "<#{el.type}" << options_for_element(el) << ">"
150
+ output = ' '*indent << "<#{el.type}" << html_attributes(el) << ">"
139
151
  res = inner(el, indent, opts)
140
- if el.children.empty? || el.children.first.options[:category] != :block
152
+ if el.children.empty? || (el.children.first.type == :p && el.children.first.options[:transparent])
141
153
  output << res << (res =~ /\n\Z/ ? ' '*indent : '')
142
154
  else
143
155
  output << "\n" << res << ' '*indent
@@ -147,22 +159,19 @@ module Kramdown
147
159
  alias :convert_dd :convert_li
148
160
 
149
161
  def convert_dt(el, indent, opts)
150
- "#{' '*indent}<dt#{options_for_element(el)}>#{inner(el, indent, opts)}</dt>\n"
162
+ "#{' '*indent}<dt#{html_attributes(el)}>#{inner(el, indent, opts)}</dt>\n"
151
163
  end
152
164
 
153
165
  HTML_TAGS_WITH_BODY=['div', 'script']
154
166
 
155
167
  def convert_html_element(el, indent, opts)
156
168
  res = inner(el, indent, opts)
157
- if @doc.options[:filter_html].include?(el.value)
158
- warn("The filter_html option is deprecated and will be removed in the next release")
159
- res.chomp + (el.options[:category] == :block ? "\n" : '')
160
- elsif el.options[:category] == :span
161
- "<#{el.value}#{options_for_element(el)}" << (!res.empty? ? ">#{res}</#{el.value}>" : " />")
169
+ if el.options[:category] == :span
170
+ "<#{el.value}#{html_attributes(el)}" << (!res.empty? ? ">#{res}</#{el.value}>" : " />")
162
171
  else
163
172
  output = ''
164
173
  output << ' '*indent if !el.options[:parent_is_raw]
165
- output << "<#{el.value}#{options_for_element(el)}"
174
+ output << "<#{el.value}#{html_attributes(el)}"
166
175
  if !res.empty? && el.options[:parse_type] != :block
167
176
  output << ">#{res}</#{el.value}>"
168
177
  elsif !res.empty?
@@ -195,11 +204,11 @@ module Kramdown
195
204
  "#{' '*(indent + INDENTATION)}" + (a == :default ? "<col />" : "<col align=\"#{a}\" />") + "\n"
196
205
  end.join('')
197
206
  end
198
- "#{' '*indent}<table#{options_for_element(el)}>\n#{alignment}#{inner(el, indent, opts)}#{' '*indent}</table>\n"
207
+ "#{' '*indent}<table#{html_attributes(el)}>\n#{alignment}#{inner(el, indent, opts)}#{' '*indent}</table>\n"
199
208
  end
200
209
 
201
210
  def convert_thead(el, indent, opts)
202
- "#{' '*indent}<#{el.type}#{options_for_element(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</#{el.type}>\n"
211
+ "#{' '*indent}<#{el.type}#{html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</#{el.type}>\n"
203
212
  end
204
213
  alias :convert_tbody :convert_thead
205
214
  alias :convert_tfoot :convert_thead
@@ -207,10 +216,18 @@ module Kramdown
207
216
 
208
217
  def convert_td(el, indent, opts)
209
218
  res = inner(el, indent, opts)
210
- "#{' '*indent}<#{el.type}#{options_for_element(el)}>#{res.empty? ? "&nbsp;" : res}</#{el.type}>\n"
219
+ "#{' '*indent}<#{el.type}#{html_attributes(el)}>#{res.empty? ? "&nbsp;" : res}</#{el.type}>\n"
211
220
  end
212
221
  alias :convert_th :convert_td
213
222
 
223
+ def convert_comment(el, indent, opts)
224
+ if el.options[:category] == :block
225
+ "#{' '*indent}<!-- #{el.value} -->\n"
226
+ else
227
+ "<!-- #{el.value} -->"
228
+ end
229
+ end
230
+
214
231
  def convert_br(el, indent, opts)
215
232
  "<br />"
216
233
  end
@@ -225,15 +242,15 @@ module Kramdown
225
242
  end
226
243
  res = inner(el, indent, opts)
227
244
  res = obfuscate(res) if do_obfuscation
228
- "<a#{options_for_element(el)}>#{res}</a>"
245
+ "<a#{html_attributes(el)}>#{res}</a>"
229
246
  end
230
247
 
231
248
  def convert_img(el, indent, opts)
232
- "<img#{options_for_element(el)} />"
249
+ "<img#{html_attributes(el)} />"
233
250
  end
234
251
 
235
252
  def convert_codespan(el, indent, opts)
236
- "<code#{options_for_element(el)}>#{el.value ? escape_html(el.value) : inner(el, indent, opts)}</code>"
253
+ "<code#{html_attributes(el)}>#{escape_html(el.value)}</code>"
237
254
  end
238
255
 
239
256
  def convert_footnote(el, indent, opts)
@@ -244,29 +261,33 @@ module Kramdown
244
261
  end
245
262
 
246
263
  def convert_raw(el, indent, opts)
247
- el.value
264
+ el.value + (el.options[:category] == :block ? "\n" : '')
248
265
  end
249
266
 
250
267
  def convert_em(el, indent, opts)
251
- "<#{el.type}#{options_for_element(el)}>#{inner(el, indent, opts)}</#{el.type}>"
268
+ "<#{el.type}#{html_attributes(el)}>#{inner(el, indent, opts)}</#{el.type}>"
252
269
  end
253
270
  alias :convert_strong :convert_em
254
271
 
255
272
  def convert_entity(el, indent, opts)
256
- "&#{el.value.kind_of?(Integer) ? '#' : ''}#{el.value};"
273
+ entity_to_str(el.value)
257
274
  end
258
275
 
259
276
  TYPOGRAPHIC_SYMS = {
260
- :mdash => '&mdash;', :ndash => '&ndash;', :hellip => '&hellip;',
261
- :laquo_space => '&laquo;&nbsp;', :raquo_space => '&nbsp;&raquo;',
262
- :laquo => '&laquo;', :raquo => '&raquo;'
277
+ :mdash => [::Kramdown::Utils::Entities.entity('mdash')],
278
+ :ndash => [::Kramdown::Utils::Entities.entity('ndash')],
279
+ :hellip => [::Kramdown::Utils::Entities.entity('hellip')],
280
+ :laquo_space => [::Kramdown::Utils::Entities.entity('laquo'), ::Kramdown::Utils::Entities.entity('nbsp')],
281
+ :raquo_space => [::Kramdown::Utils::Entities.entity('nbsp'), ::Kramdown::Utils::Entities.entity('raquo')],
282
+ :laquo => [::Kramdown::Utils::Entities.entity('laquo')],
283
+ :raquo => [::Kramdown::Utils::Entities.entity('raquo')]
263
284
  }
264
285
  def convert_typographic_sym(el, indent, opts)
265
- TYPOGRAPHIC_SYMS[el.value]
286
+ TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e)}.join('')
266
287
  end
267
288
 
268
289
  def convert_smart_quote(el, indent, opts)
269
- "&#{el.value};"
290
+ entity_to_str(::Kramdown::Utils::Entities.entity(el.value.to_s))
270
291
  end
271
292
 
272
293
  def convert_math(el, indent, opts)
@@ -276,7 +297,7 @@ module Kramdown
276
297
  el.options[:attr]['class'] += (el.options[:attr]['class'].empty? ? '' : ' ') + 'math'
277
298
  type = 'span'
278
299
  type = 'div' if el.options[:category] == :block
279
- "<#{type}#{options_for_element(el)}>#{escape_html(el.value, :text)}</#{type}>#{type == 'div' ? "\n" : ''}"
300
+ "<#{type}#{html_attributes(el)}>#{escape_html(el.value)}</#{type}>#{type == 'div' ? "\n" : ''}"
280
301
  end
281
302
 
282
303
  def convert_abbreviation(el, indent, opts)
@@ -305,9 +326,10 @@ module Kramdown
305
326
  stack = []
306
327
  toc.each do |level, id, children|
307
328
  li = Element.new(:li, nil, {:level => level})
329
+ li.children << Element.new(:p, nil, {:transparent => true})
308
330
  a = Element.new(:a, nil, {:attr => {:href => "##{id}"}})
309
331
  a.children += children
310
- li.children << a
332
+ li.children.last.children << a
311
333
  li.children << Element.new(type)
312
334
 
313
335
  success = false
@@ -363,34 +385,6 @@ module Kramdown
363
385
  (ol.children.empty? ? '' : "<div class=\"footnotes\">\n#{convert(ol, 2)}</div>\n")
364
386
  end
365
387
 
366
- # Return the string with the attributes of the element +el+.
367
- def options_for_element(el)
368
- (el.options[:attr] || {}).map {|k,v| v.nil? ? '' : " #{k}=\"#{escape_html(v.to_s, :no_entities)}\"" }.sort.join('')
369
- end
370
-
371
- ESCAPE_MAP = {
372
- '<' => '&lt;',
373
- '>' => '&gt;',
374
- '&' => '&amp;',
375
- '"' => '&quot;'
376
- }
377
- ESCAPE_ALL_RE = Regexp.union(*ESCAPE_MAP.collect {|k,v| k})
378
- ESCAPE_NO_ENTITIES_RE = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, ESCAPE_ALL_RE)
379
- ESCAPE_NORMAL = Regexp.union(REXML::Parsers::BaseParser::REFERENCE_RE, /<|>|&/)
380
- ESCAPE_RE_FROM_TYPE = {
381
- :all => ESCAPE_ALL_RE,
382
- :no_entities => ESCAPE_NO_ENTITIES_RE,
383
- :text => ESCAPE_NORMAL
384
- }
385
-
386
- # Escape the special HTML characters in the string +str+. The parameter +type+ specifies what
387
- # is escaped: <tt>:all</tt> - all special HTML characters as well as entities,
388
- # <tt>:no_entities</tt> - all special HTML characters but no entities, <tt>:text</tt> - all
389
- # special HTML characters except the quotation mark but no entities.
390
- def escape_html(str, type = :all)
391
- str.gsub(ESCAPE_RE_FROM_TYPE[type]) {|m| ESCAPE_MAP[m] || m}
392
- end
393
-
394
388
  end
395
389
 
396
390
  end