kramdown 0.10.0 → 0.11.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.
- data/CONTRIBUTERS +1 -1
- data/ChangeLog +594 -0
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/data/kramdown/document.html +11 -2
- data/doc/default.template +2 -2
- data/doc/index.page +1 -2
- data/doc/quickref.page +2 -2
- data/doc/syntax.page +270 -179
- data/lib/kramdown/converter/html.rb +43 -29
- data/lib/kramdown/converter/kramdown.rb +97 -73
- data/lib/kramdown/converter/latex.rb +18 -13
- data/lib/kramdown/document.rb +8 -6
- data/lib/kramdown/options.rb +7 -10
- data/lib/kramdown/parser/html.rb +29 -21
- data/lib/kramdown/parser/kramdown.rb +19 -3
- data/lib/kramdown/parser/kramdown/abbreviation.rb +1 -0
- data/lib/kramdown/parser/kramdown/attribute_list.rb +18 -12
- data/lib/kramdown/parser/kramdown/autolink.rb +1 -1
- data/lib/kramdown/parser/kramdown/block_boundary.rb +46 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +7 -3
- data/lib/kramdown/parser/kramdown/codeblock.rb +5 -3
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +1 -1
- data/lib/kramdown/parser/kramdown/extension.rb +22 -8
- data/lib/kramdown/parser/kramdown/footnote.rb +3 -2
- data/lib/kramdown/parser/kramdown/header.rb +10 -10
- data/lib/kramdown/parser/kramdown/html.rb +16 -14
- data/lib/kramdown/parser/kramdown/html_entity.rb +1 -1
- data/lib/kramdown/parser/kramdown/link.rb +8 -8
- data/lib/kramdown/parser/kramdown/list.rb +36 -29
- data/lib/kramdown/parser/kramdown/math.rb +15 -4
- data/lib/kramdown/parser/kramdown/paragraph.rb +14 -3
- data/lib/kramdown/parser/kramdown/table.rb +17 -9
- data/lib/kramdown/utils.rb +1 -0
- data/lib/kramdown/utils/html.rb +9 -9
- data/lib/kramdown/utils/ordered_hash.rb +79 -0
- data/lib/kramdown/version.rb +1 -1
- data/man/man1/kramdown.1 +9 -12
- data/test/test_files.rb +6 -1
- data/test/testcases/block/02_eob/middle.html +0 -1
- data/test/testcases/block/04_header/atx_header.html +5 -2
- data/test/testcases/block/04_header/atx_header.text +3 -1
- data/test/testcases/block/04_header/setext_header.html +4 -5
- data/test/testcases/block/04_header/setext_header.html.19 +30 -0
- data/test/testcases/block/05_blockquote/lazy.html +34 -0
- data/test/testcases/block/05_blockquote/lazy.text +20 -0
- data/test/testcases/block/05_blockquote/nested.html +1 -0
- data/test/testcases/block/05_blockquote/nested.text +1 -0
- data/test/testcases/block/05_blockquote/with_code_blocks.html +2 -2
- data/test/testcases/block/06_codeblock/lazy.html +4 -0
- data/test/testcases/block/06_codeblock/lazy.text +5 -0
- data/test/testcases/block/06_codeblock/no_newline_at_end_1.html +2 -0
- data/test/testcases/block/06_codeblock/no_newline_at_end_1.text +2 -0
- data/test/testcases/block/06_codeblock/with_ial.html +6 -0
- data/test/testcases/block/06_codeblock/with_ial.text +5 -0
- data/test/testcases/block/07_horizontal_rule/normal.html +0 -2
- data/test/testcases/block/07_horizontal_rule/normal.text +0 -2
- data/test/testcases/block/08_list/item_ial.html +1 -3
- data/test/testcases/block/08_list/lazy.html +39 -0
- data/test/testcases/block/08_list/lazy.text +29 -0
- data/test/testcases/block/08_list/list_and_others.html +5 -3
- data/test/testcases/block/08_list/list_and_others.text +1 -0
- data/test/testcases/block/08_list/other_first_element.html +2 -2
- data/test/testcases/block/08_list/other_first_element.text +1 -1
- data/test/testcases/block/08_list/simple_ul.html +0 -13
- data/test/testcases/block/08_list/simple_ul.text +0 -7
- data/test/testcases/block/08_list/special_cases.html +8 -31
- data/test/testcases/block/08_list/special_cases.text +2 -15
- data/test/testcases/block/09_html/comment.html +2 -2
- data/test/testcases/block/09_html/html_to_native/emphasis.html +2 -0
- data/test/testcases/block/09_html/html_to_native/emphasis.text +2 -0
- data/test/testcases/block/09_html/html_to_native/table_normal.html +2 -1
- data/test/testcases/block/09_html/html_to_native/table_simple.html +4 -2
- data/test/testcases/block/09_html/invalid_html_1.html +2 -0
- data/test/testcases/block/09_html/parse_as_raw.html +2 -2
- data/test/testcases/block/09_html/parse_as_span.html +1 -1
- data/test/testcases/block/09_html/simple.html +2 -0
- data/test/testcases/block/09_html/simple.html.19 +2 -0
- data/test/testcases/block/09_html/simple.text +2 -0
- data/test/testcases/block/11_ial/auto_id_and_ial.html +1 -1
- data/test/testcases/block/11_ial/simple.html +2 -3
- data/test/testcases/block/12_extension/comment.html +3 -1
- data/test/testcases/block/12_extension/comment.text +2 -1
- data/test/testcases/block/12_extension/ignored.html +5 -1
- data/test/testcases/block/12_extension/ignored.text +1 -1
- data/test/testcases/block/12_extension/nomarkdown.html +5 -1
- data/test/testcases/block/12_extension/nomarkdown.kramdown +20 -0
- data/test/testcases/block/12_extension/nomarkdown.latex +13 -0
- data/test/testcases/block/12_extension/nomarkdown.text +11 -1
- data/test/testcases/block/13_definition_list/item_ial.html +1 -3
- data/test/testcases/block/13_definition_list/item_ial.text +1 -1
- data/test/testcases/block/13_definition_list/simple.html +2 -2
- data/test/testcases/block/14_table/errors.html +5 -0
- data/test/testcases/block/14_table/errors.text +6 -0
- data/test/testcases/block/14_table/header.text +1 -1
- data/test/testcases/block/14_table/no_table.text +1 -1
- data/test/testcases/block/14_table/simple.html +78 -0
- data/test/testcases/block/14_table/simple.text +22 -0
- data/test/testcases/block/15_math/normal.html +11 -4
- data/test/testcases/block/15_math/normal.text +10 -0
- data/test/testcases/encoding.html +1 -1
- data/test/testcases/span/01_link/image_in_a.html +3 -3
- data/test/testcases/span/01_link/imagelinks.html +7 -7
- data/test/testcases/span/01_link/inline.html +11 -5
- data/test/testcases/span/01_link/inline.html.19 +11 -5
- data/test/testcases/span/01_link/inline.text +11 -5
- data/test/testcases/span/01_link/link_defs.html +2 -1
- data/test/testcases/span/01_link/link_defs.text +4 -0
- data/test/testcases/span/01_link/reference.html +3 -0
- data/test/testcases/span/01_link/reference.html.19 +3 -0
- data/test/testcases/span/01_link/reference.text +5 -0
- data/test/testcases/span/03_codespan/highlighting.html +1 -0
- data/test/testcases/span/03_codespan/highlighting.text +1 -0
- data/test/testcases/span/04_footnote/definitions.html +3 -0
- data/test/testcases/span/04_footnote/definitions.latex +3 -4
- data/test/testcases/span/04_footnote/definitions.text +6 -0
- data/test/testcases/span/04_footnote/footnote_nr.latex +1 -5
- data/test/testcases/span/04_footnote/markers.latex +5 -14
- data/test/testcases/span/05_html/markdown_attr.html +1 -1
- data/test/testcases/span/05_html/markdown_attr.text +1 -1
- data/test/testcases/span/05_html/normal.html +5 -3
- data/test/testcases/span/05_html/normal.text +2 -0
- data/test/testcases/span/escaped_chars/normal.html +2 -0
- data/test/testcases/span/escaped_chars/normal.text +2 -0
- data/test/testcases/span/extension/comment.html +2 -2
- data/test/testcases/span/extension/ignored.html +1 -1
- data/test/testcases/span/text_substitutions/typography.html +1 -1
- data/test/testcases/span/text_substitutions/typography.html.19 +1 -1
- data/test/testcases/span/text_substitutions/typography.text +1 -1
- metadata +20 -5
- data/test/testcases/block/05_blockquote/only_first_quoted.html +0 -8
- data/test/testcases/block/05_blockquote/only_first_quoted.text +0 -4
@@ -62,6 +62,7 @@ module Kramdown
|
|
62
62
|
result = ''
|
63
63
|
indent += INDENTATION
|
64
64
|
el.children.each do |inner_el|
|
65
|
+
opts[:parent] = el
|
65
66
|
result << send("convert_#{inner_el.type}", inner_el, indent, opts)
|
66
67
|
end
|
67
68
|
result
|
@@ -84,16 +85,17 @@ module Kramdown
|
|
84
85
|
end
|
85
86
|
|
86
87
|
def convert_codeblock(el, indent, opts)
|
87
|
-
|
88
|
-
|
88
|
+
el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
|
89
|
+
lang = el.attr.delete('lang')
|
90
|
+
if lang && HIGHLIGHTING_AVAILABLE
|
89
91
|
opts = {:wrap => @doc.options[:coderay_wrap], :line_numbers => @doc.options[:coderay_line_numbers],
|
90
92
|
:line_number_start => @doc.options[:coderay_line_number_start], :tab_width => @doc.options[:coderay_tab_width],
|
91
93
|
:bold_every => @doc.options[:coderay_bold_every], :css => @doc.options[:coderay_css]}
|
92
|
-
result = CodeRay.scan(el.value,
|
94
|
+
result = CodeRay.scan(el.value, lang.to_sym).html(opts).chomp + "\n"
|
93
95
|
"#{' '*indent}<div#{html_attributes(el)}>#{result}#{' '*indent}</div>\n"
|
94
96
|
else
|
95
97
|
result = escape_html(el.value)
|
96
|
-
if el.
|
98
|
+
if el.attr['class'].to_s =~ /\bshow-whitespaces\b/
|
97
99
|
result.gsub!(/(?:(^[ \t]+)|([ \t]+$)|([ \t]+))/) do |m|
|
98
100
|
suffix = ($1 ? '-l' : ($2 ? '-r' : ''))
|
99
101
|
m.scan(/./).map do |c|
|
@@ -114,10 +116,10 @@ module Kramdown
|
|
114
116
|
|
115
117
|
def convert_header(el, indent, opts)
|
116
118
|
el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
|
117
|
-
if @doc.options[:auto_ids] && !
|
118
|
-
|
119
|
+
if @doc.options[:auto_ids] && !el.attr['id']
|
120
|
+
el.attr['id'] = generate_id(el.options[:raw_text])
|
119
121
|
end
|
120
|
-
@toc << [el.options[:level], el.
|
122
|
+
@toc << [el.options[:level], el.attr['id'], el.children] if el.attr['id'] && within_toc_depth?(el)
|
121
123
|
"#{' '*indent}<h#{el.options[:level]}#{html_attributes(el)}>#{inner(el, indent, opts)}</h#{el.options[:level]}>\n"
|
122
124
|
end
|
123
125
|
|
@@ -131,7 +133,7 @@ module Kramdown
|
|
131
133
|
|
132
134
|
def convert_ul(el, indent, opts)
|
133
135
|
if !@toc_code && (el.options[:ial][:refs].include?('toc') rescue nil) && (el.type == :ul || el.type == :ol)
|
134
|
-
@toc_code = [el.type, el.
|
136
|
+
@toc_code = [el.type, el.attr, (0..128).to_a.map{|a| rand(36).to_s(36)}.join]
|
135
137
|
@toc_code.last
|
136
138
|
else
|
137
139
|
"#{' '*indent}<#{el.type}#{html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</#{el.type}>\n"
|
@@ -156,32 +158,33 @@ module Kramdown
|
|
156
158
|
"#{' '*indent}<dt#{html_attributes(el)}>#{inner(el, indent, opts)}</dt>\n"
|
157
159
|
end
|
158
160
|
|
159
|
-
HTML_TAGS_WITH_BODY=['div', 'script']
|
161
|
+
HTML_TAGS_WITH_BODY=['div', 'script', 'iframe', 'textarea']
|
160
162
|
|
161
163
|
def convert_html_element(el, indent, opts)
|
164
|
+
parent = opts[:parent]
|
162
165
|
res = inner(el, indent, opts)
|
163
166
|
if el.options[:category] == :span
|
164
|
-
"<#{el.value}#{html_attributes(el)}" << (!res.empty? ? ">#{res}</#{el.value}>" : " />")
|
167
|
+
"<#{el.value}#{html_attributes(el)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
|
165
168
|
else
|
166
169
|
output = ''
|
167
|
-
output << ' '*indent if
|
170
|
+
output << ' '*indent if parent.type != :html_element || parent.options[:parse_type] != :raw
|
168
171
|
output << "<#{el.value}#{html_attributes(el)}"
|
169
172
|
if !res.empty? && el.options[:parse_type] != :block
|
170
173
|
output << ">#{res}</#{el.value}>"
|
171
174
|
elsif !res.empty?
|
172
|
-
output << ">\n#{res}" << ' '*indent << "</#{el.value}>"
|
175
|
+
output << ">\n#{res.chomp}\n" << ' '*indent << "</#{el.value}>"
|
173
176
|
elsif HTML_TAGS_WITH_BODY.include?(el.value)
|
174
177
|
output << "></#{el.value}>"
|
175
178
|
else
|
176
179
|
output << " />"
|
177
180
|
end
|
178
|
-
output << "\n" if
|
181
|
+
output << "\n" if parent.type != :html_element || parent.options[:parse_type] != :raw
|
179
182
|
output
|
180
183
|
end
|
181
184
|
end
|
182
185
|
|
183
186
|
def convert_xml_comment(el, indent, opts)
|
184
|
-
if el.options[:category] == :block &&
|
187
|
+
if el.options[:category] == :block && (opts[:parent].type != :html_element || opts[:parent].options[:parse_type] != :raw)
|
185
188
|
' '*indent + el.value + "\n"
|
186
189
|
else
|
187
190
|
el.value
|
@@ -227,12 +230,12 @@ module Kramdown
|
|
227
230
|
end
|
228
231
|
|
229
232
|
def convert_a(el, indent, opts)
|
230
|
-
do_obfuscation = el.
|
233
|
+
do_obfuscation = el.attr['href'] =~ /^mailto:/
|
231
234
|
if do_obfuscation
|
232
235
|
el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
|
233
|
-
href = obfuscate(el.
|
236
|
+
href = obfuscate(el.attr['href'].sub(/^mailto:/, ''))
|
234
237
|
mailto = obfuscate('mailto')
|
235
|
-
el.
|
238
|
+
el.attr['href'] = "#{mailto}:#{href}"
|
236
239
|
end
|
237
240
|
res = inner(el, indent, opts)
|
238
241
|
res = obfuscate(res) if do_obfuscation
|
@@ -244,7 +247,14 @@ module Kramdown
|
|
244
247
|
end
|
245
248
|
|
246
249
|
def convert_codespan(el, indent, opts)
|
247
|
-
|
250
|
+
el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
|
251
|
+
lang = el.attr.delete('lang')
|
252
|
+
if lang && HIGHLIGHTING_AVAILABLE
|
253
|
+
result = CodeRay.scan(el.value, lang.to_sym).html(:wrap => :span, :css => @doc.options[:coderay_css]).chomp
|
254
|
+
"<code#{html_attributes(el)}>#{result}</code>"
|
255
|
+
else
|
256
|
+
"<code#{html_attributes(el)}>#{escape_html(el.value)}</code>"
|
257
|
+
end
|
248
258
|
end
|
249
259
|
|
250
260
|
def convert_footnote(el, indent, opts)
|
@@ -255,7 +265,11 @@ module Kramdown
|
|
255
265
|
end
|
256
266
|
|
257
267
|
def convert_raw(el, indent, opts)
|
258
|
-
el.
|
268
|
+
if !el.options[:type] || el.options[:type].empty? || el.options[:type].include?('html')
|
269
|
+
el.value + (el.options[:category] == :block ? "\n" : '')
|
270
|
+
else
|
271
|
+
''
|
272
|
+
end
|
259
273
|
end
|
260
274
|
|
261
275
|
def convert_em(el, indent, opts)
|
@@ -286,9 +300,8 @@ module Kramdown
|
|
286
300
|
|
287
301
|
def convert_math(el, indent, opts)
|
288
302
|
el = Marshal.load(Marshal.dump(el)) # so that the original is not changed
|
289
|
-
el.
|
290
|
-
el.
|
291
|
-
el.options[:attr]['class'] += (el.options[:attr]['class'].empty? ? '' : ' ') + 'math'
|
303
|
+
el.attr['class'] ||= ''
|
304
|
+
el.attr['class'] += (el.attr['class'].empty? ? '' : ' ') + 'math'
|
292
305
|
type = 'span'
|
293
306
|
type = 'div' if el.options[:category] == :block
|
294
307
|
"<#{type}#{html_attributes(el)}>#{escape_html(el.value)}</#{type}>#{type == 'div' ? "\n" : ''}"
|
@@ -316,12 +329,13 @@ module Kramdown
|
|
316
329
|
end
|
317
330
|
|
318
331
|
def generate_toc_tree(toc, type, attr)
|
319
|
-
sections = Element.new(type, nil,
|
332
|
+
sections = Element.new(type, nil, attr)
|
333
|
+
sections.attr['id'] ||= 'markdown-toc'
|
320
334
|
stack = []
|
321
335
|
toc.each do |level, id, children|
|
322
|
-
li = Element.new(:li, nil, {:level => level})
|
323
|
-
li.children << Element.new(:p, nil, {:transparent => true})
|
324
|
-
a = Element.new(:a, nil, {
|
336
|
+
li = Element.new(:li, nil, nil, {:level => level})
|
337
|
+
li.children << Element.new(:p, nil, nil, {:transparent => true})
|
338
|
+
a = Element.new(:a, nil, {'href' => "##{id}"})
|
325
339
|
a.children += children
|
326
340
|
li.children.last.children << a
|
327
341
|
li.children << Element.new(type)
|
@@ -362,10 +376,10 @@ module Kramdown
|
|
362
376
|
# Return a HTML list with the footnote content for the used footnotes.
|
363
377
|
def footnote_content
|
364
378
|
ol = Element.new(:ol)
|
365
|
-
ol.
|
379
|
+
ol.attr['start'] = @footnote_start if @footnote_start != 1
|
366
380
|
@footnotes.each do |name, data|
|
367
|
-
li = Element.new(:li, nil, {
|
368
|
-
li.children = Marshal.load(Marshal.dump(data[:content].children))
|
381
|
+
li = Element.new(:li, nil, {'id' => "fn:#{name}"}, {:first_is_block => true})
|
382
|
+
li.children = Marshal.load(Marshal.dump(data[:content].children))
|
369
383
|
ol.children << li
|
370
384
|
|
371
385
|
ref = Element.new(:raw, "<a href=\"#fnref:#{name}\" rev=\"footnote\">↩</a>")
|
@@ -41,23 +41,32 @@ module Kramdown
|
|
41
41
|
@stack = []
|
42
42
|
end
|
43
43
|
|
44
|
-
def convert(el, opts = {})
|
44
|
+
def convert(el, opts = {:indent => 0})
|
45
45
|
res = send("convert_#{el.type}", el, opts)
|
46
46
|
if el.type != :html_element && el.type != :li && el.type != :dd && (ial = ial_for_element(el))
|
47
47
|
res << ial
|
48
48
|
res << "\n\n" if el.options[:category] == :block
|
49
|
+
elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
|
50
|
+
([el.type, :codeblock].include?(opts[:next].type) ||
|
51
|
+
(opts[:next].type == :blank && opts[:nnext] && [el.type, :codeblock].include?(opts[:nnext].type)))
|
52
|
+
res << "^\n\n"
|
53
|
+
elsif el.options[:category] == :block && ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
|
54
|
+
(el.type != :p || !el.options[:transparent])
|
55
|
+
res << "\n"
|
49
56
|
end
|
50
57
|
res
|
51
58
|
end
|
52
59
|
|
53
|
-
def inner(el, opts = {})
|
54
|
-
@stack.push(
|
60
|
+
def inner(el, opts = {:indent => 0})
|
61
|
+
@stack.push(el)
|
55
62
|
result = ''
|
56
63
|
el.children.each_with_index do |inner_el, index|
|
57
64
|
options = opts.dup
|
58
65
|
options[:index] = index
|
59
66
|
options[:prev] = (index == 0 ? nil : el.children[index-1])
|
67
|
+
options[:pprev] = (index <= 1 ? nil : el.children[index-2])
|
60
68
|
options[:next] = (index == el.children.length - 1 ? nil : el.children[index+1])
|
69
|
+
options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index+2])
|
61
70
|
result << convert(inner_el, options)
|
62
71
|
end
|
63
72
|
@stack.pop
|
@@ -65,54 +74,44 @@ module Kramdown
|
|
65
74
|
end
|
66
75
|
|
67
76
|
def convert_blank(el, opts)
|
68
|
-
"
|
77
|
+
""
|
69
78
|
end
|
70
79
|
|
71
|
-
ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{
|
80
|
+
ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'])|^[ ]{0,3}(:)/
|
72
81
|
|
73
82
|
def convert_text(el, opts)
|
74
83
|
if opts[:raw_text]
|
75
84
|
el.value
|
76
85
|
else
|
77
|
-
|
78
|
-
|
86
|
+
el.value.gsub(/\A\n/) do
|
87
|
+
opts[:prev] && opts[:prev].type == :br ? '' : "\n"
|
88
|
+
end.gsub(/\s+/, ' ').gsub(ESCAPED_CHAR_RE) { "\\#{$1 || $2}" }
|
79
89
|
end
|
80
90
|
end
|
81
91
|
|
82
92
|
def convert_p(el, opts)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
res
|
93
|
+
w = @doc.options[:line_width] - opts[:indent].to_s.to_i
|
94
|
+
first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
|
95
|
+
first.gsub!(/^(?:(#)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\."}
|
96
|
+
first.gsub!(/\|/, '\\|')
|
97
|
+
second.gsub!(/^([=-]+\s*?)$/, "\\\1") if second
|
98
|
+
[first, second, *rest].compact.join("\n") + "\n"
|
90
99
|
end
|
91
100
|
|
92
|
-
CODEBLOCK_PREV_EL = [:ul, :ol, :dl, :codeblock]
|
93
101
|
|
94
102
|
def convert_codeblock(el, opts)
|
95
|
-
|
96
|
-
res << "^\n" if opts[:prev] && ((CODEBLOCK_PREV_EL.include?(opts[:prev].type) && !ial_for_element(opts[:prev])) ||
|
97
|
-
(opts[:prev].type == :blank &&
|
98
|
-
opts[:index]-2 >= 0 &&
|
99
|
-
(tmp = @stack.last.first.children[opts[:index]-2]) &&
|
100
|
-
CODEBLOCK_PREV_EL.include?(tmp.type) && !ial_for_element(tmp)))
|
101
|
-
res << el.value.split(/\n/).map {|l| l.empty? ? " " : " #{l}"}.join("\n") + "\n"
|
103
|
+
el.value.split(/\n/).map {|l| l.empty? ? " " : " #{l}"}.join("\n") + "\n"
|
102
104
|
end
|
103
105
|
|
104
106
|
def convert_blockquote(el, opts)
|
105
|
-
|
106
|
-
|
107
|
-
res << inner(el, opts).chomp.split(/\n/).map {|l| "> #{l}"}.join("\n") << "\n"
|
107
|
+
opts[:indent] += 2
|
108
|
+
inner(el, opts).chomp.split(/\n/).map {|l| "> #{l}"}.join("\n") << "\n"
|
108
109
|
end
|
109
110
|
|
110
111
|
def convert_header(el, opts)
|
111
112
|
res = ''
|
112
|
-
res << "\n" if opts[:prev] && opts[:prev].type != :blank
|
113
113
|
res << "#{'#' * el.options[:level]} #{inner(el, opts)}"
|
114
|
-
res << " {##{el.
|
115
|
-
res << "\n" if opts[:next] && opts[:next].type != :blank
|
114
|
+
res << " {##{el.attr['id']}}" if el.attr['id']
|
116
115
|
res << "\n"
|
117
116
|
end
|
118
117
|
|
@@ -121,19 +120,13 @@ module Kramdown
|
|
121
120
|
end
|
122
121
|
|
123
122
|
def convert_ul(el, opts)
|
124
|
-
|
125
|
-
res << "\n" if opts[:prev] && (opts[:prev].type == :p && !opts[:prev].options[:transparent])
|
126
|
-
res << "^\n" if opts[:prev] && ((opts[:prev].type == el.type && !ial_for_element(opts[:prev])) ||
|
127
|
-
(opts[:prev].type == :blank && opts[:index]-2 >= 0 &&
|
128
|
-
(tmp = @stack.last.first.children[opts[:index]-2]) &&
|
129
|
-
tmp.type == el.type && !ial_for_element(tmp)))
|
130
|
-
res + inner(el, opts).sub(/\n+\Z/, "\n")
|
123
|
+
inner(el, opts).sub(/\n+\Z/, "\n")
|
131
124
|
end
|
132
125
|
alias :convert_ol :convert_ul
|
133
126
|
alias :convert_dl :convert_ul
|
134
127
|
|
135
128
|
def convert_li(el, opts)
|
136
|
-
sym, width = if @stack.last.
|
129
|
+
sym, width = if @stack.last.type == :ul
|
137
130
|
['* ', el.children.first.type == :codeblock ? 4 : 2]
|
138
131
|
else
|
139
132
|
["#{opts[:index] + 1}.".ljust(4), 4]
|
@@ -142,18 +135,21 @@ module Kramdown
|
|
142
135
|
sym += ial + " "
|
143
136
|
end
|
144
137
|
|
145
|
-
|
138
|
+
opts[:indent] += width
|
139
|
+
text = inner(el, opts)
|
140
|
+
newlines = text.scan(/\n*\Z/).first
|
141
|
+
first, *last = text.split(/\n/)
|
146
142
|
last = last.map {|l| " "*width + l}.join("\n")
|
147
|
-
|
143
|
+
text = first + (last.empty? ? "" : "\n") + last + newlines
|
148
144
|
if el.children.first.type == :p && !el.children.first.options[:transparent]
|
149
|
-
res = "#{sym}#{
|
150
|
-
res << "^\n" if el.children.size == 1 && @stack.last.
|
151
|
-
(@stack.last.
|
145
|
+
res = "#{sym}#{text}"
|
146
|
+
res << "^\n" if el.children.size == 1 && @stack.last.children.last == el &&
|
147
|
+
(@stack.last.children.any? {|c| c.children.first.type != :p} || @stack.last.children.size == 1)
|
152
148
|
res
|
153
149
|
elsif el.children.first.type == :codeblock
|
154
|
-
"#{sym}\n #{
|
150
|
+
"#{sym}\n #{text}"
|
155
151
|
else
|
156
|
-
"#{sym}#{
|
152
|
+
"#{sym}#{text}"
|
157
153
|
end
|
158
154
|
end
|
159
155
|
|
@@ -163,24 +159,28 @@ module Kramdown
|
|
163
159
|
sym += ial + " "
|
164
160
|
end
|
165
161
|
|
166
|
-
|
162
|
+
opts[:indent] += width
|
163
|
+
text = inner(el, opts)
|
164
|
+
newlines = text.scan(/\n*\Z/).first
|
165
|
+
first, *last = text.split(/\n/)
|
167
166
|
last = last.map {|l| " "*width + l}.join("\n")
|
168
|
-
text = first + (last.empty? ?
|
167
|
+
text = first + (last.empty? ? "" : "\n") + last + newlines
|
168
|
+
text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
|
169
|
+
text += "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt
|
169
170
|
if el.children.first.type == :p && !el.children.first.options[:transparent]
|
170
|
-
"\n#{sym}#{text}
|
171
|
+
"\n#{sym}#{text}"
|
171
172
|
elsif el.children.first.type == :codeblock
|
172
|
-
"#{sym}\n #{text}
|
173
|
+
"#{sym}\n #{text}"
|
173
174
|
else
|
174
|
-
"#{sym}#{text}
|
175
|
+
"#{sym}#{text}"
|
175
176
|
end
|
176
177
|
end
|
177
178
|
|
178
179
|
def convert_dt(el, opts)
|
179
|
-
|
180
|
-
res << inner(el, opts) << "\n"
|
180
|
+
inner(el, opts) << "\n"
|
181
181
|
end
|
182
182
|
|
183
|
-
HTML_TAGS_WITH_BODY=['div', 'script']
|
183
|
+
HTML_TAGS_WITH_BODY=['div', 'script', 'iframe', 'textarea']
|
184
184
|
|
185
185
|
def convert_html_element(el, opts)
|
186
186
|
markdown_attr = el.options[:category] == :block && el.children.any? do |c|
|
@@ -191,7 +191,7 @@ module Kramdown
|
|
191
191
|
opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text]
|
192
192
|
res = inner(el, opts)
|
193
193
|
if el.options[:category] == :span
|
194
|
-
"<#{el.value}#{html_attributes(el)}" << (!res.empty? ? ">#{res}</#{el.value}>" : " />")
|
194
|
+
"<#{el.value}#{html_attributes(el)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
|
195
195
|
else
|
196
196
|
output = ''
|
197
197
|
output << "<#{el.value}#{html_attributes(el)}"
|
@@ -205,13 +205,13 @@ module Kramdown
|
|
205
205
|
else
|
206
206
|
output << " />"
|
207
207
|
end
|
208
|
-
output << "\n" if
|
208
|
+
output << "\n" if @stack.last.type != :html_element || @stack.last.options[:parse_type] != :raw
|
209
209
|
output
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
213
213
|
def convert_xml_comment(el, opts)
|
214
|
-
if el.options[:category] == :block &&
|
214
|
+
if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:parse_type] != :raw)
|
215
215
|
el.value + "\n"
|
216
216
|
else
|
217
217
|
el.value
|
@@ -274,17 +274,34 @@ module Kramdown
|
|
274
274
|
end
|
275
275
|
|
276
276
|
def convert_a(el, opts)
|
277
|
-
if el.
|
277
|
+
if el.attr['href'].empty?
|
278
278
|
"[#{inner(el, opts)}]()"
|
279
|
+
elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0
|
280
|
+
index = if link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href']}
|
281
|
+
@linkrefs.index(link_el) + 1
|
282
|
+
else
|
283
|
+
@linkrefs << el
|
284
|
+
@linkrefs.size
|
285
|
+
end
|
286
|
+
"[#{inner(el, opts)}][#{index}]"
|
279
287
|
else
|
280
|
-
|
281
|
-
"[#{inner(el, opts)}]
|
288
|
+
title = el.attr['title'].to_s.empty? ? '' : ' "' + el.attr['title'].gsub(/"/, """) + '"'
|
289
|
+
"[#{inner(el, opts)}](#{el.attr['href']}#{title})"
|
282
290
|
end
|
283
291
|
end
|
284
292
|
|
285
293
|
def convert_img(el, opts)
|
286
|
-
|
287
|
-
|
294
|
+
if el.attr['src'].empty?
|
295
|
+
"![#{el.attr['alt']}]()"
|
296
|
+
else
|
297
|
+
title = (el.attr['title'] ? ' "' + el.attr['title'].gsub(/"/, """) + '"' : '')
|
298
|
+
link = if el.attr['src'].count("()") > 0
|
299
|
+
"<#{el.attr['src']}>"
|
300
|
+
else
|
301
|
+
el.attr['src']
|
302
|
+
end
|
303
|
+
"![#{el.attr['alt']}](#{link}#{title})"
|
304
|
+
end
|
288
305
|
end
|
289
306
|
|
290
307
|
def convert_codespan(el, opts)
|
@@ -298,12 +315,14 @@ module Kramdown
|
|
298
315
|
end
|
299
316
|
|
300
317
|
def convert_raw(el, opts)
|
301
|
-
|
318
|
+
attr = (el.options[:type] || []).join(' ')
|
319
|
+
attr = " type=\"#{attr}\"" if attr.length > 0
|
320
|
+
if @stack.last.type == :html_element
|
302
321
|
el.value
|
303
322
|
elsif el.options[:category] == :block
|
304
|
-
"{::nomarkdown}\n#{el.value}\n{:/}\n"
|
323
|
+
"{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n"
|
305
324
|
else
|
306
|
-
"{::nomarkdown}#{el.value}{:/}"
|
325
|
+
"{::nomarkdown#{attr}}#{el.value}{:/}"
|
307
326
|
end
|
308
327
|
end
|
309
328
|
|
@@ -333,7 +352,7 @@ module Kramdown
|
|
333
352
|
end
|
334
353
|
|
335
354
|
def convert_math(el, opts)
|
336
|
-
(@stack.last.
|
355
|
+
(@stack.last.type == :p && opts[:prev].nil? ? "\\" : '') + "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '')
|
337
356
|
end
|
338
357
|
|
339
358
|
def convert_abbreviation(el, opts)
|
@@ -352,20 +371,17 @@ module Kramdown
|
|
352
371
|
res = ''
|
353
372
|
res << "\n\n" if @linkrefs.size > 0
|
354
373
|
@linkrefs.each_with_index do |el, i|
|
355
|
-
|
356
|
-
|
357
|
-
title = el.options[:attr]['title']
|
358
|
-
res << "[#{i+1}]: #{link} #{title ? '"' + title.gsub(/"/, """) + '"' : ''}\n"
|
374
|
+
title = el.attr['title']
|
375
|
+
res << "[#{i+1}]: #{el.attr['href']} #{title ? '"' + title.gsub(/"/, """) + '"' : ''}\n"
|
359
376
|
end
|
360
377
|
res
|
361
378
|
end
|
362
379
|
|
363
380
|
def create_footnote_defs
|
364
381
|
res = ''
|
365
|
-
res = "\n" if @footnotes.size > 0
|
366
382
|
@footnotes.each do |name, data|
|
367
|
-
res << "
|
368
|
-
res << inner(data[:content]).chomp.split(/\n/).map {|l| " #{l}"}.join("\n")
|
383
|
+
res << "[^#{name}]:\n"
|
384
|
+
res << inner(data[:content]).chomp.split(/\n/).map {|l| " #{l}"}.join("\n") + "\n\n"
|
369
385
|
end
|
370
386
|
res
|
371
387
|
end
|
@@ -381,11 +397,19 @@ module Kramdown
|
|
381
397
|
|
382
398
|
# Return the IAL containing the attributes of the element +el+.
|
383
399
|
def ial_for_element(el)
|
384
|
-
res =
|
400
|
+
res = el.attr.map do |k,v|
|
385
401
|
next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k)
|
386
402
|
next if el.type == :header && k == 'id'
|
387
|
-
v.nil?
|
388
|
-
|
403
|
+
if v.nil?
|
404
|
+
''
|
405
|
+
elsif k == 'class'
|
406
|
+
" " + v.split(/\s+/).map {|w| ".#{w}"}.join(" ")
|
407
|
+
elsif k == 'id'
|
408
|
+
" ##{v}"
|
409
|
+
else
|
410
|
+
" #{k}=\"#{v.to_s}\""
|
411
|
+
end
|
412
|
+
end.compact.join('')
|
389
413
|
res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
|
390
414
|
(el.options[:ial][:refs].include?('toc') rescue nil)
|
391
415
|
res.strip.empty? ? nil : "{:#{res}}"
|