prawn-html 0.1.0 → 0.3.2

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.
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class A < Base
5
+ class A < Tag
8
6
  ELEMENTS = [:a].freeze
9
7
 
10
- def styles
11
- super.merge(
12
- link: attrs.hash.href
13
- )
8
+ def tag_styles
9
+ attrs.href ? { 'href' => attrs.href } : {}
14
10
  end
15
11
  end
16
12
  end
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class B < Base
5
+ class B < Tag
8
6
  ELEMENTS = [:b, :strong].freeze
9
7
 
10
- def extra_attrs
8
+ def tag_styles
11
9
  {
12
10
  'font-weight' => 'bold'
13
11
  }
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Body < Base
5
+ class Body < Tag
8
6
  ELEMENTS = [:body].freeze
9
7
  end
10
8
  end
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Br < Base
5
+ class Br < Tag
8
6
  ELEMENTS = [:br].freeze
9
7
 
10
- BR_SPACING = 12
8
+ BR_SPACING = Utils.convert_size('12')
11
9
 
12
10
  def block?
13
11
  true
@@ -16,8 +14,7 @@ module PrawnHtml
16
14
  def custom_render(pdf, context)
17
15
  return if context.last_text_node
18
16
 
19
- @spacing ||= Attributes.convert_size(BR_SPACING.to_s)
20
- pdf.move_down(@spacing)
17
+ pdf.advance_cursor(BR_SPACING)
21
18
  end
22
19
  end
23
20
  end
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Del < Base
5
+ class Del < Tag
8
6
  ELEMENTS = [:del, :s].freeze
9
7
 
10
- def styles
11
- super.merge(
12
- callback: Callbacks::StrikeThrough
13
- )
8
+ def tag_styles
9
+ {
10
+ 'callback' => Callbacks::StrikeThrough
11
+ }
14
12
  end
15
13
  end
16
14
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Div < Base
5
+ class Div < Tag
8
6
  ELEMENTS = [:div].freeze
9
7
 
10
8
  def block?
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class H < Base
5
+ class H < Tag
8
6
  ELEMENTS = [:h1, :h2, :h3, :h4, :h5, :h6].freeze
9
7
 
10
8
  MARGINS_TOP = {
@@ -38,8 +36,8 @@ module PrawnHtml
38
36
  true
39
37
  end
40
38
 
41
- def extra_attrs
42
- @extra_attrs ||= {
39
+ def tag_styles
40
+ @tag_styles ||= {
43
41
  'font-size' => SIZES[tag].to_s,
44
42
  'font-weight' => 'bold',
45
43
  'margin-bottom' => MARGINS_BOTTOM[tag].to_s,
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Hr < Base
5
+ class Hr < Tag
8
6
  ELEMENTS = [:hr].freeze
9
7
 
10
8
  MARGIN_BOTTOM = 12
@@ -15,15 +13,27 @@ module PrawnHtml
15
13
  end
16
14
 
17
15
  def custom_render(pdf, _context)
18
- pdf.stroke_horizontal_rule
16
+ dash = attrs.data.include?('dash') ? parse_dash_value(attrs.data['dash']) : nil
17
+ pdf.horizontal_rule(color: attrs.styles[:color], dash: dash)
19
18
  end
20
19
 
21
- def extra_attrs
22
- @extra_attrs ||= {
20
+ def tag_styles
21
+ @tag_styles ||= {
23
22
  'margin-bottom' => MARGIN_BOTTOM.to_s,
24
23
  'margin-top' => MARGIN_TOP.to_s,
25
24
  }
26
25
  end
26
+
27
+ private
28
+
29
+ def parse_dash_value(dash_string)
30
+ if dash_string.match? /\A\d+\Z/
31
+ dash_string.to_i
32
+ else
33
+ dash_array = dash_string.split(',')
34
+ dash_array.map(&:to_i) if dash_array.any?
35
+ end
36
+ end
27
37
  end
28
38
  end
29
39
  end
@@ -1,13 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class I < Base
5
+ class I < Tag
8
6
  ELEMENTS = [:i, :em].freeze
9
7
 
10
- def extra_attrs
8
+ def tag_styles
11
9
  {
12
10
  'font-style' => 'italic'
13
11
  }
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Img < Base
5
+ class Img < Tag
8
6
  ELEMENTS = [:img].freeze
9
7
 
10
8
  def block?
@@ -12,20 +10,20 @@ module PrawnHtml
12
10
  end
13
11
 
14
12
  def custom_render(pdf, context)
15
- styles = Attributes.parse_styles(attrs.hash.style)
16
- context_options = context.merge_options
17
- options = evaluate_styles(pdf, context_options.merge(styles))
18
- pdf.image(@attrs.hash.src, options)
13
+ parsed_styles = Attributes.parse_styles(attrs.style)
14
+ block_styles = context.block_styles
15
+ evaluated_styles = evaluate_styles(pdf, block_styles.merge(parsed_styles))
16
+ pdf.image(@attrs.src, evaluated_styles)
19
17
  end
20
18
 
21
19
  private
22
20
 
23
- def evaluate_styles(pdf, styles)
24
- options = {}
25
- options[:width] = Attributes.convert_size(styles['width'], pdf.bounds.width) if styles.include?('width')
26
- options[:height] = Attributes.convert_size(styles['height'], pdf.bounds.height) if styles.include?('height')
27
- options[:position] = styles[:align] if %i[left center right].include?(styles[:align])
28
- options
21
+ def evaluate_styles(pdf, img_styles)
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')
25
+ result[:position] = img_styles[:align] if %i[left center right].include?(img_styles[:align])
26
+ end
29
27
  end
30
28
  end
31
29
  end
@@ -1,20 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Li < Base
5
+ class Li < Tag
8
6
  ELEMENTS = [:li].freeze
9
7
 
10
8
  def block?
11
9
  true
12
10
  end
13
11
 
14
- def options
15
- super.merge(
16
- before_content: '&bullet; '
17
- )
12
+ def on_context_add(_context)
13
+ @counter = (parent.counter += 1) if parent.is_a? Ol
14
+ @symbol = parent.styles[:list_style_type] || '&bullet;' if parent.is_a? Ul
15
+ end
16
+
17
+ def tag_styles
18
+ {
19
+ before_content: @counter ? "#{@counter}. " : "#{@symbol} "
20
+ }
18
21
  end
19
22
  end
20
23
  end
@@ -1,16 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Mark < Base
5
+ class Mark < Tag
8
6
  ELEMENTS = [:mark].freeze
9
7
 
10
- def styles
11
- super.merge(
12
- callback: Callbacks::Highlight
13
- )
8
+ def tag_styles
9
+ {
10
+ 'callback' => Callbacks::Highlight
11
+ }
14
12
  end
15
13
  end
16
14
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrawnHtml
4
+ module Tags
5
+ class Ol < Tag
6
+ ELEMENTS = [:ol].freeze
7
+
8
+ MARGIN_LEFT = 25
9
+
10
+ attr_accessor :counter
11
+
12
+ def initialize(*_args)
13
+ super
14
+ @counter = 0
15
+ end
16
+
17
+ def block?
18
+ true
19
+ end
20
+
21
+ def tag_styles
22
+ @tag_styles ||= {
23
+ 'margin-left' => MARGIN_LEFT.to_s,
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class P < Base
5
+ class P < Tag
8
6
  ELEMENTS = [:p].freeze
9
7
 
10
8
  MARGIN_BOTTOM = 6
@@ -14,8 +12,8 @@ module PrawnHtml
14
12
  true
15
13
  end
16
14
 
17
- def extra_attrs
18
- @extra_attrs ||= {
15
+ def tag_styles
16
+ @tag_styles ||= {
19
17
  'margin-bottom' => MARGIN_BOTTOM.to_s,
20
18
  'margin-top' => MARGIN_TOP.to_s
21
19
  }
@@ -1,15 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Small < Base
5
+ class Small < Tag
8
6
  ELEMENTS = [:small].freeze
9
7
 
10
8
  def update_styles(styles)
11
9
  size = (styles[:size] || Context::DEF_FONT_SIZE) * 0.85
12
10
  styles[:size] = size
11
+ styles
13
12
  end
14
13
  end
15
14
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Span < Base
5
+ class Span < Tag
8
6
  ELEMENTS = [:span].freeze
9
7
  end
10
8
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module PrawnHtml
4
4
  module Tags
5
- class U < Base
5
+ class U < Tag
6
6
  ELEMENTS = [:ins, :u].freeze
7
7
 
8
- def extra_attrs
8
+ def tag_styles
9
9
  {
10
10
  'text-decoration' => 'underline'
11
11
  }
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module PrawnHtml
6
4
  module Tags
7
- class Ul < Base
5
+ class Ul < Tag
8
6
  ELEMENTS = [:ul].freeze
9
7
 
10
8
  MARGIN_LEFT = 25
@@ -13,8 +11,8 @@ module PrawnHtml
13
11
  true
14
12
  end
15
13
 
16
- def extra_attrs
17
- @extra_attrs ||= {
14
+ def tag_styles
15
+ @tag_styles ||= {
18
16
  'margin-left' => MARGIN_LEFT.to_s,
19
17
  }
20
18
  end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrawnHtml
4
+ module Utils
5
+ # Converts a color string
6
+ #
7
+ # Supported formats:
8
+ # - 3 hex digits, ex. `color: #FB1`;
9
+ # - 6 hex digits, ex. `color: #abcdef`;
10
+ # - RGB, ex. `color: RGB(64, 0, 128)`;
11
+ # - color name, ex. `color: red`.
12
+ #
13
+ # @param value [String] HTML string color
14
+ #
15
+ # @return [String] adjusted string color or nil if value is invalid
16
+ def convert_color(value)
17
+ val = value.to_s.strip.downcase
18
+ return Regexp.last_match[1] if val.match /\A#([a-f0-9]{6})\Z/ # rubocop:disable Performance/RedundantMatch
19
+
20
+ if val.match /\A#([a-f0-9]{3})\Z/ # rubocop:disable Performance/RedundantMatch
21
+ r, g, b = Regexp.last_match[1].chars
22
+ return r * 2 + g * 2 + b * 2
23
+ end
24
+ if val.match /\Argb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\Z/ # rubocop:disable Performance/RedundantMatch
25
+ r, g, b = Regexp.last_match[1..3].map { |v| v.to_i.to_s(16) }
26
+ return "#{r.rjust(2, '0')}#{g.rjust(2, '0')}#{b.rjust(2, '0')}"
27
+ end
28
+
29
+ COLORS[val]
30
+ end
31
+
32
+ # Converts a decimal number string
33
+ #
34
+ # @param value [String] string decimal
35
+ #
36
+ # @return [Float] converted and rounded float number
37
+ def convert_float(value)
38
+ val = value&.gsub(/[^0-9.]/, '') || ''
39
+ val.to_f.round(4)
40
+ end
41
+
42
+ # Converts a size string
43
+ #
44
+ # @param value [String] size string
45
+ # @param container_size [Numeric] container size
46
+ #
47
+ # @return [Float] converted and rounded size
48
+ def convert_size(value, container_size = nil)
49
+ val = value&.gsub(/[^0-9.]/, '') || ''
50
+ val =
51
+ if container_size && value.include?('%')
52
+ val.to_f * container_size * 0.01
53
+ else
54
+ val.to_f * PrawnHtml::PX
55
+ end
56
+ val.round(4)
57
+ end
58
+
59
+ # Converts a string to symbol
60
+ #
61
+ # @param value [String] string
62
+ #
63
+ # @return [Symbol] symbol
64
+ def convert_symbol(value)
65
+ value.to_sym if value && !value.match?(/\A\s*\Z/)
66
+ end
67
+
68
+ # Copy a value without conversion
69
+ #
70
+ # @param value
71
+ #
72
+ # @return value
73
+ def copy_value(value)
74
+ value
75
+ end
76
+
77
+ # Unquotes a string
78
+ #
79
+ # @param value [String] string
80
+ #
81
+ # @return [String] string without quotes at the beginning/ending
82
+ def unquote(value)
83
+ (value&.strip || +'').tap do |val|
84
+ val.gsub!(/\A['"]|["']\Z/, '')
85
+ end
86
+ end
87
+
88
+ module_function :convert_color, :convert_float, :convert_size, :convert_symbol, :copy_value, :unquote
89
+ end
90
+ end