prawn-html 0.1.4 → 0.4.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.
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrawnHtml
4
+ class Tag
5
+ CALLBACKS = {
6
+ 'Highlight' => Callbacks::Highlight,
7
+ 'StrikeThrough' => Callbacks::StrikeThrough
8
+ }.freeze
9
+ TAG_CLASSES = %w[A B Blockquote Body Br Del Div H Hr I Img Li Mark Ol P Small Span U Ul].freeze
10
+
11
+ attr_accessor :parent
12
+ attr_reader :attrs, :tag
13
+
14
+ # Init the Tag
15
+ #
16
+ # @param tag [Symbol] tag name
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: '')
20
+ @tag = tag
21
+ @attrs = Attributes.new(attributes)
22
+ process_styles(element_styles, attributes['style'])
23
+ end
24
+
25
+ # Is a block tag?
26
+ #
27
+ # @return [Boolean] true if the type of the tag is block, false otherwise
28
+ def block?
29
+ false
30
+ end
31
+
32
+ # Styles to apply to the block
33
+ #
34
+ # @return [Hash] hash of styles to apply
35
+ def block_styles
36
+ block_styles = styles.slice(*Attributes::STYLES_APPLY[:block])
37
+ block_styles[:mode] = attrs.data['mode'].to_sym if attrs.data.include?('mode')
38
+ block_styles
39
+ end
40
+
41
+ # Styles to apply on tag closing
42
+ #
43
+ # @return [Hash] hash of styles to apply
44
+ def tag_close_styles
45
+ styles.slice(*Attributes::STYLES_APPLY[:tag_close])
46
+ end
47
+
48
+ # Styles hash
49
+ #
50
+ # @return [Hash] hash of styles
51
+ def styles
52
+ attrs.styles
53
+ end
54
+
55
+ # Styles to apply on tag opening
56
+ #
57
+ # @return [Hash] hash of styles to apply
58
+ def tag_open_styles
59
+ styles.slice(*Attributes::STYLES_APPLY[:tag_open])
60
+ end
61
+
62
+ class << self
63
+ # Evaluate the Tag class from a tag name
64
+ #
65
+ # @params tag_name [Symbol] the tag name
66
+ #
67
+ # @return [Tag] the class for the tag if available or nil
68
+ def class_for(tag_name)
69
+ @tag_classes ||= TAG_CLASSES.each_with_object({}) do |tag_class, res|
70
+ klass = const_get("PrawnHtml::Tags::#{tag_class}")
71
+ k = [klass] * klass::ELEMENTS.size
72
+ res.merge!(klass::ELEMENTS.zip(k).to_h)
73
+ end
74
+ @tag_classes[tag_name]
75
+ end
76
+ end
77
+
78
+ private
79
+
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
85
+ end
86
+ end
@@ -1,14 +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
- attrs.hash.href ? super.merge(link: attrs.hash.href) : super
8
+ def tag_styles
9
+ "href: #{attrs.href}" if attrs.href
12
10
  end
13
11
  end
14
12
  end
@@ -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 B < Base
5
+ class B < Tag
8
6
  ELEMENTS = [:b, :strong].freeze
9
7
 
10
- def extra_attrs
11
- {
12
- 'font-weight' => 'bold'
13
- }
8
+ def tag_styles
9
+ 'font-weight: bold'
14
10
  end
15
11
  end
16
12
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrawnHtml
4
+ module Tags
5
+ class Blockquote < Tag
6
+ ELEMENTS = [:blockquote].freeze
7
+
8
+ MARGIN_BOTTOM = 10
9
+ MARGIN_LEFT = 25
10
+ MARGIN_TOP = 10
11
+
12
+ def block?
13
+ true
14
+ end
15
+
16
+ def tag_styles
17
+ <<~STYLES
18
+ margin-bottom: #{MARGIN_BOTTOM}px;
19
+ margin-left: #{MARGIN_LEFT}px;
20
+ margin-top: #{MARGIN_TOP}px;
21
+ STYLES
22
+ end
23
+ end
24
+ end
25
+ 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 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,12 @@
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
+ 'callback: StrikeThrough'
14
10
  end
15
11
  end
16
12
  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,13 +36,13 @@ module PrawnHtml
38
36
  true
39
37
  end
40
38
 
41
- def extra_attrs
42
- @extra_attrs ||= {
43
- 'font-size' => SIZES[tag].to_s,
44
- 'font-weight' => 'bold',
45
- 'margin-bottom' => MARGINS_BOTTOM[tag].to_s,
46
- 'margin-top' => MARGINS_TOP[tag].to_s
47
- }
39
+ def tag_styles
40
+ <<~STYLES
41
+ font-size: #{SIZES[tag]}px;
42
+ font-weight: bold;
43
+ margin-bottom: #{MARGINS_BOTTOM[tag]}px;
44
+ margin-top: #{MARGINS_TOP[tag]}px;
45
+ STYLES
48
46
  end
49
47
  end
50
48
  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 Hr < Base
5
+ class Hr < Tag
8
6
  ELEMENTS = [:hr].freeze
9
7
 
10
8
  MARGIN_BOTTOM = 12
@@ -15,14 +13,26 @@ 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)
18
+ end
19
+
20
+ def tag_styles
21
+ <<~STYLES
22
+ margin-bottom: #{MARGIN_BOTTOM}px;
23
+ margin-top: #{MARGIN_TOP}px;
24
+ STYLES
19
25
  end
20
26
 
21
- def extra_attrs
22
- @extra_attrs ||= {
23
- 'margin-bottom' => MARGIN_BOTTOM.to_s,
24
- 'margin-top' => MARGIN_TOP.to_s,
25
- }
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
26
36
  end
27
37
  end
28
38
  end
@@ -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 I < Base
5
+ class I < Tag
8
6
  ELEMENTS = [:i, :em].freeze
9
7
 
10
- def extra_attrs
11
- {
12
- 'font-style' => 'italic'
13
- }
8
+ def tag_styles
9
+ 'font-style: italic'
14
10
  end
15
11
  end
16
12
  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 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,21 @@
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 before_content
13
+ @counter ? "#{@counter}. " : "#{@symbol} "
14
+ end
15
+
16
+ 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
18
19
  end
19
20
  end
20
21
  end
@@ -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 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
+ 'callback: Highlight'
14
10
  end
15
11
  end
16
12
  end
@@ -0,0 +1,26 @@
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(tag, attributes: {}, element_styles: '')
13
+ super
14
+ @counter = 0
15
+ end
16
+
17
+ def block?
18
+ true
19
+ end
20
+
21
+ def tag_styles
22
+ "margin-left: #{MARGIN_LEFT}px"
23
+ end
24
+ end
25
+ end
26
+ end