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.
- checksums.yaml +4 -4
- data/README.md +51 -8
- data/lib/prawn-html.rb +170 -14
- data/lib/prawn_html/attributes.rb +71 -110
- data/lib/prawn_html/callbacks/highlight.rb +2 -4
- data/lib/prawn_html/callbacks/strike_through.rb +4 -4
- data/lib/prawn_html/context.rb +29 -12
- data/lib/prawn_html/document_renderer.rb +45 -50
- data/lib/prawn_html/html_parser.rb +95 -0
- data/lib/prawn_html/pdf_wrapper.rb +94 -0
- data/lib/prawn_html/tag.rb +86 -0
- data/lib/prawn_html/tags/a.rb +3 -5
- data/lib/prawn_html/tags/b.rb +3 -7
- data/lib/prawn_html/tags/blockquote.rb +25 -0
- data/lib/prawn_html/tags/body.rb +1 -3
- data/lib/prawn_html/tags/br.rb +3 -6
- data/lib/prawn_html/tags/del.rb +3 -7
- data/lib/prawn_html/tags/div.rb +1 -3
- data/lib/prawn_html/tags/h.rb +8 -10
- data/lib/prawn_html/tags/hr.rb +19 -9
- data/lib/prawn_html/tags/i.rb +3 -7
- data/lib/prawn_html/tags/img.rb +11 -13
- data/lib/prawn_html/tags/li.rb +8 -7
- data/lib/prawn_html/tags/mark.rb +3 -7
- data/lib/prawn_html/tags/ol.rb +26 -0
- data/lib/prawn_html/tags/p.rb +6 -8
- data/lib/prawn_html/tags/small.rb +1 -3
- data/lib/prawn_html/tags/span.rb +1 -3
- data/lib/prawn_html/tags/u.rb +3 -5
- data/lib/prawn_html/tags/ul.rb +3 -7
- data/lib/prawn_html/utils.rb +107 -0
- data/lib/prawn_html/version.rb +1 -1
- metadata +8 -4
- data/lib/prawn_html/html_handler.rb +0 -68
- data/lib/prawn_html/tags/base.rb +0 -54
data/lib/prawn_html/tags/p.rb
CHANGED
@@ -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 <
|
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
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
data/lib/prawn_html/tags/span.rb
CHANGED
data/lib/prawn_html/tags/u.rb
CHANGED
data/lib/prawn_html/tags/ul.rb
CHANGED
@@ -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 <
|
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
|
17
|
-
|
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
|
data/lib/prawn_html/version.rb
CHANGED
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.
|
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-
|
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/
|
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/
|
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
|
data/lib/prawn_html/tags/base.rb
DELETED
@@ -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
|