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.
@@ -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