prawn-html 0.2.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +45 -6
- data/lib/prawn-html.rb +170 -15
- data/lib/prawn_html/attributes.rb +33 -101
- 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 +16 -3
- data/lib/prawn_html/document_renderer.rb +39 -27
- data/lib/prawn_html/html_parser.rb +95 -0
- data/lib/prawn_html/pdf_wrapper.rb +94 -0
- data/lib/prawn_html/tag.rb +13 -22
- data/lib/prawn_html/tags/a.rb +1 -1
- data/lib/prawn_html/tags/b.rb +1 -3
- data/lib/prawn_html/tags/blockquote.rb +25 -0
- data/lib/prawn_html/tags/br.rb +2 -3
- data/lib/prawn_html/tags/code.rb +13 -0
- data/lib/prawn_html/tags/del.rb +1 -3
- data/lib/prawn_html/tags/h.rb +6 -6
- data/lib/prawn_html/tags/hr.rb +6 -8
- data/lib/prawn_html/tags/i.rb +1 -3
- data/lib/prawn_html/tags/img.rb +7 -7
- data/lib/prawn_html/tags/li.rb +7 -4
- data/lib/prawn_html/tags/mark.rb +1 -3
- data/lib/prawn_html/tags/ol.rb +26 -0
- data/lib/prawn_html/tags/p.rb +4 -4
- data/lib/prawn_html/tags/pre.rb +25 -0
- data/lib/prawn_html/tags/sub.rb +13 -0
- data/lib/prawn_html/tags/sup.rb +13 -0
- data/lib/prawn_html/tags/u.rb +1 -3
- data/lib/prawn_html/tags/ul.rb +1 -3
- data/lib/prawn_html/utils.rb +109 -0
- data/lib/prawn_html/version.rb +1 -1
- metadata +11 -3
- data/lib/prawn_html/html_handler.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3eec6595a60748790725f32e92e7b749d92086e5331d8a572d287a3a90f9d83a
|
4
|
+
data.tar.gz: 89bcbe740f84c4ecdea2877e96d0f677a25bf424325b41fa40caf3d1351fba96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b34f31b07aaac30910fd1bcb2118b9cbe92bbdaf4ac80850520887e7c3803a6bb1217764551baeeb1a88d695d7b26c4885a4d3065bbd1f20527d37a5723c7bf
|
7
|
+
data.tar.gz: 6ed594bd070e4e4cf20519c28094f7d57eeb779f60c4867f380aab22946d20401bac307e17db47c0560b2cf1cdc591d80e07c3ff54999db92bd3040e19cc18d7
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Features:
|
|
11
11
|
- custom [data attributes](#data-attributes) for Prawn PDF features;
|
12
12
|
- no extra settings: it just parses an input HTML and outputs to a Prawn PDF document.
|
13
13
|
|
14
|
-
**Notice**: render HTML documents properly is not an easy task, this gem support only some HTML tags and a small set of CSS attributes. If you need more rendering accuracy take a look at other projects like WickedPDF
|
14
|
+
**Notice**: render HTML documents properly is not an easy task, this gem support only some HTML tags and a small set of CSS attributes. If you need more rendering accuracy take a look at other projects like *WickedPDF* or *PDFKit*.
|
15
15
|
|
16
16
|
> [prawn-styled-text](https://github.com/blocknotes/prawn-styled-text) rewritten from scratch, finally!
|
17
17
|
|
@@ -39,7 +39,9 @@ HTML tags:
|
|
39
39
|
|
40
40
|
- **a**: link
|
41
41
|
- **b**: bold
|
42
|
+
- **blockquote**: block quotation element
|
42
43
|
- **br**: new line
|
44
|
+
- **code**: inline code element
|
43
45
|
- **del**: strike-through
|
44
46
|
- **div**: block element
|
45
47
|
- **em**: italic
|
@@ -50,34 +52,50 @@ HTML tags:
|
|
50
52
|
- **img**: image
|
51
53
|
- **li**: list item
|
52
54
|
- **mark**: highlight
|
55
|
+
- **ol**: ordered list
|
53
56
|
- **p**: block element
|
57
|
+
- **pre**: preformatted text element
|
54
58
|
- **s**: strike-through
|
55
59
|
- **small**: smaller text
|
56
60
|
- **span**: inline element
|
57
61
|
- **strong**: bold
|
62
|
+
- **sub**: subscript element
|
63
|
+
- **sup**: superscript element
|
58
64
|
- **u**: underline
|
59
|
-
- **ul**: list
|
65
|
+
- **ul**: unordered list
|
60
66
|
|
61
67
|
CSS attributes (dimensional units are ignored and considered in pixel):
|
62
68
|
|
63
|
-
- **background**: for *mark* tag
|
64
|
-
- **
|
69
|
+
- **background**: for *mark* tag (3/6 hex digits or RGB or color name), ex. `style="background: #FECD08"`
|
70
|
+
- **break-after**: go to a new page after some elements, ex. `style="break-after: auto"`
|
71
|
+
- **break-before**: go to a new page before some elements, ex. `style="break-before: auto"`
|
72
|
+
- **color**: (3/6 hex digits or RGB or color name) ex. `style="color: #FB1"`
|
65
73
|
- **font-family**: font must be registered, quotes are optional, ex. `style="font-family: Courier"`
|
66
74
|
- **font-size**: ex. `style="font-size: 20px"`
|
67
75
|
- **font-style**: values: *:italic*, ex. `style="font-style: italic"`
|
68
76
|
- **font-weight**: values: *:bold*, ex. `style="font-weight: bold"`
|
69
77
|
- **height**: for *img* tag, ex. `<img src="image.jpg" style="height: 200px"/>`
|
70
78
|
- **href**: for *a* tag, ex. `<a href="http://www.google.com/">Google</a>`
|
79
|
+
- **left**: see *position (absolute)*
|
71
80
|
- **letter-spacing**: ex. `style="letter-spacing: 1.5"`
|
72
81
|
- **line-height**: ex. `style="line-height: 10px"`
|
82
|
+
- **list-style-type**: for *ul*, a string, ex. `style="list-style-type: '- '"`
|
73
83
|
- **margin-bottom**: ex. `style="margin-bottom: 10px"`
|
74
84
|
- **margin-left**: ex. `style="margin-left: 15px"`
|
75
85
|
- **margin-top**: ex. `style="margin-top: 20px"`
|
86
|
+
- **position**: `absolute`, ex. `style="position: absolute; left: 20px; top: 100px"`
|
76
87
|
- **src**: for *img* tag, ex. `<img src="image.jpg"/>`
|
77
88
|
- **text-align**: `left` | `center` | `right` | `justify`, ex. `style="text-align: center"`
|
78
89
|
- **text-decoration**: `underline`, ex. `style="text-decoration: underline"`
|
90
|
+
- **top**: see *position (absolute)*
|
79
91
|
- **width**: for *img* tag, support also percentage, ex. `<img src="image.jpg" style="width: 50%; height: 200px"/>`
|
80
92
|
|
93
|
+
For colors, the supported formats are:
|
94
|
+
- 3 hex digits, ex. `color: #FB1`;
|
95
|
+
- 6 hex digits, ex. `color: #abcdef`;
|
96
|
+
- RGB, ex. `color: RGB(64, 0, 128)`;
|
97
|
+
- color name, ex. `color: yellow`.
|
98
|
+
|
81
99
|
## Data attributes
|
82
100
|
|
83
101
|
Some custom data attributes are used to pass options:
|
@@ -87,8 +105,7 @@ Some custom data attributes are used to pass options:
|
|
87
105
|
|
88
106
|
## Document styles
|
89
107
|
|
90
|
-
|
91
|
-
Only single CSS selectors and basic ones are supported. Example:
|
108
|
+
You can define document CSS rules inside an _head_ tag. Example:
|
92
109
|
|
93
110
|
```html
|
94
111
|
<!DOCTYPE html>
|
@@ -113,6 +130,28 @@ Only single CSS selectors and basic ones are supported. Example:
|
|
113
130
|
</html>
|
114
131
|
```
|
115
132
|
|
133
|
+
## Additional notes
|
134
|
+
|
135
|
+
### Rails: generate PDF on the fly
|
136
|
+
|
137
|
+
Sample controller's action to create a PDF from Rails:
|
138
|
+
|
139
|
+
```rb
|
140
|
+
class SomeController < ApplicationController
|
141
|
+
def sample_action
|
142
|
+
respond_to do |format|
|
143
|
+
format.pdf do
|
144
|
+
pdf = Prawn::Document.new
|
145
|
+
PrawnHtml.append_html(pdf, '<h1 style="text-align: center">Just a test</h1>')
|
146
|
+
send_data(pdf.render, filename: 'sample.pdf', type: 'application/pdf')
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
More details in this blogpost: [generate PDF from HTML](https://www.blocknot.es/2021-08-20-rails-generate-pdf-from-html/)
|
154
|
+
|
116
155
|
## Do you like it? Star it!
|
117
156
|
|
118
157
|
If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
|
data/lib/prawn-html.rb
CHANGED
@@ -1,25 +1,180 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'oga'
|
4
|
-
require 'prawn'
|
5
|
-
|
6
|
-
require 'prawn_html/tag'
|
7
|
-
Dir["#{__dir__}/prawn_html/tags/*.rb"].sort.each { |f| require f }
|
8
|
-
|
9
|
-
Dir["#{__dir__}/prawn_html/callbacks/*.rb"].sort.each { |f| require f }
|
10
|
-
|
11
|
-
require 'prawn_html/attributes'
|
12
|
-
require 'prawn_html/context'
|
13
|
-
require 'prawn_html/document_renderer'
|
14
|
-
require 'prawn_html/html_handler'
|
15
|
-
|
16
3
|
module PrawnHtml
|
17
4
|
PX = 0.66 # conversion constant for pixel sixes
|
18
5
|
|
6
|
+
COLORS = {
|
7
|
+
'aliceblue' => 'f0f8ff',
|
8
|
+
'antiquewhite' => 'faebd7',
|
9
|
+
'aqua' => '00ffff',
|
10
|
+
'aquamarine' => '7fffd4',
|
11
|
+
'azure' => 'f0ffff',
|
12
|
+
'beige' => 'f5f5dc',
|
13
|
+
'bisque' => 'ffe4c4',
|
14
|
+
'black' => '000000',
|
15
|
+
'blanchedalmond' => 'ffebcd',
|
16
|
+
'blue' => '0000ff',
|
17
|
+
'blueviolet' => '8a2be2',
|
18
|
+
'brown' => 'a52a2a',
|
19
|
+
'burlywood' => 'deb887',
|
20
|
+
'cadetblue' => '5f9ea0',
|
21
|
+
'chartreuse' => '7fff00',
|
22
|
+
'chocolate' => 'd2691e',
|
23
|
+
'coral' => 'ff7f50',
|
24
|
+
'cornflowerblue' => '6495ed',
|
25
|
+
'cornsilk' => 'fff8dc',
|
26
|
+
'crimson' => 'dc143c',
|
27
|
+
'cyan' => '00ffff',
|
28
|
+
'darkblue' => '00008b',
|
29
|
+
'darkcyan' => '008b8b',
|
30
|
+
'darkgoldenrod' => 'b8860b',
|
31
|
+
'darkgray' => 'a9a9a9',
|
32
|
+
'darkgreen' => '006400',
|
33
|
+
'darkgrey' => 'a9a9a9',
|
34
|
+
'darkkhaki' => 'bdb76b',
|
35
|
+
'darkmagenta' => '8b008b',
|
36
|
+
'darkolivegreen' => '556b2f',
|
37
|
+
'darkorange' => 'ff8c00',
|
38
|
+
'darkorchid' => '9932cc',
|
39
|
+
'darkred' => '8b0000',
|
40
|
+
'darksalmon' => 'e9967a',
|
41
|
+
'darkseagreen' => '8fbc8f',
|
42
|
+
'darkslateblue' => '483d8b',
|
43
|
+
'darkslategray' => '2f4f4f',
|
44
|
+
'darkslategrey' => '2f4f4f',
|
45
|
+
'darkturquoise' => '00ced1',
|
46
|
+
'darkviolet' => '9400d3',
|
47
|
+
'deeppink' => 'ff1493',
|
48
|
+
'deepskyblue' => '00bfff',
|
49
|
+
'dimgray' => '696969',
|
50
|
+
'dimgrey' => '696969',
|
51
|
+
'dodgerblue' => '1e90ff',
|
52
|
+
'firebrick' => 'b22222',
|
53
|
+
'floralwhite' => 'fffaf0',
|
54
|
+
'forestgreen' => '228b22',
|
55
|
+
'fuchsia' => 'ff00ff',
|
56
|
+
'gainsboro' => 'dcdcdc',
|
57
|
+
'ghostwhite' => 'f8f8ff',
|
58
|
+
'gold' => 'ffd700',
|
59
|
+
'goldenrod' => 'daa520',
|
60
|
+
'gray' => '808080',
|
61
|
+
'green' => '008000',
|
62
|
+
'greenyellow' => 'adff2f',
|
63
|
+
'grey' => '808080',
|
64
|
+
'honeydew' => 'f0fff0',
|
65
|
+
'hotpink' => 'ff69b4',
|
66
|
+
'indianred' => 'cd5c5c',
|
67
|
+
'indigo' => '4b0082',
|
68
|
+
'ivory' => 'fffff0',
|
69
|
+
'khaki' => 'f0e68c',
|
70
|
+
'lavender' => 'e6e6fa',
|
71
|
+
'lavenderblush' => 'fff0f5',
|
72
|
+
'lawngreen' => '7cfc00',
|
73
|
+
'lemonchiffon' => 'fffacd',
|
74
|
+
'lightblue' => 'add8e6',
|
75
|
+
'lightcoral' => 'f08080',
|
76
|
+
'lightcyan' => 'e0ffff',
|
77
|
+
'lightgoldenrodyellow' => 'fafad2',
|
78
|
+
'lightgray' => 'd3d3d3',
|
79
|
+
'lightgreen' => '90ee90',
|
80
|
+
'lightgrey' => 'd3d3d3',
|
81
|
+
'lightpink' => 'ffb6c1',
|
82
|
+
'lightsalmon' => 'ffa07a',
|
83
|
+
'lightseagreen' => '20b2aa',
|
84
|
+
'lightskyblue' => '87cefa',
|
85
|
+
'lightslategray' => '778899',
|
86
|
+
'lightslategrey' => '778899',
|
87
|
+
'lightsteelblue' => 'b0c4de',
|
88
|
+
'lightyellow' => 'ffffe0',
|
89
|
+
'lime' => '00ff00',
|
90
|
+
'limegreen' => '32cd32',
|
91
|
+
'linen' => 'faf0e6',
|
92
|
+
'magenta' => 'ff00ff',
|
93
|
+
'maroon' => '800000',
|
94
|
+
'mediumaquamarine' => '66cdaa',
|
95
|
+
'mediumblue' => '0000cd',
|
96
|
+
'mediumorchid' => 'ba55d3',
|
97
|
+
'mediumpurple' => '9370db',
|
98
|
+
'mediumseagreen' => '3cb371',
|
99
|
+
'mediumslateblue' => '7b68ee',
|
100
|
+
'mediumspringgreen' => '00fa9a',
|
101
|
+
'mediumturquoise' => '48d1cc',
|
102
|
+
'mediumvioletred' => 'c71585',
|
103
|
+
'midnightblue' => '191970',
|
104
|
+
'mintcream' => 'f5fffa',
|
105
|
+
'mistyrose' => 'ffe4e1',
|
106
|
+
'moccasin' => 'ffe4b5',
|
107
|
+
'navajowhite' => 'ffdead',
|
108
|
+
'navy' => '000080',
|
109
|
+
'oldlace' => 'fdf5e6',
|
110
|
+
'olive' => '808000',
|
111
|
+
'olivedrab' => '6b8e23',
|
112
|
+
'orange' => 'ffa500',
|
113
|
+
'orangered' => 'ff4500',
|
114
|
+
'orchid' => 'da70d6',
|
115
|
+
'palegoldenrod' => 'eee8aa',
|
116
|
+
'palegreen' => '98fb98',
|
117
|
+
'paleturquoise' => 'afeeee',
|
118
|
+
'palevioletred' => 'db7093',
|
119
|
+
'papayawhip' => 'ffefd5',
|
120
|
+
'peachpuff' => 'ffdab9',
|
121
|
+
'peru' => 'cd853f',
|
122
|
+
'pink' => 'ffc0cb',
|
123
|
+
'plum' => 'dda0dd',
|
124
|
+
'powderblue' => 'b0e0e6',
|
125
|
+
'purple' => '800080',
|
126
|
+
'rebeccapurple' => '663399',
|
127
|
+
'red' => 'ff0000',
|
128
|
+
'rosybrown' => 'bc8f8f',
|
129
|
+
'royalblue' => '4169e1',
|
130
|
+
'saddlebrown' => '8b4513',
|
131
|
+
'salmon' => 'fa8072',
|
132
|
+
'sandybrown' => 'f4a460',
|
133
|
+
'seagreen' => '2e8b57',
|
134
|
+
'seashell' => 'fff5ee',
|
135
|
+
'sienna' => 'a0522d',
|
136
|
+
'silver' => 'c0c0c0',
|
137
|
+
'skyblue' => '87ceeb',
|
138
|
+
'slateblue' => '6a5acd',
|
139
|
+
'slategray' => '708090',
|
140
|
+
'slategrey' => '708090',
|
141
|
+
'snow' => 'fffafa',
|
142
|
+
'springgreen' => '00ff7f',
|
143
|
+
'steelblue' => '4682b4',
|
144
|
+
'tan' => 'd2b48c',
|
145
|
+
'teal' => '008080',
|
146
|
+
'thistle' => 'd8bfd8',
|
147
|
+
'tomato' => 'ff6347',
|
148
|
+
'turquoise' => '40e0d0',
|
149
|
+
'violet' => 'ee82ee',
|
150
|
+
'wheat' => 'f5deb3',
|
151
|
+
'white' => 'ffffff',
|
152
|
+
'whitesmoke' => 'f5f5f5',
|
153
|
+
'yellow' => 'ffff00',
|
154
|
+
'yellowgreen' => '9acd32'
|
155
|
+
}.freeze
|
156
|
+
|
19
157
|
def append_html(pdf, html)
|
20
|
-
|
21
|
-
|
158
|
+
pdf_wrapper = PdfWrapper.new(pdf)
|
159
|
+
renderer = DocumentRenderer.new(pdf_wrapper)
|
160
|
+
html_parser = PrawnHtml::HtmlParser.new(renderer)
|
161
|
+
html_parser.process(html)
|
22
162
|
end
|
23
163
|
|
24
164
|
module_function :append_html
|
25
165
|
end
|
166
|
+
|
167
|
+
require 'prawn'
|
168
|
+
|
169
|
+
require 'prawn_html/utils'
|
170
|
+
|
171
|
+
Dir["#{__dir__}/prawn_html/callbacks/*.rb"].sort.each { |f| require f }
|
172
|
+
|
173
|
+
require 'prawn_html/tag'
|
174
|
+
Dir["#{__dir__}/prawn_html/tags/*.rb"].sort.each { |f| require f }
|
175
|
+
|
176
|
+
require 'prawn_html/attributes'
|
177
|
+
require 'prawn_html/context'
|
178
|
+
require 'prawn_html/pdf_wrapper'
|
179
|
+
require 'prawn_html/document_renderer'
|
180
|
+
require 'prawn_html/html_parser'
|
@@ -7,35 +7,43 @@ module PrawnHtml
|
|
7
7
|
attr_reader :styles
|
8
8
|
|
9
9
|
STYLES_APPLY = {
|
10
|
-
block: %i[align leading margin_left padding_left],
|
11
|
-
tag_close: %i[margin_bottom padding_bottom],
|
12
|
-
tag_open: %i[margin_top padding_top],
|
13
|
-
text_node: %i[background callback character_spacing color font link size styles]
|
10
|
+
block: %i[align leading left margin_left padding_left position top],
|
11
|
+
tag_close: %i[margin_bottom padding_bottom break_after],
|
12
|
+
tag_open: %i[margin_top padding_top break_before],
|
13
|
+
text_node: %i[background callback character_spacing color font link list_style_type size styles white_space]
|
14
14
|
}.freeze
|
15
15
|
|
16
16
|
STYLES_LIST = {
|
17
17
|
# text node styles
|
18
18
|
'background' => { key: :background, set: :convert_color },
|
19
|
-
'callback' => { key: :callback, set: :
|
19
|
+
'callback' => { key: :callback, set: :copy_value },
|
20
20
|
'color' => { key: :color, set: :convert_color },
|
21
21
|
'font-family' => { key: :font, set: :unquote },
|
22
22
|
'font-size' => { key: :size, set: :convert_size },
|
23
|
-
'font-style' => { key: :styles, set: :
|
24
|
-
'font-weight' => { key: :styles, set: :
|
25
|
-
'href' => { key: :link, set: :
|
23
|
+
'font-style' => { key: :styles, set: :append_styles },
|
24
|
+
'font-weight' => { key: :styles, set: :append_styles },
|
25
|
+
'href' => { key: :link, set: :copy_value },
|
26
26
|
'letter-spacing' => { key: :character_spacing, set: :convert_float },
|
27
|
-
'
|
27
|
+
'list-style-type' => { key: :list_style_type, set: :unquote },
|
28
|
+
'text-decoration' => { key: :styles, set: :append_styles },
|
29
|
+
'vertical-align' => { key: :styles, set: :append_styles },
|
30
|
+
'white-space' => { key: :white_space, set: :convert_symbol },
|
28
31
|
# tag opening styles
|
32
|
+
'break-before' => { key: :break_before, set: :convert_symbol },
|
29
33
|
'margin-top' => { key: :margin_top, set: :convert_size },
|
30
34
|
'padding-top' => { key: :padding_top, set: :convert_size },
|
31
35
|
# tag closing styles
|
36
|
+
'break-after' => { key: :break_after, set: :convert_symbol },
|
32
37
|
'margin-bottom' => { key: :margin_bottom, set: :convert_size },
|
33
38
|
'padding-bottom' => { key: :padding_bottom, set: :convert_size },
|
34
39
|
# block styles
|
40
|
+
'left' => { key: :left, set: :convert_size },
|
35
41
|
'line-height' => { key: :leading, set: :convert_size },
|
36
42
|
'margin-left' => { key: :margin_left, set: :convert_size },
|
37
43
|
'padding-left' => { key: :padding_left, set: :convert_size },
|
38
|
-
'
|
44
|
+
'position' => { key: :position, set: :convert_symbol },
|
45
|
+
'text-align' => { key: :align, set: :convert_symbol },
|
46
|
+
'top' => { key: :top, set: :convert_size }
|
39
47
|
}.freeze
|
40
48
|
|
41
49
|
STYLES_MERGE = %i[margin_left padding_left].freeze
|
@@ -44,10 +52,6 @@ module PrawnHtml
|
|
44
52
|
def initialize(attributes = {})
|
45
53
|
super
|
46
54
|
@styles = {} # result styles
|
47
|
-
return unless style
|
48
|
-
|
49
|
-
styles_hash = Attributes.parse_styles(style)
|
50
|
-
process_styles(styles_hash)
|
51
55
|
end
|
52
56
|
|
53
57
|
# Processes the data attributes
|
@@ -60,83 +64,15 @@ module PrawnHtml
|
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
63
|
-
# Merge
|
67
|
+
# Merge text styles
|
64
68
|
#
|
65
|
-
# @param
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
# Processes the styles attributes
|
71
|
-
#
|
72
|
-
# @param styles_hash [Hash] hash of styles attributes
|
73
|
-
def process_styles(styles_hash)
|
74
|
-
styles_hash.each do |key, value|
|
75
|
-
apply_rule!(@styles, STYLES_LIST[key], value)
|
76
|
-
end
|
77
|
-
@styles
|
69
|
+
# @param text_styles [String] styles to parse and process
|
70
|
+
def merge_text_styles!(text_styles)
|
71
|
+
hash_styles = Attributes.parse_styles(text_styles)
|
72
|
+
process_styles(hash_styles) unless hash_styles.empty?
|
78
73
|
end
|
79
74
|
|
80
75
|
class << self
|
81
|
-
# Converts a color string
|
82
|
-
#
|
83
|
-
# @param value [String] HTML string color
|
84
|
-
#
|
85
|
-
# @return [String] adjusted string color
|
86
|
-
def convert_color(value)
|
87
|
-
val = value&.downcase || +''
|
88
|
-
val.gsub!(/[^a-f0-9]/, '')
|
89
|
-
return val unless val.size == 3
|
90
|
-
|
91
|
-
a, b, c = val.chars
|
92
|
-
a * 2 + b * 2 + c * 2
|
93
|
-
end
|
94
|
-
|
95
|
-
# Converts a decimal number string
|
96
|
-
#
|
97
|
-
# @param value [String] string decimal
|
98
|
-
#
|
99
|
-
# @return [Float] converted and rounded float number
|
100
|
-
def convert_float(value)
|
101
|
-
val = value&.gsub(/[^0-9.]/, '') || ''
|
102
|
-
val.to_f.round(4)
|
103
|
-
end
|
104
|
-
|
105
|
-
# Converts a size string
|
106
|
-
#
|
107
|
-
# @param value [String] size string
|
108
|
-
# @param container_size [Numeric] container size
|
109
|
-
#
|
110
|
-
# @return [Float] converted and rounded size
|
111
|
-
def convert_size(value, container_size = nil)
|
112
|
-
val = value&.gsub(/[^0-9.]/, '') || ''
|
113
|
-
val =
|
114
|
-
if container_size && value.include?('%')
|
115
|
-
val.to_f * container_size * 0.01
|
116
|
-
else
|
117
|
-
val.to_f * PX
|
118
|
-
end
|
119
|
-
val.round(4)
|
120
|
-
end
|
121
|
-
|
122
|
-
# Converts a string to symbol
|
123
|
-
#
|
124
|
-
# @param value [String] string
|
125
|
-
#
|
126
|
-
# @return [Symbol] symbol
|
127
|
-
def convert_symbol(value)
|
128
|
-
value.to_sym if value && !value.match?(/\A\s*\Z/)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Copy a value without conversion
|
132
|
-
#
|
133
|
-
# @param value
|
134
|
-
#
|
135
|
-
# @return value
|
136
|
-
def copy(value)
|
137
|
-
value
|
138
|
-
end
|
139
|
-
|
140
76
|
# Merges attributes
|
141
77
|
#
|
142
78
|
# @param attributes [Hash] target attributes hash
|
@@ -160,17 +96,6 @@ module PrawnHtml
|
|
160
96
|
def parse_styles(styles)
|
161
97
|
(styles || '').scan(/\s*([^:;]+)\s*:\s*([^;]+)\s*/).to_h
|
162
98
|
end
|
163
|
-
|
164
|
-
# Unquotes a string
|
165
|
-
#
|
166
|
-
# @param value [String] string
|
167
|
-
#
|
168
|
-
# @return [String] string without quotes at the beginning/ending
|
169
|
-
def unquote(value)
|
170
|
-
(value&.strip || +'').tap do |val|
|
171
|
-
val.gsub!(/\A['"]|["']\Z/, '')
|
172
|
-
end
|
173
|
-
end
|
174
99
|
end
|
175
100
|
|
176
101
|
private
|
@@ -178,11 +103,18 @@ module PrawnHtml
|
|
178
103
|
def apply_rule!(result, rule, value)
|
179
104
|
return unless rule
|
180
105
|
|
181
|
-
if rule[:set] == :
|
182
|
-
(result[rule[:key]] ||= []) <<
|
106
|
+
if rule[:set] == :append_styles
|
107
|
+
(result[rule[:key]] ||= []) << Utils.normalize_style(value)
|
183
108
|
else
|
184
|
-
result[rule[:key]] =
|
109
|
+
result[rule[:key]] = Utils.send(rule[:set], value)
|
185
110
|
end
|
186
111
|
end
|
112
|
+
|
113
|
+
def process_styles(hash_styles)
|
114
|
+
hash_styles.each do |key, value|
|
115
|
+
apply_rule!(@styles, STYLES_LIST[key], value)
|
116
|
+
end
|
117
|
+
@styles
|
118
|
+
end
|
187
119
|
end
|
188
120
|
end
|