diff --git a/lib/md_to_pdf/elements/html.rb b/lib/md_to_pdf/elements/html.rb index 4419602..7633f7a 100644 --- a/lib/md_to_pdf/elements/html.rb +++ b/lib/md_to_pdf/elements/html.rb @@ -107,14 +107,11 @@ def data_inlinehtml_tag(tag, node, opts) when 'img' result.push({ image: sub.attr('src') }) when 'input' - if sub.attr('type') == 'checkbox' - checkbox = opt_task_list_point_sign(@styles.task_list_point, sub.attributes.key?('checked')) - result.push(text_hash(checkbox, current_opts)) - else - data_array, current_opts = handle_unknown_inline_html_tag(sub, node, current_opts) - result.concat(data_array) - end - when 'ul', 'ol', 'li', 'label', 'p' + data_array, current_opts = handle_unknown_inline_html_tag(sub, node, current_opts) + result.concat(data_array) + when 'ul', 'ol' + result.concat(data_inlinehtml_list_tag(sub, node, opts)) + when 'label', 'p', 'li' result.concat(data_inlinehtml_tag(sub, node, opts)) when 'br' result.push(text_hash_raw("\n", current_opts)) @@ -126,6 +123,25 @@ def data_inlinehtml_tag(tag, node, opts) result end + def data_inlinehtml_list_tag(tag, node, opts) + result = [] + points, level, _list_style, content_opts = data_html_list(tag, node, opts) + result.push(text_hash_raw("\n", content_opts).merge({ list_level: level, list_indent: 0 })) if level > 1 + points.each do |point| + data = data_inlinehtml_tag(point[:tag], node, content_opts) + data.push(text_hash_raw("\n", content_opts).merge({ list_entry_type: 'end' })) + data[0][:list_entry_type] = 'first' unless data.empty? + data.unshift(text_hash(point[:bullet], point[:opts]).merge({ list_entry_type: 'bullet' })) + data.each do |item| + item[:list_level] = level if item[:list_level].nil? + item[:list_indent] = point[:width] if item[:list_indent].nil? + item[:list_indent_space] = point[:space_width] if item[:list_indent_space].nil? + end + result.concat(data) + end + result + end + def collect_html_table_tag_rows(tag, table_font_opts, opts) rows = [] tag.children.each do |sub| @@ -257,16 +273,51 @@ def collect_html_table_tag_cell(tag, opts) cell_data end + def space_stuffing(width, space_width) + amount = (width / space_width).truncate + return '' if amount < 1 + + Prawn::Text::NBSP * amount + end + + def indent_html_table_list_items(cell_data) + cell_data.each do |item| + next if item[:list_level].nil? + + # Note: There is no settings for paddings of text fragments in Prawn::Table + # so as a workaround the lists are stuffed with spaces, which is of course not pixel perfect + + # first indenting with spaces of multiline list items + # * item + # multiline item + # multiline item + if item[:list_entry_type].nil? && item[:text] != "\n" + item[:text] = "#{space_stuffing(item[:list_indent], item[:list_indent_space])}#{item[:text]}" + end + + # second indenting of nested lists + # * item + # multiline item + # * sub list item + # * sub list item + # sub list multiline item + if item[:list_level] > 1 && (item[:list_entry_type].nil? || item[:list_entry_type] == 'bullet') && item[:text] != "\n" + item[:text] = "#{space_stuffing(item[:list_indent], item[:list_indent_space])}#{item[:text]}" + end + end + cell_data + end + def collect_html_table_tag_row(tag, table_font_opts, opts) cells = [] tag.children.each do |sub| case sub.name when 'th' cell_data = collect_html_table_tag_cell(sub, opts.merge(table_font_opts[:header])) - cells.push(cell_data) + cells.push(indent_html_table_list_items(cell_data)) when 'td' cell_data = collect_html_table_tag_cell(sub, opts.merge(table_font_opts[:cell])) - cells.push(cell_data) + cells.push(indent_html_table_list_items(cell_data)) end end cells diff --git a/lib/md_to_pdf/elements/list.rb b/lib/md_to_pdf/elements/list.rb index ac68ddd..1aa97d9 100644 --- a/lib/md_to_pdf/elements/list.rb +++ b/lib/md_to_pdf/elements/list.rb @@ -25,12 +25,11 @@ def draw_list(node, opts) end end - def draw_html_list_tag(tag, node, opts) + def data_html_list(tag, node, opts) level = count_list_level_html(tag) is_ordered = tag.name.downcase == 'ol' - list_style = list_style(level, is_ordered, false) - padding = level == 1 ? opts_padding(list_style) : {} - # point_inline = opt_list_point_inline?(list_style) + is_task_list = !tag.search("input[type=checkbox]").first.nil? + list_style = list_style(level, is_ordered, is_task_list) content_opts = opts_font(list_style, opts).merge( { force_paragraph: { @@ -38,7 +37,13 @@ def draw_html_list_tag(tag, node, opts) } } ) - points = collect_points_html(tag, level, is_ordered, content_opts) + points = collect_points_html(tag, level, is_ordered, is_task_list, content_opts) + [points, level, list_style, content_opts] + end + + def draw_html_list_tag(tag, node, opts) + points, level, list_style, content_opts = data_html_list(tag, node, opts) + padding = level == 1 ? opts_padding(list_style) : {} with_block_padding_all(padding) do draw_points_html(points, node, content_opts) end @@ -82,8 +87,8 @@ def draw_inline_points(points, opts) end end - def collect_points_html(tag, level, is_ordered, content_opts) - point_style = list_point_style(level, is_ordered, false) + def collect_points_html(tag, level, is_ordered, is_task_list, content_opts) + point_style = list_point_style(level, is_ordered, is_task_list) auto_span = opt_list_point_spanning?(point_style) bullet_opts = opts_font(point_style, content_opts) spacing = opt_list_point_spacing(point_style) @@ -91,13 +96,22 @@ def collect_points_html(tag, level, is_ordered, content_opts) index = 1 tag.children.each do |sub| if sub.name.downcase == 'li' - bullet = list_bullet(point_style, is_ordered, false, index, false) + checked = false + if is_task_list + checked_box_tag = tag.search("input[type=checkbox]").first + unless checked_box_tag.nil? + checked = checked_box_tag.attributes.key?('checked') + checked_box_tag.remove + end + end + bullet = list_bullet(point_style, is_ordered, is_task_list, index, checked) bullet_width = measure_text_width(bullet, bullet_opts) + spacing - points.push({ tag: sub, bullet: bullet, width: bullet_width, opts: bullet_opts }) + space_width = measure_text_width(Prawn::Text::NBSP, bullet_opts) + points.push({ tag: sub, bullet: bullet, width: bullet_width, space_width: space_width, opts: bullet_opts }) index += 1 end end - if auto_span + if auto_span || is_task_list max_span = max_point_width(points) points.each { |point| point[:width] = max_span } end diff --git a/spec/fixtures/list/tasklist_html.md b/spec/fixtures/list/tasklist_html.md new file mode 100644 index 0000000..1f0ce93 --- /dev/null +++ b/spec/fixtures/list/tasklist_html.md @@ -0,0 +1 @@ +
|
|