prawn-html 0.1.4 → 0.4.0

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