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
@@ -27,6 +27,7 @@ require 'kramdown/error'
27
27
  require 'kramdown/parser'
28
28
  require 'kramdown/converter'
29
29
  require 'kramdown/options'
30
+ require 'kramdown/utils'
30
31
 
31
32
  module Kramdown
32
33
 
@@ -92,6 +93,7 @@ module Kramdown
92
93
  @options = Options.merge(options)
93
94
  @warnings = []
94
95
  @parse_infos = {}
96
+ @parse_infos[:encoding] = source.encoding if RUBY_VERSION >= '1.9'
95
97
  @conversion_infos = {}
96
98
  parser = (options[:input] || 'kramdown').to_s
97
99
  parser = parser[0..0].upcase + parser[1..-1]
@@ -210,21 +210,6 @@ footnote.
210
210
 
211
211
  Default: 1
212
212
  Used by: HTML converter
213
- EOF
214
-
215
- define(:filter_html, Array, [], <<EOF)
216
- NOTE: This option is deprecated and will be removed in a future release!
217
-
218
- An array of HTML tags that should be filtered from the output
219
-
220
- The value can either be specified as array or as a space separated
221
- string (which will be converted to an array). All HTML tags that are
222
- listed in the array will be filtered from the output, i.e. only their
223
- contents is used. This applies only to HTML tags found in the initial
224
- document.
225
-
226
- Default: []
227
- Used by: HTML converter
228
213
  EOF
229
214
 
230
215
  define(:coderay_wrap, Symbol, :div, <<EOF)
@@ -275,6 +260,22 @@ styles are directly applied to the code elements).
275
260
 
276
261
  Default: style
277
262
  Used by: HTML converter
263
+ EOF
264
+
265
+ define(:numeric_entities, Boolean, false, <<EOF)
266
+ Defines whether entities are output using names or numeric values
267
+
268
+ Default: false
269
+ Used by: HTML converter, kramdown converter
270
+ EOF
271
+
272
+ define(:toc_depth, Integer, 0, <<EOF)
273
+ Defines the maximum level of headers which will be used to generate the table of
274
+ contents. For instance, with a value of 2, toc entries will be generated for h1
275
+ and h2 headers but not for h3, h4, etc. A value of 0 uses all header levels.
276
+
277
+ Default: 0
278
+ Used by: HTML/Latex converter
278
279
  EOF
279
280
 
280
281
  end
@@ -34,7 +34,6 @@ module Kramdown
34
34
  # Initialize the parser with the given Kramdown document +doc+.
35
35
  def initialize(doc)
36
36
  @doc = doc
37
- @doc.parse_infos.clear
38
37
  @text_type = :text
39
38
  end
40
39
  private_class_method(:new, :allocate)
@@ -161,16 +161,23 @@ module Kramdown
161
161
  class ElementConverter
162
162
 
163
163
  include Constants
164
+ include ::Kramdown::Utils::Entities
164
165
 
165
166
  REMOVE_TEXT_CHILDREN = %w{html head hgroup ol ul dl table colgroup tbody thead tfoot tr select optgroup}
167
+ WRAP_TEXT_CHILDREN = %w{body section nav article aside header footer address div li dd blockquote figure
168
+ figcaption fieldset form}
166
169
  REMOVE_WHITESPACE_CHILDREN = %w{body section nav article aside header footer address
167
170
  div li dd blockquote figure figcaption td th fieldset form}
168
171
  STRIP_WHITESPACE = %w{address article aside blockquote body caption dd div dl dt fieldset figcaption form footer
169
172
  header h1 h2 h3 h4 h5 h6 legend li nav p section td th}
170
173
  SIMPLE_ELEMENTS = %w{em strong blockquote hr br a img p thead tbody tfoot tr td th ul ol dl li dl dt dd}
171
174
 
175
+ def initialize(doc)
176
+ @doc = doc
177
+ end
178
+
172
179
  # Convert the element +el+ and its children.
173
- def process(el, convert_simple = true, parent = nil)
180
+ def process(el, do_conversion = true, preserve_text = false, parent = nil)
174
181
  case el.type
175
182
  when :xml_comment, :xml_pi, :html_doctype
176
183
  ptype = if parent.nil?
@@ -194,25 +201,26 @@ module Kramdown
194
201
  remove_text_children(el) if REMOVE_TEXT_CHILDREN.include?(type)
195
202
 
196
203
  mname = "convert_#{el.value}"
197
- if self.class.method_defined?(mname)
204
+ if do_conversion && self.class.method_defined?(mname)
198
205
  send(mname, el)
199
- elsif convert_simple && SIMPLE_ELEMENTS.include?(type)
206
+ elsif do_conversion && SIMPLE_ELEMENTS.include?(type)
200
207
  set_basics(el, type.intern, HTML_SPAN_ELEMENTS.include?(type) ? :span : :block)
201
- process_children(el, convert_simple)
208
+ process_children(el, do_conversion, preserve_text)
202
209
  else
203
- process_html_element(el, convert_simple)
210
+ process_html_element(el, do_conversion, preserve_text)
204
211
  end
205
212
 
206
213
  strip_whitespace(el) if STRIP_WHITESPACE.include?(type)
207
214
  remove_whitespace_children(el) if REMOVE_WHITESPACE_CHILDREN.include?(type)
215
+ wrap_text_children(el) if WRAP_TEXT_CHILDREN.include?(type)
208
216
  end
209
217
 
210
- def process_children(el, convert_simple = true)
218
+ def process_children(el, do_conversion = true, preserve_text = false)
211
219
  el.children.map! do |c|
212
220
  if c.type == :text
213
- process_text(c.value)
221
+ process_text(c.value, preserve_text)
214
222
  else
215
- process(c, convert_simple, el)
223
+ process(c, do_conversion, preserve_text, el)
216
224
  c
217
225
  end
218
226
  end.flatten!
@@ -234,7 +242,7 @@ module Kramdown
234
242
  elsif %w{mdash ndash hellip laquo raquo}.include?(val)
235
243
  Element.new(:typographic_sym, val.intern)
236
244
  else
237
- Element.new(:entity, val)
245
+ Element.new(:entity, entity(val))
238
246
  end
239
247
  else
240
248
  result << Element.new(:text, src.scan(/.*/m))
@@ -243,18 +251,39 @@ module Kramdown
243
251
  result
244
252
  end
245
253
 
246
- def process_html_element(el, convert_simple = true)
254
+ def process_html_element(el, do_conversion = true, preserve_text = false)
247
255
  el.options = {:category => HTML_SPAN_ELEMENTS.include?(el.value) ? :span : :block,
248
256
  :parse_type => HTML_PARSE_AS[el.value],
249
257
  :attr => el.options[:attr]
250
258
  }
251
- process_children(el, convert_simple)
259
+ process_children(el, do_conversion, preserve_text)
252
260
  end
253
261
 
254
262
  def remove_text_children(el)
255
263
  el.children.delete_if {|c| c.type == :text}
256
264
  end
257
265
 
266
+ SPAN_ELEMENTS = [:em, :strong, :br, :a, :img, :codespan, :entity, :smart_quote, :typographic_sym, :math]
267
+
268
+ def wrap_text_children(el)
269
+ tmp = []
270
+ last_is_p = false
271
+ el.children.each do |c|
272
+ if c.options[:category] != :block || c.type == :text
273
+ if !last_is_p
274
+ tmp << Element.new(:p, nil, :transparent => true)
275
+ last_is_p = true
276
+ end
277
+ tmp.last.children << c
278
+ tmp
279
+ else
280
+ tmp << c
281
+ last_is_p = false
282
+ end
283
+ end
284
+ el.children = tmp
285
+ end
286
+
258
287
  def strip_whitespace(el)
259
288
  return if el.children.empty?
260
289
  if el.children.first.type == :text
@@ -291,20 +320,42 @@ module Kramdown
291
320
  extract_text(el, el.options[:raw_text] = '')
292
321
  process_children(el)
293
322
  end
294
- %w{h2 h3 h4 h5 h6}.each {|i| alias_method("convert_#{i}".intern, :convert_h1)}
323
+ %w{h2 h3 h4 h5 h6}.each do |i|
324
+ alias_method("convert_#{i}".to_sym, :convert_h1)
325
+ end
295
326
 
296
327
  def convert_code(el)
297
- if el.value == 'code'
298
- set_basics(el, :codespan, :span)
299
- else
300
- set_basics(el, :codeblock, :block)
301
- end
302
328
  raw = ''
303
329
  extract_text(el, raw)
304
330
  result = process_text(raw, true)
331
+ begin
332
+ str = result.inject('') do |mem, c|
333
+ if c.type == :text
334
+ mem << c.value
335
+ elsif c.type == :entity
336
+ if RUBY_VERSION >= '1.9'
337
+ mem << c.value.char.encode(@doc.parse_infos[:encoding])
338
+ elsif [60, 62, 34, 38].include?(c.value.code_point)
339
+ mem << c.value.code_point.chr
340
+ end
341
+ elsif c.type == :smart_quote || c.type == :typographic_sym
342
+ mem << entity(c.value.to_s).char.encode(@doc.parse_infos[:encoding])
343
+ else
344
+ raise "Bug - please report"
345
+ end
346
+ end
347
+ result.clear
348
+ result << Element.new(:text, str)
349
+ rescue
350
+ end
305
351
  if result.length > 1 || result.first.type != :text
306
- el.children = result
352
+ process_html_element(el, false, true)
307
353
  else
354
+ if el.value == 'code'
355
+ set_basics(el, :codespan, :span)
356
+ else
357
+ set_basics(el, :codeblock, :block)
358
+ end
308
359
  el.value = result.first.value
309
360
  end
310
361
  end
@@ -318,16 +369,20 @@ module Kramdown
318
369
  process_children(el)
319
370
  set_basics(el, :table, :block)
320
371
  el.options[:alignment] = []
321
- helper = lambda do |c|
372
+ calc_alignment = lambda do |c|
322
373
  if c.type == :tr && el.options[:alignment].empty?
323
374
  el.options[:alignment] = [:default] * c.children.length
324
375
  break
325
376
  else
326
- c.children.each {|cc| helper.call(cc)}
377
+ c.children.each {|cc| calc_alignment.call(cc)}
327
378
  end
328
379
  end
329
- helper.call(el)
330
- true
380
+ calc_alignment.call(el)
381
+ if el.children.first.type == :tr
382
+ tbody = Element.new(:tbody, nil, :category => :block)
383
+ tbody.children = el.children
384
+ el.children = [tbody]
385
+ end
331
386
  end
332
387
 
333
388
  def is_simple_table?(el)
@@ -336,17 +391,56 @@ module Kramdown
336
391
  (cc.type == :text || !HTML_BLOCK_ELEMENTS.include?(cc.value)) && only_phrasing_content.call(cc)
337
392
  end
338
393
  end
339
- helper = Proc.new do |c|
394
+ check_cells = Proc.new do |c|
340
395
  if c.value == 'th' || c.value == 'td'
341
396
  return false if !only_phrasing_content.call(c)
342
397
  else
343
- c.children.each {|cc| helper.call(cc)}
398
+ c.children.each {|cc| check_cells.call(cc)}
344
399
  end
345
400
  end
346
- helper.call(el)
347
- true
401
+ check_cells.call(el)
402
+
403
+ check_rows = lambda do |t, type|
404
+ t.children.all? {|r| (r.value == 'tr' || r.type == :text) && r.children.all? {|c| c.value == type || c.type == :text}}
405
+ end
406
+ check_rows.call(el, 'td') ||
407
+ (el.children.all? do |t|
408
+ t.type == :text || (t.value == 'thead' && check_rows.call(t, 'th')) ||
409
+ ((t.value == 'tfoot' || t.value == 'tbody') && check_rows.call(t, 'td'))
410
+ end && el.children.any? {|t| t.value == 'tbody'})
411
+ end
412
+
413
+ def convert_div(el)
414
+ if !is_math_tag?(el)
415
+ process_html_element(el)
416
+ else
417
+ handle_math_tag(el)
418
+ end
348
419
  end
420
+ alias :convert_span :convert_div
349
421
 
422
+ def is_math_tag?(el)
423
+ el.options[:attr] && el.options[:attr]['class'].to_s =~ /\bmath\b/ &&
424
+ el.children.size == 1 && el.children.first.type == :text
425
+ end
426
+
427
+ def handle_math_tag(el)
428
+ set_basics(el, :math, (el.value == 'div' ? :block : :span))
429
+ el.value = el.children.shift.value
430
+ if el.options[:attr]['class'] =~ /^\s*math\s*$/
431
+ el.options[:attr].delete('class')
432
+ else
433
+ el.options[:attr]['class'].sub!(/\s?math/, '')
434
+ end
435
+ el.value.gsub!(/&(amp|quot|gt|lt);/) do |m|
436
+ case m
437
+ when '&amp;' then '&'
438
+ when '&quot;' then '"'
439
+ when '&gt;' then '>'
440
+ when '&lt;' then '<'
441
+ end
442
+ end
443
+ end
350
444
  end
351
445
 
352
446
  include Parser
@@ -374,7 +468,7 @@ module Kramdown
374
468
  end
375
469
  parse_raw_html(@tree, &tag_handler)
376
470
 
377
- ec = ElementConverter.new
471
+ ec = ElementConverter.new(@doc)
378
472
  @tree.children.each {|c| ec.process(c)}
379
473
  ec.remove_whitespace_children(@tree)
380
474
  @tree
@@ -385,3 +479,4 @@ module Kramdown
385
479
  end
386
480
 
387
481
  end
482
+
@@ -174,6 +174,8 @@ module Kramdown
174
174
  @src = StringScanner.new(child.value)
175
175
  parse_spans(child)
176
176
  child.children
177
+ elsif child.type == :eob
178
+ []
177
179
  else
178
180
  update_tree(child)
179
181
  update_attr_with_ial(child.options[:attr] ||= {}, child.options[:ial]) if child.options[:ial]
@@ -62,6 +62,7 @@ module Kramdown
62
62
  def parse_ald
63
63
  @src.pos += @src.matched_size
64
64
  parse_attribute_list(@src[2], @doc.parse_infos[:ald][@src[1]] ||= {})
65
+ @tree.children << Element.new(:eob)
65
66
  true
66
67
  end
67
68
  define_parser(:ald, ALD_START)
@@ -77,6 +78,7 @@ module Kramdown
77
78
  else
78
79
  parse_attribute_list(@src[1], @block_ial = {})
79
80
  end
81
+ @tree.children << Element.new(:eob) unless @src.check(IAL_BLOCK_START)
80
82
  true
81
83
  end
82
84
  define_parser(:block_ial, IAL_BLOCK_START)
@@ -44,6 +44,7 @@ module Kramdown
44
44
  stop_re = (type == :block ? /#{EXT_BLOCK_STOP_STR % ext}/ : /#{EXT_STOP_STR % ext}/)
45
45
  if result = @src.scan_until(stop_re)
46
46
  body = result.sub!(stop_re, '')
47
+ body.chomp! if type == :block
47
48
  else
48
49
  warning("No stop tag for extension '#{ext}' found - treating it as extension without body")
49
50
  end
@@ -55,7 +56,7 @@ module Kramdown
55
56
  def handle_extension(name, opts, body, type)
56
57
  case name
57
58
  when 'comment'
58
- # nothing to do
59
+ @tree.children << Element.new(:comment, body, :category => type) if body.kind_of?(String)
59
60
  when 'nomarkdown'
60
61
  @tree.children << Element.new(:raw, body, :category => type) if body.kind_of?(String)
61
62
  when 'options'
@@ -98,7 +98,7 @@ module Kramdown
98
98
  if result = @src.check(/^#{OPT_SPACE}#{HTML_TAG_RE}/) && !HTML_SPAN_ELEMENTS.include?(@src[1])
99
99
  @src.pos += @src.matched_size
100
100
  handle_html_start_tag(&method(:handle_kramdown_html_tag))
101
- Kramdown::Parser::Html::ElementConverter.new.process(@tree.children.last) if @doc.options[:html_to_native]
101
+ Kramdown::Parser::Html::ElementConverter.new(@doc).process(@tree.children.last) if @doc.options[:html_to_native]
102
102
  true
103
103
  elsif result = @src.check(/^#{OPT_SPACE}#{HTML_TAG_CLOSE_RE}/) && !HTML_SPAN_ELEMENTS.include?(@src[1])
104
104
  @src.pos += @src.matched_size
@@ -161,7 +161,7 @@ module Kramdown
161
161
  add_text(@src.scan(/.*/m), el)
162
162
  end
163
163
  end
164
- Kramdown::Parser::Html::ElementConverter.new.process(el) if @doc.options[:html_to_native]
164
+ Kramdown::Parser::Html::ElementConverter.new(@doc).process(el) if @doc.options[:html_to_native]
165
165
  else
166
166
  add_text(@src.scan(/./))
167
167
  end
@@ -29,7 +29,7 @@ module Kramdown
29
29
  # Parse the HTML entity at the current location.
30
30
  def parse_html_entity
31
31
  @src.pos += @src.matched_size
32
- @tree.children << Element.new(:entity, @src[1] || (@src[2] && @src[2].to_i) || @src[3].hex)
32
+ @tree.children << Element.new(:entity, ::Kramdown::Utils::Entities.entity(@src[1] || (@src[2] && @src[2].to_i) || @src[3].hex))
33
33
  end
34
34
  define_parser(:html_entity, Kramdown::Parser::Html::Constants::HTML_ENTITY_RE, '&')
35
35
 
@@ -86,7 +86,7 @@ module Kramdown
86
86
  end
87
87
  count - el.children.select {|c| c.type == :img}.size == 0
88
88
  end
89
- if !found || el.children.empty?
89
+ if !found || (link_type == :a && el.children.empty?)
90
90
  @src.pos = reset_pos
91
91
  add_text(result)
92
92
  return
@@ -98,7 +98,10 @@ module Kramdown
98
98
  # reference style link or no link url
99
99
  if @src.scan(LINK_INLINE_ID_RE) || !@src.check(/\(/)
100
100
  link_id = (@src[1] || conv_link_id).downcase
101
- if @doc.parse_infos[:link_defs].has_key?(link_id)
101
+ if link_id.empty?
102
+ @src.pos = reset_pos
103
+ add_text(result)
104
+ elsif @doc.parse_infos[:link_defs].has_key?(link_id)
102
105
  add_link(el, @doc.parse_infos[:link_defs][link_id].first, @doc.parse_infos[:link_defs][link_id].last, alt_text)
103
106
  else
104
107
  warning("No link definition for link ID '#{link_id}' found")
@@ -32,7 +32,7 @@ module Kramdown
32
32
  # Used for parsing the first line of a list item or a definition, i.e. the line with list item
33
33
  # marker or the definition marker.
34
34
  def parse_first_list_line(indentation, content)
35
- if content =~ /^\s*\n/
35
+ if content =~ /^\s*(#{IAL_SPAN_START})?\s*\n/
36
36
  indentation = 4
37
37
  else
38
38
  while content =~ /^ *\t/
@@ -75,7 +75,7 @@ module Kramdown
75
75
  item.value, indentation, content_re, indent_re = parse_first_list_line(@src[1].length, @src[2])
76
76
  list.children << item
77
77
 
78
- item.value.sub!(/^#{IAL_SPAN_START}/) do |match|
78
+ item.value.sub!(/^#{IAL_SPAN_START}\s*/) do |match|
79
79
  parse_attribute_list($~[1], item.options[:ial] ||= {})
80
80
  ''
81
81
  end
@@ -119,10 +119,10 @@ module Kramdown
119
119
 
120
120
  if it.children.first.type == :p && (it.children.length < 2 || it.children[1].type != :blank ||
121
121
  (it == list.children.last && it.children.length == 2 && !eob_found)) &&
122
- (list.children.last != it || list.children.size == 1 || list.children[0..-2].any? {|cit| cit.children.first.type != :p})
123
- text = it.children.shift.children.first
124
- text.value += "\n" if !it.children.empty? && it.children[0].type != :blank
125
- it.children.unshift(text)
122
+ (list.children.last != it || list.children.size == 1 ||
123
+ list.children[0..-2].any? {|cit| cit.children.first.type != :p || cit.children.first.options[:transparent]})
124
+ it.children.first.children.first.value += "\n" if it.children.size > 1 && it.children[1].type != :blank
125
+ it.children.first.options[:transparent] = true
126
126
  end
127
127
 
128
128
  if it.children.last.type == :blank
@@ -173,6 +173,11 @@ module Kramdown
173
173
  item.value, indentation, content_re, indent_re = parse_first_list_line(@src[1].length, @src[2])
174
174
  deflist.children << item
175
175
 
176
+ item.value.sub!(/^#{IAL_SPAN_START}\s*/) do |match|
177
+ parse_attribute_list($~[1], item.options[:ial] ||= {})
178
+ ''
179
+ end
180
+
176
181
  def_start_re = /^( {0,#{[3, indentation - 1].min}}:)([\t| ].*?\n)/
177
182
  first_as_para = false
178
183
  elsif result = @src.scan(content_re)
@@ -202,9 +207,8 @@ module Kramdown
202
207
  last = nil
203
208
  end
204
209
  if it.children.first.type == :p && !it.options.delete(:first_as_para)
205
- text = it.children.shift.children.first
206
- text.value += "\n" if !it.children.empty?
207
- it.children.unshift(text)
210
+ it.children.first.children.first.value += "\n" if it.children.size > 1
211
+ it.children.first.options[:transparent] = true
208
212
  end
209
213
  end
210
214