prawn-html 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3eec6595a60748790725f32e92e7b749d92086e5331d8a572d287a3a90f9d83a
4
- data.tar.gz: 89bcbe740f84c4ecdea2877e96d0f677a25bf424325b41fa40caf3d1351fba96
3
+ metadata.gz: e82e0a464e39fd4c47c399cb043ceefe090524b29ead1c06795a484d4c648388
4
+ data.tar.gz: e124a7fb9800a434f42d403b478c6a6cb30b4e7d1e7e540d015028dec6daaa59
5
5
  SHA512:
6
- metadata.gz: 9b34f31b07aaac30910fd1bcb2118b9cbe92bbdaf4ac80850520887e7c3803a6bb1217764551baeeb1a88d695d7b26c4885a4d3065bbd1f20527d37a5723c7bf
7
- data.tar.gz: 6ed594bd070e4e4cf20519c28094f7d57eeb779f60c4867f380aab22946d20401bac307e17db47c0560b2cf1cdc591d80e07c3ff54999db92bd3040e19cc18d7
6
+ metadata.gz: c08e1252e2c9c8f1591840179549d3e14483d91361b1a9f56d96f23cfa30829b98d8d2ace33808a73a9467e1ff37054d7f462d1c7170db273a4ff83b203d807f
7
+ data.tar.gz: '0979bd9a66e463ee8e4ea3c141a2d4e2fcc0e3b1bc82397aeda2e357c10c4518b00b1e1e4fc3f2ec786070c6d229241423cd5933a89fbc9137bdccc211d22a44'
data/lib/prawn-html.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PrawnHtml
4
- PX = 0.66 # conversion constant for pixel sixes
4
+ PX = 0.6 # conversion constant for pixel sixes
5
5
 
6
6
  COLORS = {
7
7
  'aliceblue' => 'f0f8ff',
@@ -7,16 +7,15 @@ module PrawnHtml
7
7
  attr_reader :styles
8
8
 
9
9
  STYLES_APPLY = {
10
- block: %i[align leading left margin_left padding_left position top],
10
+ block: %i[align bottom leading left margin_left padding_left position right top],
11
11
  tag_close: %i[margin_bottom padding_bottom break_after],
12
12
  tag_open: %i[margin_top padding_top break_before],
13
- text_node: %i[background callback character_spacing color font link list_style_type size styles white_space]
13
+ text_node: %i[callback character_spacing color font link list_style_type size styles white_space]
14
14
  }.freeze
15
15
 
16
16
  STYLES_LIST = {
17
17
  # text node styles
18
- 'background' => { key: :background, set: :convert_color },
19
- 'callback' => { key: :callback, set: :copy_value },
18
+ 'background' => { key: :callback, set: :callback_background },
20
19
  'color' => { key: :color, set: :convert_color },
21
20
  'font-family' => { key: :font, set: :unquote },
22
21
  'font-size' => { key: :size, set: :convert_size },
@@ -25,7 +24,7 @@ module PrawnHtml
25
24
  'href' => { key: :link, set: :copy_value },
26
25
  'letter-spacing' => { key: :character_spacing, set: :convert_float },
27
26
  'list-style-type' => { key: :list_style_type, set: :unquote },
28
- 'text-decoration' => { key: :styles, set: :append_styles },
27
+ 'text-decoration' => { key: :styles, set: :append_text_decoration },
29
28
  'vertical-align' => { key: :styles, set: :append_styles },
30
29
  'white-space' => { key: :white_space, set: :convert_symbol },
31
30
  # tag opening styles
@@ -37,13 +36,15 @@ module PrawnHtml
37
36
  'margin-bottom' => { key: :margin_bottom, set: :convert_size },
38
37
  'padding-bottom' => { key: :padding_bottom, set: :convert_size },
39
38
  # block styles
40
- 'left' => { key: :left, set: :convert_size },
39
+ 'bottom' => { key: :bottom, set: :convert_size, options: :height },
40
+ 'left' => { key: :left, set: :convert_size, options: :width },
41
41
  'line-height' => { key: :leading, set: :convert_size },
42
42
  'margin-left' => { key: :margin_left, set: :convert_size },
43
43
  'padding-left' => { key: :padding_left, set: :convert_size },
44
44
  'position' => { key: :position, set: :convert_symbol },
45
+ 'right' => { key: :right, set: :convert_size, options: :width },
45
46
  'text-align' => { key: :align, set: :convert_symbol },
46
- 'top' => { key: :top, set: :convert_size }
47
+ 'top' => { key: :top, set: :convert_size, options: :height }
47
48
  }.freeze
48
49
 
49
50
  STYLES_MERGE = %i[margin_left padding_left].freeze
@@ -67,9 +68,10 @@ module PrawnHtml
67
68
  # Merge text styles
68
69
  #
69
70
  # @param text_styles [String] styles to parse and process
70
- def merge_text_styles!(text_styles)
71
+ # @param options [Hash] options (container width/height/etc.)
72
+ def merge_text_styles!(text_styles, options: {})
71
73
  hash_styles = Attributes.parse_styles(text_styles)
72
- process_styles(hash_styles) unless hash_styles.empty?
74
+ process_styles(hash_styles, options: options) unless hash_styles.empty?
73
75
  end
74
76
 
75
77
  class << self
@@ -100,21 +102,33 @@ module PrawnHtml
100
102
 
101
103
  private
102
104
 
103
- def apply_rule!(result, rule, value)
104
- return unless rule
105
+ def process_styles(hash_styles, options:)
106
+ hash_styles.each do |key, value|
107
+ rule = evaluate_rule(key, value)
108
+ apply_rule!(merged_styles: @styles, rule: rule, value: value, options: options)
109
+ end
110
+ @styles
111
+ end
105
112
 
106
- if rule[:set] == :append_styles
107
- (result[rule[:key]] ||= []) << Utils.normalize_style(value)
108
- else
109
- result[rule[:key]] = Utils.send(rule[:set], value)
113
+ def evaluate_rule(rule_key, attr_value)
114
+ rule = STYLES_LIST[rule_key]
115
+ if rule && rule[:set] == :append_text_decoration
116
+ return { key: :callback, set: :callback_strike_through } if attr_value == 'line-through'
117
+
118
+ return { key: :styles, set: :append_styles }
110
119
  end
120
+ rule
111
121
  end
112
122
 
113
- def process_styles(hash_styles)
114
- hash_styles.each do |key, value|
115
- apply_rule!(@styles, STYLES_LIST[key], value)
123
+ def apply_rule!(merged_styles:, rule:, value:, options:)
124
+ return unless rule
125
+
126
+ if rule[:set] == :append_styles
127
+ (merged_styles[rule[:key]] ||= []) << Utils.normalize_style(value)
128
+ else
129
+ opts = rule[:options] ? options[rule[:options]] : nil
130
+ merged_styles[rule[:key]] = Utils.send(rule[:set], value, options: opts)
116
131
  end
117
- @styles
118
132
  end
119
133
  end
120
134
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module PrawnHtml
4
4
  module Callbacks
5
- class Highlight
5
+ class Background
6
6
  DEF_HIGHLIGHT = 'ffff00'
7
7
 
8
- def initialize(pdf, item)
8
+ def initialize(pdf, color = nil)
9
9
  @pdf = pdf
10
- @color = item.delete(:background) || DEF_HIGHLIGHT
10
+ @color = color || DEF_HIGHLIGHT
11
11
  end
12
12
 
13
13
  def render_behind(fragment)
@@ -2,15 +2,17 @@
2
2
 
3
3
  module PrawnHtml
4
4
  class Context < Array
5
- DEF_FONT_SIZE = 10.3
5
+ DEF_FONT_SIZE = 16 * PX
6
6
 
7
- attr_accessor :last_margin, :last_text_node
7
+ attr_reader :previous_tag
8
+ attr_accessor :last_text_node
8
9
 
9
10
  # Init the Context
10
11
  def initialize(*_args)
11
12
  super
12
- @last_margin = 0
13
13
  @last_text_node = false
14
+ @merged_styles = nil
15
+ @previous_tag = nil
14
16
  end
15
17
 
16
18
  # Add an element to the context
@@ -25,6 +27,7 @@ module PrawnHtml
25
27
  element.parent = last
26
28
  push(element)
27
29
  element.on_context_add(self) if element.respond_to?(:on_context_add)
30
+ @merged_styles = nil
28
31
  self
29
32
  end
30
33
 
@@ -49,11 +52,21 @@ module PrawnHtml
49
52
  # Merge the context styles for text nodes
50
53
  #
51
54
  # @return [Hash] the hash of merged styles
52
- def text_node_styles
53
- each_with_object(base_styles) do |element, res|
54
- evaluate_element_styles(element, res)
55
- element.update_styles(res) if element.respond_to?(:update_styles)
56
- end
55
+ def merged_styles
56
+ @merged_styles ||=
57
+ each_with_object(base_styles) do |element, res|
58
+ evaluate_element_styles(element, res)
59
+ element.update_styles(res) if element.respond_to?(:update_styles)
60
+ end
61
+ end
62
+
63
+ # Remove the last element from the context
64
+ def remove_last
65
+ last.on_context_remove(self) if last.respond_to?(:on_context_remove)
66
+ @merged_styles = nil
67
+ @last_text_node = false
68
+ @previous_tag = last.tag
69
+ pop
57
70
  end
58
71
 
59
72
  private
@@ -11,6 +11,7 @@ module PrawnHtml
11
11
  def initialize(pdf)
12
12
  @buffer = []
13
13
  @context = Context.new
14
+ @last_margin = 0
14
15
  @pdf = pdf
15
16
  end
16
17
 
@@ -20,8 +21,7 @@ module PrawnHtml
20
21
  def on_tag_close(element)
21
22
  render_if_needed(element)
22
23
  apply_tag_close_styles(element)
23
- context.last_text_node = false
24
- context.pop
24
+ context.remove_last
25
25
  end
26
26
 
27
27
  # On tag open callback
@@ -35,8 +35,9 @@ module PrawnHtml
35
35
  tag_class = Tag.class_for(tag_name)
36
36
  return unless tag_class
37
37
 
38
- tag_class.new(tag_name, attributes: attributes, element_styles: element_styles).tap do |element|
39
- setup_element(element)
38
+ options = { width: pdf.page_width, height: pdf.page_height }
39
+ tag_class.new(tag_name, attributes: attributes, options: options).tap do |element|
40
+ setup_element(element, element_styles: element_styles)
40
41
  end
41
42
  end
42
43
 
@@ -48,7 +49,7 @@ module PrawnHtml
48
49
  def on_text_node(content)
49
50
  return if content.match?(/\A\s*\Z/)
50
51
 
51
- buffer << context.text_node_styles.merge(text: prepare_text(content))
52
+ buffer << context.merged_styles.merge(text: prepare_text(content))
52
53
  context.last_text_node = true
53
54
  nil
54
55
  end
@@ -59,19 +60,20 @@ module PrawnHtml
59
60
 
60
61
  output_content(buffer.dup, context.block_styles)
61
62
  buffer.clear
62
- context.last_margin = 0
63
+ @last_margin = 0
63
64
  end
64
65
 
65
66
  alias_method :flush, :render
66
67
 
67
68
  private
68
69
 
69
- attr_reader :buffer, :context, :pdf
70
+ attr_reader :buffer, :context, :last_margin, :pdf
70
71
 
71
- def setup_element(element)
72
+ def setup_element(element, element_styles:)
72
73
  add_space_if_needed unless render_if_needed(element)
73
- apply_tag_open_styles(element)
74
74
  context.add(element)
75
+ element.process_styles(element_styles: element_styles)
76
+ apply_tag_open_styles(element)
75
77
  element.custom_render(pdf, context) if element.respond_to?(:custom_render)
76
78
  end
77
79
 
@@ -89,14 +91,14 @@ module PrawnHtml
89
91
 
90
92
  def apply_tag_close_styles(element)
91
93
  tag_styles = element.tag_close_styles
92
- context.last_margin = tag_styles[:margin_bottom].to_f
93
- pdf.advance_cursor(context.last_margin + tag_styles[:padding_bottom].to_f)
94
+ @last_margin = tag_styles[:margin_bottom].to_f
95
+ pdf.advance_cursor(last_margin + tag_styles[:padding_bottom].to_f)
94
96
  pdf.start_new_page if tag_styles[:break_after]
95
97
  end
96
98
 
97
99
  def apply_tag_open_styles(element)
98
100
  tag_styles = element.tag_open_styles
99
- move_down = (tag_styles[:margin_top].to_f - context.last_margin) + tag_styles[:padding_top].to_f
101
+ move_down = (tag_styles[:margin_top].to_f - last_margin) + tag_styles[:padding_top].to_f
100
102
  pdf.advance_cursor(move_down) if move_down > 0
101
103
  pdf.start_new_page if tag_styles[:break_before]
102
104
  end
@@ -111,24 +113,41 @@ module PrawnHtml
111
113
  def output_content(buffer, block_styles)
112
114
  apply_callbacks(buffer)
113
115
  left_indent = block_styles[:margin_left].to_f + block_styles[:padding_left].to_f
114
- options = block_styles.slice(:align, :leading, :mode, :padding_left)
115
- options[:indent_paragraphs] = left_indent if left_indent > 0
116
- pdf.puts(buffer, options, bounding_box: bounds(block_styles))
116
+ options = block_styles.slice(:align, :indent_paragraphs, :leading, :mode, :padding_left)
117
+ options[:leading] = adjust_leading(buffer, options[:leading])
118
+ pdf.puts(buffer, options, bounding_box: bounds(buffer, options, block_styles), left_indent: left_indent)
117
119
  end
118
120
 
119
121
  def apply_callbacks(buffer)
120
122
  buffer.select { |item| item[:callback] }.each do |item|
121
- callback = Tag::CALLBACKS[item[:callback]]
122
- item[:callback] = callback.new(pdf, item)
123
+ callback, arg = item[:callback]
124
+ callback_class = Tag::CALLBACKS[callback]
125
+ item[:callback] = callback_class.new(pdf, arg)
123
126
  end
124
127
  end
125
128
 
126
- def bounds(block_styles)
129
+ def adjust_leading(buffer, leading)
130
+ return leading if leading
131
+
132
+ (buffer.map { |item| item[:size] || Context::DEF_FONT_SIZE }.max * 0.055).round(4)
133
+ end
134
+
135
+ def bounds(buffer, options, block_styles)
127
136
  return unless block_styles[:position] == :absolute
128
137
 
129
- y = pdf.bounds.height - (block_styles[:top] || 0)
130
- w = pdf.bounds.width - (block_styles[:left] || 0)
131
- [[block_styles[:left] || 0, y], { width: w }]
138
+ x = if block_styles.include?(:right)
139
+ x1 = pdf.calc_buffer_width(buffer) + block_styles[:right]
140
+ x1 < pdf.page_width ? (pdf.page_width - x1) : 0
141
+ else
142
+ block_styles[:left] || 0
143
+ end
144
+ y = if block_styles.include?(:bottom)
145
+ pdf.calc_buffer_height(buffer, options) + block_styles[:bottom]
146
+ else
147
+ pdf.page_height - (block_styles[:top] || 0)
148
+ end
149
+
150
+ [[x, y], { width: pdf.page_width - x }]
132
151
  end
133
152
  end
134
153
  end
@@ -6,7 +6,7 @@ module PrawnHtml
6
6
  class PdfWrapper
7
7
  extend Forwardable
8
8
 
9
- def_delegators :@pdf, :bounds, :start_new_page
9
+ def_delegators :@pdf, :start_new_page
10
10
 
11
11
  # Wrapper for Prawn PDF Document
12
12
  #
@@ -24,6 +24,46 @@ module PrawnHtml
24
24
  pdf.move_down(move_down)
25
25
  end
26
26
 
27
+ # Calculate the height of a buffer of items
28
+ #
29
+ # @param buffer [Array] Buffer of items
30
+ # @param options [Hash] Output options
31
+ #
32
+ # @return [Float] calculated height
33
+ def calc_buffer_height(buffer, options)
34
+ pdf.height_of_formatted(buffer, options)
35
+ end
36
+
37
+ # Calculate the width of a buffer of items
38
+ #
39
+ # @param buffer [Array] Buffer of items
40
+ #
41
+ # @return [Float] calculated width
42
+ def calc_buffer_width(buffer)
43
+ width = 0
44
+ buffer.each do |item|
45
+ font_family = item[:font] || pdf.font.name
46
+ pdf.font(font_family, size: item[:size] || pdf.font_size) do
47
+ width += pdf.width_of(item[:text], inline_format: true)
48
+ end
49
+ end
50
+ width
51
+ end
52
+
53
+ # Height of the page
54
+ #
55
+ # @return [Float] height
56
+ def page_height
57
+ pdf.bounds.height
58
+ end
59
+
60
+ # Width of the page
61
+ #
62
+ # @return [Float] width
63
+ def page_width
64
+ pdf.bounds.width
65
+ end
66
+
27
67
  # Draw a rectangle
28
68
  #
29
69
  # @param x [Float] left position of the rectangle
@@ -66,12 +106,12 @@ module PrawnHtml
66
106
  # @param buffer [Array] array of text items
67
107
  # @param options [Hash] hash of options
68
108
  # @param bounding_box [Array] bounding box arguments, if bounded
69
- def puts(buffer, options, bounding_box: nil)
70
- return pdf.formatted_text(buffer, options) unless bounding_box
109
+ def puts(buffer, options, bounding_box: nil, left_indent: 0)
110
+ return output_buffer(buffer, options, left_indent: left_indent) unless bounding_box
71
111
 
72
112
  current_y = pdf.cursor
73
113
  pdf.bounding_box(*bounding_box) do
74
- pdf.formatted_text(buffer, options)
114
+ output_buffer(buffer, options, left_indent: left_indent)
75
115
  end
76
116
  pdf.move_cursor_to(current_y)
77
117
  end
@@ -90,5 +130,12 @@ module PrawnHtml
90
130
  private
91
131
 
92
132
  attr_reader :pdf
133
+
134
+ def output_buffer(buffer, options, left_indent:)
135
+ formatted_text = proc { pdf.formatted_text(buffer, options) }
136
+ return formatted_text.call if left_indent == 0
137
+
138
+ pdf.indent(left_indent, 0, &formatted_text)
139
+ end
93
140
  end
94
141
  end
@@ -3,7 +3,7 @@
3
3
  module PrawnHtml
4
4
  class Tag
5
5
  CALLBACKS = {
6
- 'Highlight' => Callbacks::Highlight,
6
+ 'Background' => Callbacks::Background,
7
7
  'StrikeThrough' => Callbacks::StrikeThrough
8
8
  }.freeze
9
9
  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
@@ -15,11 +15,11 @@ module PrawnHtml
15
15
  #
16
16
  # @param tag [Symbol] tag name
17
17
  # @param attributes [Hash] hash of element attributes
18
- # @param element_styles [String] document styles tp apply to the element
19
- def initialize(tag, attributes: {}, element_styles: '')
18
+ # @param options [Hash] options (container width/height/etc.)
19
+ def initialize(tag, attributes: {}, options: {})
20
20
  @tag = tag
21
+ @options = options
21
22
  @attrs = Attributes.new(attributes)
22
- process_styles(element_styles, attributes['style'])
23
23
  end
24
24
 
25
25
  # Is a block tag?
@@ -38,6 +38,15 @@ module PrawnHtml
38
38
  block_styles
39
39
  end
40
40
 
41
+ # Process tag styles
42
+ #
43
+ # @param element_styles [String] extra styles to apply to the element
44
+ def process_styles(element_styles: nil)
45
+ attrs.merge_text_styles!(tag_styles, options: options) if respond_to?(:tag_styles)
46
+ attrs.merge_text_styles!(element_styles, options: options) if element_styles
47
+ attrs.merge_text_styles!(attrs.style, options: options)
48
+ end
49
+
41
50
  # Styles to apply on tag closing
42
51
  #
43
52
  # @return [Hash] hash of styles to apply
@@ -77,10 +86,6 @@ module PrawnHtml
77
86
 
78
87
  private
79
88
 
80
- def process_styles(element_styles, inline_styles)
81
- attrs.merge_text_styles!(tag_styles) if respond_to?(:tag_styles)
82
- attrs.merge_text_styles!(element_styles)
83
- attrs.merge_text_styles!(inline_styles)
84
- end
89
+ attr_reader :options
85
90
  end
86
91
  end
@@ -6,7 +6,13 @@ module PrawnHtml
6
6
  ELEMENTS = [:a].freeze
7
7
 
8
8
  def tag_styles
9
- "href: #{attrs.href}" if attrs.href
9
+ return unless attrs.href
10
+
11
+ <<~STYLES
12
+ color: #00E;
13
+ href: #{attrs.href};
14
+ text-decoration: underline;
15
+ STYLES
10
16
  end
11
17
  end
12
18
  end
@@ -5,9 +5,9 @@ module PrawnHtml
5
5
  class Blockquote < Tag
6
6
  ELEMENTS = [:blockquote].freeze
7
7
 
8
- MARGIN_BOTTOM = 10
9
- MARGIN_LEFT = 25
10
- MARGIN_TOP = 10
8
+ MARGIN_BOTTOM = 12.7
9
+ MARGIN_LEFT = 40.4
10
+ MARGIN_TOP = 12.7
11
11
 
12
12
  def block?
13
13
  true
@@ -4,6 +4,10 @@ module PrawnHtml
4
4
  module Tags
5
5
  class Body < Tag
6
6
  ELEMENTS = [:body].freeze
7
+
8
+ def block?
9
+ true
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -5,14 +5,14 @@ module PrawnHtml
5
5
  class Br < Tag
6
6
  ELEMENTS = [:br].freeze
7
7
 
8
- BR_SPACING = Utils.convert_size('12')
8
+ BR_SPACING = Utils.convert_size('17')
9
9
 
10
10
  def block?
11
11
  true
12
12
  end
13
13
 
14
14
  def custom_render(pdf, context)
15
- return if context.last_text_node
15
+ return if context.last_text_node || context.previous_tag != :br
16
16
 
17
17
  pdf.advance_cursor(BR_SPACING)
18
18
  end
@@ -6,7 +6,7 @@ module PrawnHtml
6
6
  ELEMENTS = [:del, :s].freeze
7
7
 
8
8
  def tag_styles
9
- 'callback: StrikeThrough'
9
+ 'text-decoration: line-through'
10
10
  end
11
11
  end
12
12
  end
@@ -6,30 +6,30 @@ module PrawnHtml
6
6
  ELEMENTS = [:h1, :h2, :h3, :h4, :h5, :h6].freeze
7
7
 
8
8
  MARGINS_TOP = {
9
- h1: 25.5,
9
+ h1: 25,
10
10
  h2: 20.5,
11
- h3: 19,
12
- h4: 20,
11
+ h3: 18,
12
+ h4: 21.2,
13
13
  h5: 21.2,
14
- h6: 23.5
14
+ h6: 22.8
15
15
  }.freeze
16
16
 
17
17
  MARGINS_BOTTOM = {
18
- h1: 18.2,
19
- h2: 17.5,
20
- h3: 17.5,
21
- h4: 22,
22
- h5: 22,
23
- h6: 26.5
18
+ h1: 15.8,
19
+ h2: 15.8,
20
+ h3: 15.8,
21
+ h4: 20,
22
+ h5: 21.4,
23
+ h6: 24.8
24
24
  }.freeze
25
25
 
26
26
  SIZES = {
27
- h1: 31,
28
- h2: 23.5,
29
- h3: 18.2,
30
- h4: 16,
27
+ h1: 31.5,
28
+ h2: 24,
29
+ h3: 18.7,
30
+ h4: 15.7,
31
31
  h5: 13,
32
- h6: 10.5
32
+ h6: 10.8
33
33
  }.freeze
34
34
 
35
35
  def block?
@@ -12,16 +12,17 @@ module PrawnHtml
12
12
  def custom_render(pdf, context)
13
13
  parsed_styles = Attributes.parse_styles(attrs.style)
14
14
  block_styles = context.block_styles
15
- evaluated_styles = evaluate_styles(pdf, block_styles.merge(parsed_styles))
15
+ evaluated_styles = adjust_styles(pdf, block_styles.merge(parsed_styles))
16
16
  pdf.image(@attrs.src, evaluated_styles)
17
17
  end
18
18
 
19
19
  private
20
20
 
21
- def evaluate_styles(pdf, img_styles)
21
+ def adjust_styles(pdf, img_styles)
22
22
  {}.tap do |result|
23
- result[:width] = Utils.convert_size(img_styles['width'], pdf.bounds.width) if img_styles.include?('width')
24
- result[:height] = Utils.convert_size(img_styles['height'], pdf.bounds.height) if img_styles.include?('height')
23
+ w, h = img_styles['width'], img_styles['height']
24
+ result[:width] = Utils.convert_size(w, options: pdf.page_width) if w
25
+ result[:height] = Utils.convert_size(h, options: pdf.page_height) if h
25
26
  result[:position] = img_styles[:align] if %i[left center right].include?(img_styles[:align])
26
27
  end
27
28
  end
@@ -5,6 +5,9 @@ module PrawnHtml
5
5
  class Li < Tag
6
6
  ELEMENTS = [:li].freeze
7
7
 
8
+ INDENT_OL = -12
9
+ INDENT_UL = -6
10
+
8
11
  def block?
9
12
  true
10
13
  end
@@ -13,9 +16,21 @@ module PrawnHtml
13
16
  @counter ? "#{@counter}. " : "#{@symbol} "
14
17
  end
15
18
 
19
+ def block_styles
20
+ super.tap do |bs|
21
+ bs[:indent_paragraphs] = @indent
22
+ end
23
+ end
24
+
16
25
  def on_context_add(_context)
17
- @counter = (parent.counter += 1) if parent.is_a? Ol
18
- @symbol = parent.styles[:list_style_type] || '&bullet;' if parent.is_a? Ul
26
+ case parent.class.to_s
27
+ when 'PrawnHtml::Tags::Ol'
28
+ @indent = INDENT_OL
29
+ @counter = (parent.counter += 1)
30
+ when 'PrawnHtml::Tags::Ul'
31
+ @indent = INDENT_UL
32
+ @symbol = parent.styles[:list_style_type] || '&bullet;'
33
+ end
19
34
  end
20
35
  end
21
36
  end
@@ -6,7 +6,7 @@ module PrawnHtml
6
6
  ELEMENTS = [:mark].freeze
7
7
 
8
8
  def tag_styles
9
- 'callback: Highlight'
9
+ 'background: #ff0'
10
10
  end
11
11
  end
12
12
  end
@@ -5,21 +5,38 @@ module PrawnHtml
5
5
  class Ol < Tag
6
6
  ELEMENTS = [:ol].freeze
7
7
 
8
- MARGIN_LEFT = 25
8
+ MARGIN_TOP = 15
9
+ MARGIN_LEFT = 40
10
+ MARGIN_BOTTOM = 15
9
11
 
10
12
  attr_accessor :counter
11
13
 
12
- def initialize(tag, attributes: {}, element_styles: '')
14
+ def initialize(tag, attributes: {}, options: {})
13
15
  super
14
16
  @counter = 0
17
+ @first_level = false
15
18
  end
16
19
 
17
20
  def block?
18
21
  true
19
22
  end
20
23
 
24
+ def on_context_add(context)
25
+ return if context.map(&:tag).count { |el| el == :ol } > 1
26
+
27
+ @first_level = true
28
+ end
29
+
21
30
  def tag_styles
22
- "margin-left: #{MARGIN_LEFT}px"
31
+ if @first_level
32
+ <<~STYLES
33
+ margin-top: #{MARGIN_TOP}px;
34
+ margin-left: #{MARGIN_LEFT}px;
35
+ margin-bottom: #{MARGIN_BOTTOM}px;
36
+ STYLES
37
+ else
38
+ "margin-left: #{MARGIN_LEFT}px"
39
+ end
23
40
  end
24
41
  end
25
42
  end
@@ -5,8 +5,8 @@ module PrawnHtml
5
5
  class P < Tag
6
6
  ELEMENTS = [:p].freeze
7
7
 
8
- MARGIN_BOTTOM = 6
9
- MARGIN_TOP = 6
8
+ MARGIN_BOTTOM = 12.5
9
+ MARGIN_TOP = 12.5
10
10
 
11
11
  def block?
12
12
  true
@@ -5,14 +5,35 @@ module PrawnHtml
5
5
  class Ul < Tag
6
6
  ELEMENTS = [:ul].freeze
7
7
 
8
- MARGIN_LEFT = 25
8
+ MARGIN_TOP = 15
9
+ MARGIN_LEFT = 40
10
+ MARGIN_BOTTOM = 15
11
+
12
+ def initialize(tag, attributes: {}, options: {})
13
+ super
14
+ @first_level = false
15
+ end
9
16
 
10
17
  def block?
11
18
  true
12
19
  end
13
20
 
21
+ def on_context_add(context)
22
+ return if context.map(&:tag).count { |el| el == :ul } > 1
23
+
24
+ @first_level = true
25
+ end
26
+
14
27
  def tag_styles
15
- "margin-left: #{MARGIN_LEFT}px"
28
+ if @first_level
29
+ <<~STYLES
30
+ margin-top: #{MARGIN_TOP}px;
31
+ margin-left: #{MARGIN_LEFT}px;
32
+ margin-bottom: #{MARGIN_BOTTOM}px;
33
+ STYLES
34
+ else
35
+ "margin-left: #{MARGIN_LEFT}px"
36
+ end
16
37
  end
17
38
  end
18
39
  end
@@ -10,6 +10,24 @@ module PrawnHtml
10
10
  'underline' => :underline
11
11
  }.freeze
12
12
 
13
+ # Setup a background callback
14
+ #
15
+ # @param value [String] HTML string color
16
+ #
17
+ # @return [Array] callback name and argument value
18
+ def callback_background(value, options: nil)
19
+ ['Background', convert_color(value, options: options)]
20
+ end
21
+
22
+ # Setup a strike through callback
23
+ #
24
+ # @param value [String] unused
25
+ #
26
+ # @return [Array] callback name and argument value
27
+ def callback_strike_through(value, options: nil)
28
+ ['StrikeThrough', nil]
29
+ end
30
+
13
31
  # Converts a color string
14
32
  #
15
33
  # Supported formats:
@@ -21,7 +39,7 @@ module PrawnHtml
21
39
  # @param value [String] HTML string color
22
40
  #
23
41
  # @return [String] adjusted string color or nil if value is invalid
24
- def convert_color(value)
42
+ def convert_color(value, options: nil)
25
43
  val = value.to_s.strip.downcase
26
44
  return Regexp.last_match[1] if val.match /\A#([a-f0-9]{6})\Z/ # rubocop:disable Performance/RedundantMatch
27
45
 
@@ -42,7 +60,7 @@ module PrawnHtml
42
60
  # @param value [String] string decimal
43
61
  #
44
62
  # @return [Float] converted and rounded float number
45
- def convert_float(value)
63
+ def convert_float(value, options: nil)
46
64
  val = value&.gsub(/[^0-9.]/, '') || ''
47
65
  val.to_f.round(4)
48
66
  end
@@ -50,14 +68,14 @@ module PrawnHtml
50
68
  # Converts a size string
51
69
  #
52
70
  # @param value [String] size string
53
- # @param container_size [Numeric] container size
71
+ # @param options [Numeric] container size
54
72
  #
55
73
  # @return [Float] converted and rounded size
56
- def convert_size(value, container_size = nil)
74
+ def convert_size(value, options: nil)
57
75
  val = value&.gsub(/[^0-9.]/, '') || ''
58
76
  val =
59
- if container_size && value.include?('%')
60
- val.to_f * container_size * 0.01
77
+ if options && value&.include?('%')
78
+ val.to_f * options * 0.01
61
79
  else
62
80
  val.to_f * PrawnHtml::PX
63
81
  end
@@ -69,7 +87,7 @@ module PrawnHtml
69
87
  # @param value [String] string
70
88
  #
71
89
  # @return [Symbol] symbol
72
- def convert_symbol(value)
90
+ def convert_symbol(value, options: nil)
73
91
  value.to_sym if value && !value.match?(/\A\s*\Z/)
74
92
  end
75
93
 
@@ -78,7 +96,7 @@ module PrawnHtml
78
96
  # @param value
79
97
  #
80
98
  # @return value
81
- def copy_value(value)
99
+ def copy_value(value, options: nil)
82
100
  value
83
101
  end
84
102
 
@@ -97,13 +115,13 @@ module PrawnHtml
97
115
  # @param value [String] string
98
116
  #
99
117
  # @return [String] string without quotes at the beginning/ending
100
- def unquote(value)
118
+ def unquote(value, options: nil)
101
119
  (value&.strip || +'').tap do |val|
102
120
  val.gsub!(/\A['"]|["']\Z/, '')
103
121
  end
104
122
  end
105
123
 
106
- module_function :convert_color, :convert_float, :convert_size, :convert_symbol, :copy_value, :normalize_style,
107
- :unquote
124
+ module_function :callback_background, :callback_strike_through, :convert_color, :convert_float, :convert_size,
125
+ :convert_symbol, :copy_value, :normalize_style, :unquote
108
126
  end
109
127
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PrawnHtml # :nodoc:
4
- VERSION = '0.4.2'
4
+ VERSION = '0.5.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prawn-html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-03 00:00:00.000000000 Z
11
+ date: 2021-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oga
@@ -48,7 +48,7 @@ files:
48
48
  - README.md
49
49
  - lib/prawn-html.rb
50
50
  - lib/prawn_html/attributes.rb
51
- - lib/prawn_html/callbacks/highlight.rb
51
+ - lib/prawn_html/callbacks/background.rb
52
52
  - lib/prawn_html/callbacks/strike_through.rb
53
53
  - lib/prawn_html/context.rb
54
54
  - lib/prawn_html/document_renderer.rb