prawn-html 0.1.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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