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.
@@ -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,11 +12,11 @@ module PrawnHtml
14
12
  true
15
13
  end
16
14
 
17
- def extra_attrs
18
- @extra_attrs ||= {
19
- 'margin-bottom' => MARGIN_BOTTOM.to_s,
20
- 'margin-top' => MARGIN_TOP.to_s
21
- }
15
+ def tag_styles
16
+ <<~STYLES
17
+ margin-bottom: #{MARGIN_BOTTOM}px;
18
+ margin-top: #{MARGIN_TOP}px;
19
+ STYLES
22
20
  end
23
21
  end
24
22
  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 Small < Base
5
+ class Small < Tag
8
6
  ELEMENTS = [:small].freeze
9
7
 
10
8
  def update_styles(styles)
@@ -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,13 +2,11 @@
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
9
- {
10
- 'text-decoration' => 'underline'
11
- }
8
+ def tag_styles
9
+ 'text-decoration: underline'
12
10
  end
13
11
  end
14
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 Ul < Base
5
+ class Ul < Tag
8
6
  ELEMENTS = [:ul].freeze
9
7
 
10
8
  MARGIN_LEFT = 25
@@ -13,10 +11,8 @@ module PrawnHtml
13
11
  true
14
12
  end
15
13
 
16
- def extra_attrs
17
- @extra_attrs ||= {
18
- 'margin-left' => MARGIN_LEFT.to_s,
19
- }
14
+ def tag_styles
15
+ "margin-left: #{MARGIN_LEFT}px"
20
16
  end
21
17
  end
22
18
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PrawnHtml
4
+ module Utils
5
+ NORMALIZE_STYLES = {
6
+ 'bold' => :bold,
7
+ 'italic' => :italic,
8
+ 'underline' => :underline
9
+ }.freeze
10
+
11
+ # Converts a color string
12
+ #
13
+ # Supported formats:
14
+ # - 3 hex digits, ex. `color: #FB1`;
15
+ # - 6 hex digits, ex. `color: #abcdef`;
16
+ # - RGB, ex. `color: RGB(64, 0, 128)`;
17
+ # - color name, ex. `color: red`.
18
+ #
19
+ # @param value [String] HTML string color
20
+ #
21
+ # @return [String] adjusted string color or nil if value is invalid
22
+ def convert_color(value)
23
+ val = value.to_s.strip.downcase
24
+ return Regexp.last_match[1] if val.match /\A#([a-f0-9]{6})\Z/ # rubocop:disable Performance/RedundantMatch
25
+
26
+ if val.match /\A#([a-f0-9]{3})\Z/ # rubocop:disable Performance/RedundantMatch
27
+ r, g, b = Regexp.last_match[1].chars
28
+ return r * 2 + g * 2 + b * 2
29
+ end
30
+ if val.match /\Argb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\Z/ # rubocop:disable Performance/RedundantMatch
31
+ r, g, b = Regexp.last_match[1..3].map { |v| v.to_i.to_s(16) }
32
+ return "#{r.rjust(2, '0')}#{g.rjust(2, '0')}#{b.rjust(2, '0')}"
33
+ end
34
+
35
+ COLORS[val]
36
+ end
37
+
38
+ # Converts a decimal number string
39
+ #
40
+ # @param value [String] string decimal
41
+ #
42
+ # @return [Float] converted and rounded float number
43
+ def convert_float(value)
44
+ val = value&.gsub(/[^0-9.]/, '') || ''
45
+ val.to_f.round(4)
46
+ end
47
+
48
+ # Converts a size string
49
+ #
50
+ # @param value [String] size string
51
+ # @param container_size [Numeric] container size
52
+ #
53
+ # @return [Float] converted and rounded size
54
+ def convert_size(value, container_size = nil)
55
+ val = value&.gsub(/[^0-9.]/, '') || ''
56
+ val =
57
+ if container_size && value.include?('%')
58
+ val.to_f * container_size * 0.01
59
+ else
60
+ val.to_f * PrawnHtml::PX
61
+ end
62
+ val.round(4)
63
+ end
64
+
65
+ # Converts a string to symbol
66
+ #
67
+ # @param value [String] string
68
+ #
69
+ # @return [Symbol] symbol
70
+ def convert_symbol(value)
71
+ value.to_sym if value && !value.match?(/\A\s*\Z/)
72
+ end
73
+
74
+ # Copy a value without conversion
75
+ #
76
+ # @param value
77
+ #
78
+ # @return value
79
+ def copy_value(value)
80
+ value
81
+ end
82
+
83
+ # Normalize a style value
84
+ #
85
+ # @param value [String] string value
86
+ #
87
+ # @return [Symbol] style value or nil
88
+ def normalize_style(value)
89
+ val = value&.strip&.downcase
90
+ NORMALIZE_STYLES[val]
91
+ end
92
+
93
+ # Unquotes a string
94
+ #
95
+ # @param value [String] string
96
+ #
97
+ # @return [String] string without quotes at the beginning/ending
98
+ def unquote(value)
99
+ (value&.strip || +'').tap do |val|
100
+ val.gsub!(/\A['"]|["']\Z/, '')
101
+ end
102
+ end
103
+
104
+ module_function :convert_color, :convert_float, :convert_size, :convert_symbol, :copy_value, :normalize_style,
105
+ :unquote
106
+ end
107
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PrawnHtml # :nodoc:
4
- VERSION = '0.1.4'
4
+ VERSION = '0.4.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.1.4
4
+ version: 0.4.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-08-13 00:00:00.000000000 Z
11
+ date: 2021-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oga
@@ -52,10 +52,12 @@ files:
52
52
  - lib/prawn_html/callbacks/strike_through.rb
53
53
  - lib/prawn_html/context.rb
54
54
  - lib/prawn_html/document_renderer.rb
55
- - lib/prawn_html/html_handler.rb
55
+ - lib/prawn_html/html_parser.rb
56
+ - lib/prawn_html/pdf_wrapper.rb
57
+ - lib/prawn_html/tag.rb
56
58
  - lib/prawn_html/tags/a.rb
57
59
  - lib/prawn_html/tags/b.rb
58
- - lib/prawn_html/tags/base.rb
60
+ - lib/prawn_html/tags/blockquote.rb
59
61
  - lib/prawn_html/tags/body.rb
60
62
  - lib/prawn_html/tags/br.rb
61
63
  - lib/prawn_html/tags/del.rb
@@ -66,11 +68,13 @@ files:
66
68
  - lib/prawn_html/tags/img.rb
67
69
  - lib/prawn_html/tags/li.rb
68
70
  - lib/prawn_html/tags/mark.rb
71
+ - lib/prawn_html/tags/ol.rb
69
72
  - lib/prawn_html/tags/p.rb
70
73
  - lib/prawn_html/tags/small.rb
71
74
  - lib/prawn_html/tags/span.rb
72
75
  - lib/prawn_html/tags/u.rb
73
76
  - lib/prawn_html/tags/ul.rb
77
+ - lib/prawn_html/utils.rb
74
78
  - lib/prawn_html/version.rb
75
79
  homepage: https://github.com/blocknotes/prawn-html
76
80
  licenses:
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'oga'
4
-
5
- module PrawnHtml
6
- class HtmlHandler
7
- # Init the HtmlHandler
8
- #
9
- # @param pdf [Prawn::Document] Target Prawn PDF document
10
- def initialize(pdf)
11
- @processing = false
12
- @renderer = DocumentRenderer.new(pdf)
13
- end
14
-
15
- # Processes HTML and renders it on the PDF document
16
- #
17
- # @param html [String] The HTML content to process
18
- def process(html)
19
- @processing = !html.include?('<body')
20
- doc = Oga.parse_html(html)
21
- traverse_nodes(doc.children)
22
- renderer.flush
23
- end
24
-
25
- private
26
-
27
- attr_reader :processing, :renderer
28
-
29
- def traverse_nodes(nodes)
30
- nodes.each do |node|
31
- element = node_open(node)
32
- traverse_nodes(node.children) if node.children.any?
33
- node_close(element) if element
34
- end
35
- end
36
-
37
- def node_open(node)
38
- tag = node.is_a?(Oga::XML::Element) && init_element(node)
39
- return unless processing
40
- return renderer.on_text_node(node.text) unless tag
41
-
42
- attributes = prepare_attributes(node)
43
- renderer.on_tag_open(tag, attributes)
44
- end
45
-
46
- def init_element(node)
47
- node.name.downcase.to_sym.tap do |tag_name|
48
- @processing = true if tag_name == :body
49
- renderer.assign_document_styles(extract_styles(node.text)) if tag_name == :style && !@processing
50
- end
51
- end
52
-
53
- def extract_styles(text)
54
- text.scan(/\s*([^{\s]+)\s*{\s*([^}]*?)\s*}/m).to_h
55
- end
56
-
57
- def prepare_attributes(node)
58
- node.attributes.each_with_object({}) do |attr, res|
59
- res[attr.name] = attr.value
60
- end
61
- end
62
-
63
- def node_close(element)
64
- renderer.on_tag_close(element) if @processing
65
- @processing = false if element.tag == :body
66
- end
67
- end
68
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PrawnHtml
4
- module Tags
5
- class Base
6
- attr_reader :attrs, :styles, :tag
7
-
8
- def initialize(tag, attributes = {})
9
- @attrs = Attributes.new(attributes)
10
- @styles = attrs.styles
11
- @tag = tag
12
- attrs.process_styles(extra_attrs) unless extra_attrs.empty?
13
- end
14
-
15
- def apply_doc_styles(document_styles)
16
- selectors = [
17
- tag.to_s,
18
- attrs.hash['class'] ? ".#{attrs.hash['class']}" : nil,
19
- attrs.hash['id'] ? "##{attrs.hash['id']}" : nil
20
- ].compact!
21
- merged_styles = document_styles.each_with_object({}) do |(sel, attributes), res|
22
- res.merge!(attributes) if selectors.include?(sel)
23
- end
24
- @styles = merged_styles.merge(styles)
25
- end
26
-
27
- def block?
28
- false
29
- end
30
-
31
- def extra_attrs
32
- {}
33
- end
34
-
35
- def options
36
- attrs.options
37
- end
38
-
39
- def post_styles
40
- attrs.post_styles
41
- end
42
-
43
- def pre_styles
44
- attrs.pre_styles
45
- end
46
-
47
- class << self
48
- def elements
49
- self::ELEMENTS.each_with_object({}) { |el, list| list[el] = self }
50
- end
51
- end
52
- end
53
- end
54
- end