Skip to content

Commit

Permalink
even better support for html tables (#18)
Browse files Browse the repository at this point in the history
split styles definition for html table vs markdown table; no forced borders for html tables
  • Loading branch information
as-op authored Jan 29, 2025
1 parent 0bd488f commit 6d63af6
Show file tree
Hide file tree
Showing 19 changed files with 213 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
ruby-version: '3.2.1'
bundler-cache: true
- name: Run rspec
run: bundle exec rspec
Expand Down
10 changes: 6 additions & 4 deletions demo/demo.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,24 @@ pdf_fields:

# Horizontal Rules

`___`
Code: `___`

___

`---`
Code: `---`

---

`***`
Code: `***`

***

`_________________`
Code: `_________________`

_________________

<br-page/>

# Emphasis

This is **bold** text with `**`
Expand Down
1 change: 1 addition & 0 deletions docs/STYLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
| `blockquote` | **Blockquote**<br/>Styling to denote a paragraph as quote<br/>See [Blockquote](#blockquote) | object |
| `link` | **Link**<br/>Styling a clickable link<br/>See [Link](#link) | object |
| `table` | **Table**<br/>See [Table](#table) | object |
| `html_table` | **Table**<br/>See [Table](#table) | object |
| `headless_table` | **Headless table**<br/>Tables without or empty header rows can be styled differently.<br/>See [Headless table](#headless-table) | object |
| `image` | **Image**<br/>Styling of images<br/>See [Image](#image) | object |
| `image_classes` | **Image classes**<br/>Styling for images by class names<br/>See [Image classes](#image-classes) | object |
Expand Down
18 changes: 11 additions & 7 deletions lib/md_to_pdf/elements/html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def collect_html_table_tag_rows(tag, table_font_opts, opts)
end

def draw_html_table_tag(tag, opts)
current_opts = opts.merge({ is_in_table: true })
current_opts = opts.merge({ is_in_table: true, is_html_table: true })
table_font_opts = build_table_font_opts(current_opts)
rows = collect_html_table_tag_rows(tag, table_font_opts, current_opts)
column_count = 0
Expand Down Expand Up @@ -329,12 +329,15 @@ def remove_font_style(opts, style)

def collect_html_table_tag_cell(tag, opts)
cell_data = data_inlinehtml_tag(tag, nil, opts)
if tag.key?('style')
style = tag.get_attribute('style') || ''
cell_styling = parse_css_stylings(style)
cell_data = [{}] if cell_data.empty?
cell_data[0] = cell_data[0].merge(cell_styling)
end
cell_styling =
if tag.key?('style')
style = tag.get_attribute('style') || ''
parse_css_stylings(style)
else
{ cell_borders: [] }
end
cell_data = [{}] if cell_data.empty?
cell_data[0] = cell_data[0].merge(cell_styling)
cell_data
end

Expand All @@ -360,6 +363,7 @@ def parse_css_stylings(style)
end
end
{
cell_borders: cell_border_color || cell_border_width || cell_border_style ? %i[left right top bottom] : [],
cell_background_color: cell_background_color,
cell_border_color: cell_border_color,
cell_border_width: cell_border_width,
Expand Down
36 changes: 24 additions & 12 deletions lib/md_to_pdf/elements/table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def make_table_cell(cell_data, opts)
border_colors: additional_cell_settings[:cell_border_color] || opts.dig(:opts_cell, :border_colors),
border_widths: additional_cell_settings[:cell_border_width] || opts.dig(:opts_cell, :border_widths),
border_line: additional_cell_settings[:cell_border_style] ? [additional_cell_settings[:cell_border_style]] * 4 : opts.dig(:opts_cell, :border_line),
borders: additional_cell_settings[:cell_borders],
inline_format: true
}.compact
Prawn::Table::Cell::Text.new(@pdf, [0, 0], cell_opts)
Expand All @@ -40,7 +41,7 @@ def draw_table_data(table, data_rows, column_alignments, opts)
return if data_rows.empty?

data = build_table_data(data_rows, column_alignments, opts)
pdf_tables = try_build_table(table, data, column_alignments)
pdf_tables = try_build_table(table, data, column_alignments, opts)
pdf_tables.each do |pdf_table|
optional_break_before_table(table, pdf_table)
with_block_margin_all(table[:margins]) do
Expand All @@ -60,7 +61,11 @@ def build_table_settings(header_row_count, opts)
cell_style = @styles.table_cell
header_style = @styles.table_header

if header_row_count == 0
if opts[:is_html_table]
table_style = @styles.html_table
cell_style = @styles.html_table_cell
header_style = @styles.html_table_header
elsif header_row_count == 0
table_style = @styles.headless_table
cell_style = @styles.headless_table_cell
header_style = @styles.headless_table_header
Expand All @@ -82,7 +87,7 @@ def build_table_settings(header_row_count, opts)

private

def build_split_tables(table, data, column_alignments)
def build_split_tables(table, data, column_alignments, opts)
range = 4
header_row_count = table[:header_row_count]
pdf_tables = []
Expand All @@ -96,16 +101,16 @@ def build_split_tables(table, data, column_alignments)
end
new_column_alignments = column_alignments.slice(start, range)
new_column_alignments.unshift :left
pdf_table = build_pdf_table(table, table[:opts_cell], new_rows, new_column_alignments)
pdf_table = build_pdf_table(table, table[:opts_cell], new_rows, new_column_alignments, opts)
pdf_tables.push pdf_table
end
pdf_tables
end

def try_build_table(table, data, column_alignments)
[build_pdf_table(table, table[:opts_cell], data, column_alignments)]
def try_build_table(table, data, column_alignments, opts)
[build_pdf_table(table, table[:opts_cell], data, column_alignments, opts)]
rescue Prawn::Errors::CannotFit
build_split_tables(table, data, column_alignments)
build_split_tables(table, data, column_alignments, opts)
end

def merge_cell_data(cell_data)
Expand All @@ -125,12 +130,10 @@ def optional_break_before_table(table, pdf_table)
end
end

def build_pdf_table(table, cell_style, data, column_alignments)
def build_pdf_table(table, cell_style, data, column_alignments, opts)
column_count = column_alignments.length
column_widths = Array.new(column_count, @pdf.bounds.right / column_count)
# the default border width/color property overrides the already set cell border widths/colors
# so we remove it and set it manually for each cell on creation
default_cell_style = cell_style.except(:border_widths, :border_colors)
default_cell_style = opts[:is_html_table] ? cell_style.except(:borders, :border_widths, :border_colors) : cell_style
@pdf.make_table(
data,
width: @pdf.bounds.right,
Expand Down Expand Up @@ -172,7 +175,16 @@ def make_subtable(cell_data, opts, alignment, column_count)
rows.push([make_subtable_cell(row, opts)]) unless row.empty?
return make_table_cell([{ text: '' }], opts) if rows.empty?

@pdf.make_table(rows, column_widths: [@pdf.bounds.width / column_count]) do
additional_cell_settings = cell_data[0] || {}
subtable_cell_style = {
border_colors: additional_cell_settings[:cell_border_color] || opts.dig(:opts_cell, :border_colors),
border_widths: additional_cell_settings[:cell_border_width] || opts.dig(:opts_cell, :border_widths),
border_line: additional_cell_settings[:cell_border_style] ? [additional_cell_settings[:cell_border_style]] * 4 : opts.dig(:opts_cell, :border_line),
borders: additional_cell_settings[:cell_borders]
}.compact
@pdf.make_table(rows,
cell_style: subtable_cell_style,
column_widths: [@pdf.bounds.width / column_count]) do
columns(0).align = alignment unless alignment == nil
end
end
Expand Down
13 changes: 13 additions & 0 deletions lib/md_to_pdf/ext/prawn-table/table/cell/cell/subtable.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
Prawn::Table::Cell::Subtable.prepend(Module.new do
def initialize(pdf, point, options = {})
super

border_cell = @subtable.cells[0, 0]
if border_cell
@borders = border_cell.borders
@border_colors = border_cell.border_colors
@border_lines = border_cell.border_lines
@border_widths = border_cell.border_widths
end
@subtable.cells.borders = []
end

def width=(new_width)
@width = @min_width = @max_width = new_width
@height = nil
Expand Down
3 changes: 3 additions & 0 deletions lib/md_to_pdf/style/schema_styles.json
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@
"table": {
"$ref": "#/$defs/table"
},
"html_table": {
"$ref": "#/$defs/table"
},
"headless_table": {
"$ref": "#/$defs/headless_table"
},
Expand Down
14 changes: 14 additions & 0 deletions lib/md_to_pdf/style/styles.rb
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ def headless_table_header
headless_table[:header] || {}
end

def html_table
return table if @styling[:html_table].nil?

get_style(:html_table)
end

def html_table_cell
html_table[:cell] || {}
end

def html_table_header
html_table[:header] || {}
end

def codeblock
get_style(:codeblock)
end
Expand Down
File renamed without changes.
File renamed without changes.
30 changes: 10 additions & 20 deletions spec/fixtures/table/html_borders.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,29 @@
<tr>
<td style="border:10px dotted hsl(0, 0%, 0%);">dotted</td>
<td
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p
>column1</td>
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p>column1</p></td>
<td
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p
>column2</td>
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p>column2</p></td>
<td
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p
>column3</td>
>column3</p></td>
<td
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p
>column4</td>
style="border-color:hsl(0, 0%, 0%);border-style:solid;"><p>column4</p></td>
</tr>
<tr>
<td
style="border-color:hsl(0, 0%, 0%);border-style:solid;">
line1</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">line1</td>
<td style="border:2px solid hsl(0, 0%, 0%);">width: 2px</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">
default</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">
default</td>
<td style="border-color:hsl(219,100%,50%);border-style:solid;border-width: 3px">
blue</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">default</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">default</td>
<td style="border-color:hsl(219,100%,50%);border-style:solid;border-width: 3px">blue</td>
</tr>
<tr>
<td
style="border-color:hsl(0, 0%, 0%);border-style:solid;">
line3</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">
default</td>
<td style="border-color:hsl(0, 0%, 0%);border-style:solid;">default</td>
<td style="border:2px dashed hsl(30, 75%, 60%);">dashed</td>
<td style="border-color:hsl(0,100%,50%);border-style:solid;">
red</td>
<td style="border-color:hsl(0,100%,50%);border-style:solid;">red</td>
<td style="border:4px solid hsl(0, 0%, 0%);">width: 4px</td>
</tr>
<tr>
Expand Down
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions spec/fixtures/table/html_no_borders.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<table>
<tbody>
<tr>
<td>No</td>
<td>Borders!</td>
</tr>
</tbody>
</table>
21 changes: 21 additions & 0 deletions spec/fixtures/table/subtable_in_header_row.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<table>
<thead>
<tr>
<th style="border-color:hsl(0, 0%, 0%);border-style:solid;"><br></th>
<th style="border-color:hsl(0, 0%, 0%);border-style:solid;">Header 1<img src="demo.jpg"></th>
<th style="border-color:hsl(0, 0%, 0%);border-style:solid;">Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<th>Entry 1</th>
<td></td>
<td></td>
</tr>
<tr>
<th>Entry 2</th>
<td></td>
<td></td>
</tr>
</tbody>
</table>
21 changes: 0 additions & 21 deletions spec/fixtures/table/subtable_in_header_row.md

This file was deleted.

6 changes: 3 additions & 3 deletions spec/markdown_to_pdf/image_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@
expect_pdf_images([{ x: 256.0, y: 676.925, width: 100.0, height: 79.075 }])
end

it 'creates image in table' do
generator.parse_file('image/in_table.md', { headless_table: { auto_width: true } })
it 'creates image in a html table' do
generator.parse_file('image/in_table.html', { html_table: { auto_width: true } })
expect_pdf([
{ x: 41.0, y: 739.756, text: "Lorem ipsum dolor sit amet, consetetur" },
{ x: 41.0, y: 725.884, text: "sadipscing elitr, sed diam nonumy eirmod tempor" },
Expand Down Expand Up @@ -129,7 +129,7 @@
end

it 'creates large image in table' do
generator.parse_file('image/large_in_table.md', { headless_table: { auto_width: true } })
generator.parse_file('image/large_in_table.html', { html_table: { auto_width: true } })
expect_pdf([
{ x: 36.0, y: 747.384, text: "With image style.width:" },
{ x: 41.0, y: 725.884, text: "Lorem ipsum dolor sit amet, consetetur" },
Expand Down
Loading

0 comments on commit 6d63af6

Please sign in to comment.