diff --git a/.rubocop.yml b/.rubocop.yml index 64b4698..9fede3e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -16,8 +16,7 @@ AllCops: NewCops: enable Lint/UnusedMethodArgument: - Exclude: - - lib/prawn_html/utils.rb + Enabled: false Naming/FileName: Exclude: diff --git a/examples/tables.html b/examples/tables.html new file mode 100644 index 0000000..45223f2 --- /dev/null +++ b/examples/tables.html @@ -0,0 +1,26 @@ + + + + Tables + + +
Tables
+ + + + + + + + + + + + + + + + +
A 1A 2A 3
B 1B 2B 3
C 1C 2C 3
+ + diff --git a/examples/tables.pdf b/examples/tables.pdf new file mode 100644 index 0000000..d42766f Binary files /dev/null and b/examples/tables.pdf differ diff --git a/lib/prawn_html/context.rb b/lib/prawn_html/context.rb index c5250da..6ea340b 100644 --- a/lib/prawn_html/context.rb +++ b/lib/prawn_html/context.rb @@ -7,11 +7,12 @@ class Context < Array }.freeze attr_reader :previous_tag - attr_accessor :last_text_node + attr_accessor :last_text_node, :current_table # Init the Context def initialize(*_args) super + @current_table = nil @last_text_node = false @merged_styles = nil @previous_tag = nil diff --git a/lib/prawn_html/document_renderer.rb b/lib/prawn_html/document_renderer.rb index 32f5cb7..2f65590 100644 --- a/lib/prawn_html/document_renderer.rb +++ b/lib/prawn_html/document_renderer.rb @@ -66,7 +66,13 @@ def on_text_node(content) def render return if buffer.empty? - output_content(buffer.dup, context.block_styles) + content = prepare_content(buffer.dup, context.block_styles) + if context.current_table + td_content = content.dig(:buffer, 0, :text) + context.current_table.update_content(td_content) + else + pdf.puts(content[:buffer], content[:options], left_indent: content[:left_indent], bounding_box: content[:bounds]) + end buffer.clear @last_margin = 0 end @@ -94,14 +100,15 @@ def render_if_needed(element) end def apply_tag_close_styles(element) - tag_styles = element.tag_close_styles + tag_styles = element.tag_closing(context: context) + pdf.table(element.table_data) if element.is_a?(Tags::Table) @last_margin = tag_styles[:margin_bottom].to_f pdf.advance_cursor(last_margin + tag_styles[:padding_bottom].to_f) pdf.start_new_page if tag_styles[:break_after] end def apply_tag_open_styles(element) - tag_styles = element.tag_open_styles + tag_styles = element.tag_opening(context: context) move_down = (tag_styles[:margin_top].to_f - last_margin) + tag_styles[:padding_top].to_f pdf.advance_cursor(move_down) if move_down > 0 pdf.start_new_page if tag_styles[:break_before] @@ -118,12 +125,12 @@ def prepare_text(content) @last_text = text end - def output_content(buffer, block_styles) + def prepare_content(buffer, block_styles) apply_callbacks(buffer) left_indent = block_styles[:margin_left].to_f + block_styles[:padding_left].to_f options = block_styles.slice(:align, :indent_paragraphs, :leading, :mode, :padding_left) options[:leading] = adjust_leading(buffer, options[:leading]) - pdf.puts(buffer, options, bounding_box: bounds(buffer, options, block_styles), left_indent: left_indent) + { buffer: buffer, options: options, left_indent: left_indent, bounds: bounds(buffer, options, block_styles) } end def apply_callbacks(buffer) diff --git a/lib/prawn_html/pdf_wrapper.rb b/lib/prawn_html/pdf_wrapper.rb index 7a816ab..72a02d4 100644 --- a/lib/prawn_html/pdf_wrapper.rb +++ b/lib/prawn_html/pdf_wrapper.rb @@ -1,12 +1,13 @@ # frozen_string_literal: true require 'forwardable' +require 'prawn/table' module PrawnHtml class PdfWrapper extend Forwardable - def_delegators :@pdf, :start_new_page + def_delegators :@pdf, :start_new_page, :table # Wrapper for Prawn PDF Document # diff --git a/lib/prawn_html/tag.rb b/lib/prawn_html/tag.rb index 1f0505f..533046f 100644 --- a/lib/prawn_html/tag.rb +++ b/lib/prawn_html/tag.rb @@ -9,7 +9,7 @@ class Tag 'StrikeThrough' => Callbacks::StrikeThrough }.freeze - TAG_CLASSES = %w[A B Blockquote Body Br Code Del Div H Hr I Img Li Mark Ol P Pre Small Span Sub Sup U Ul].freeze + TAG_CLASSES = %w[A B Blockquote Body Br Code Del Div H Hr I Img Li Mark Ol P Pre Small Span Sub Sup Table Td Tr U Ul].freeze def_delegators :@attrs, :styles, :update_styles @@ -53,17 +53,17 @@ def process_styles(element_styles: nil) attrs.merge_text_styles!(extra_styles, options: options) if respond_to?(:extra_styles) end - # Styles to apply on tag closing + # Tag closing callback that applies tag's specific styles # # @return [Hash] hash of styles to apply - def tag_close_styles + def tag_closing(context: nil) styles.slice(*Attributes::STYLES_APPLY[:tag_close]) end - # Styles to apply on tag opening + # Tag opening callback that applies tag's specific styles # # @return [Hash] hash of styles to apply - def tag_open_styles + def tag_opening(context: nil) styles.slice(*Attributes::STYLES_APPLY[:tag_open]) end diff --git a/lib/prawn_html/tags/table.rb b/lib/prawn_html/tags/table.rb new file mode 100644 index 0000000..7c37f71 --- /dev/null +++ b/lib/prawn_html/tags/table.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module PrawnHtml + module Tags + class Table < Tag + ELEMENTS = [:table].freeze + + attr_reader :table_data + + def block? + true + end + + def new_cell + @col_index += 1 + @table_data[@row_index] << '' + end + + def new_row + @row_index += 1 + @col_index = -1 + @table_data << [] + end + + def update_content(content) + @table_data[@row_index][@col_index] = content + end + + def tag_opening(context: nil) + super.tap do + context.current_table = self + @row_index = -1 + @table_data = [] + end + end + + def tag_closing(context: nil) + super.tap do + context.current_table = nil + end + end + end + end +end diff --git a/lib/prawn_html/tags/td.rb b/lib/prawn_html/tags/td.rb new file mode 100644 index 0000000..29d29c9 --- /dev/null +++ b/lib/prawn_html/tags/td.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module PrawnHtml + module Tags + class Td < Tag + ELEMENTS = [:td].freeze + + def block? + true + end + + def tag_opening(context: nil) + super.tap do + context.current_table&.new_cell + end + end + end + end +end diff --git a/lib/prawn_html/tags/tr.rb b/lib/prawn_html/tags/tr.rb new file mode 100644 index 0000000..d065760 --- /dev/null +++ b/lib/prawn_html/tags/tr.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module PrawnHtml + module Tags + class Tr < Tag + ELEMENTS = [:tr].freeze + + def block? + true + end + + def tag_opening(context: nil) + super.tap do + context.current_table&.new_row + end + end + end + end +end diff --git a/prawn-html.gemspec b/prawn-html.gemspec index 954d174..f4deede 100644 --- a/prawn-html.gemspec +++ b/prawn-html.gemspec @@ -26,4 +26,5 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'oga', '~> 3.3' spec.add_runtime_dependency 'prawn', '~> 2.4' + spec.add_runtime_dependency 'prawn-table', '~> 0.2.2' end diff --git a/spec/units/prawn_html/document_renderer_spec.rb b/spec/units/prawn_html/document_renderer_spec.rb index e9b72d6..e9accd4 100644 --- a/spec/units/prawn_html/document_renderer_spec.rb +++ b/spec/units/prawn_html/document_renderer_spec.rb @@ -18,12 +18,12 @@ before do allow(context).to receive(:remove_last) - allow(element).to receive(:tag_close_styles).and_call_original + allow(element).to receive(:tag_closing).and_call_original end it 'handles tag closing', :aggregate_failures do on_tag_close - expect(element).to have_received(:tag_close_styles) + expect(element).to have_received(:tag_closing) expect(context).to have_received(:remove_last) end end diff --git a/spec/units/prawn_html/tag_spec.rb b/spec/units/prawn_html/tag_spec.rb index e6e4d89..87755fd 100644 --- a/spec/units/prawn_html/tag_spec.rb +++ b/spec/units/prawn_html/tag_spec.rb @@ -94,14 +94,14 @@ def tag_styles it { is_expected.to eq(color: '0088ff') } end - describe '#tag_close_styles' do - subject(:tag_close_styles) { tag.tag_close_styles } + describe '#tag_closing' do + subject(:tag_closing) { tag.tag_closing } it { is_expected.to eq({}) } end - describe '#tag_open_styles' do - subject(:tag_open_styles) { tag.tag_open_styles } + describe '#tag_opening' do + subject(:tag_opening) { tag.tag_opening } it { is_expected.to eq({}) } end