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.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4dec0bd9a3746705bdaca34d49c8a8eff5700fd8a5feebc3b3452001cd239b0b
|
4
|
+
data.tar.gz: 74b5e31d3056560435ea939f50f713f11c44ad4c1f584873203b910754e1f782
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 814c481a5fce1da43dcb04254ed97f76f234fbdcaa6826070b00594f80cd3b4396c190a2972c0f6f72e00d35e5fd1b534cf22c9ef932b8ee308562de7c6bc854
|
7
|
+
data.tar.gz: f99ce1543d1b28689b19ceddd8e86a73fae8e204bc98270e6a422dd93e44d89ff50366969b67e0fb2a9a4e91d03367981ab5c0f9481b91378df57e2304358f40
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Prawn HTML
|
2
|
-
[![gem version](https://badge.fury.io/rb/prawn-html.svg)](https://
|
2
|
+
[![gem version](https://badge.fury.io/rb/prawn-html.svg)](https://rubygems.org/gems/prawn-html)
|
3
3
|
[![linters](https://github.com/blocknotes/prawn-html/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/prawn-html/actions/workflows/linters.yml)
|
4
4
|
[![specs](https://github.com/blocknotes/prawn-html/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/prawn-html/actions/workflows/specs.yml)
|
5
5
|
|
@@ -8,9 +8,10 @@ HTML to PDF renderer using [Prawn PDF](https://github.com/prawnpdf/prawn).
|
|
8
8
|
Features:
|
9
9
|
- support a [good set](#supported-tags--attributes) of HTML tags and CSS properties;
|
10
10
|
- handle [document styles](#document-styles);
|
11
|
-
-
|
11
|
+
- custom [data attributes](#data-attributes) for Prawn PDF features;
|
12
|
+
- no extra settings: it just parses an input HTML and outputs to a Prawn PDF document.
|
12
13
|
|
13
|
-
**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*.
|
14
15
|
|
15
16
|
> [prawn-styled-text](https://github.com/blocknotes/prawn-styled-text) rewritten from scratch, finally!
|
16
17
|
|
@@ -38,6 +39,7 @@ HTML tags:
|
|
38
39
|
|
39
40
|
- **a**: link
|
40
41
|
- **b**: bold
|
42
|
+
- **blockquote**: block quotation element
|
41
43
|
- **br**: new line
|
42
44
|
- **del**: strike-through
|
43
45
|
- **div**: block element
|
@@ -49,38 +51,57 @@ HTML tags:
|
|
49
51
|
- **img**: image
|
50
52
|
- **li**: list item
|
51
53
|
- **mark**: highlight
|
54
|
+
- **ol**: ordered list
|
52
55
|
- **p**: block element
|
53
56
|
- **s**: strike-through
|
54
57
|
- **small**: smaller text
|
55
58
|
- **span**: inline element
|
56
59
|
- **strong**: bold
|
57
60
|
- **u**: underline
|
58
|
-
- **ul**: list
|
61
|
+
- **ul**: unordered list
|
59
62
|
|
60
63
|
CSS attributes (dimensional units are ignored and considered in pixel):
|
61
64
|
|
62
|
-
- **background**: for *mark* tag
|
63
|
-
- **
|
65
|
+
- **background**: for *mark* tag (3/6 hex digits or RGB or color name), ex. `style="background: #FECD08"`
|
66
|
+
- **break-after**: go to a new page after some elements, ex. `style="break-after: auto"`
|
67
|
+
- **break-before**: go to a new page before some elements, ex. `style="break-before: auto"`
|
68
|
+
- **color**: (3/6 hex digits or RGB or color name) ex. `style="color: #FB1"`
|
64
69
|
- **font-family**: font must be registered, quotes are optional, ex. `style="font-family: Courier"`
|
65
70
|
- **font-size**: ex. `style="font-size: 20px"`
|
66
71
|
- **font-style**: values: *:italic*, ex. `style="font-style: italic"`
|
67
72
|
- **font-weight**: values: *:bold*, ex. `style="font-weight: bold"`
|
68
73
|
- **height**: for *img* tag, ex. `<img src="image.jpg" style="height: 200px"/>`
|
69
74
|
- **href**: for *a* tag, ex. `<a href="http://www.google.com/">Google</a>`
|
75
|
+
- **left**: see *position (absolute)*
|
70
76
|
- **letter-spacing**: ex. `style="letter-spacing: 1.5"`
|
71
77
|
- **line-height**: ex. `style="line-height: 10px"`
|
78
|
+
- **list-style-type**: for *ul*, a string, ex. `style="list-style-type: '- '"`
|
72
79
|
- **margin-bottom**: ex. `style="margin-bottom: 10px"`
|
73
80
|
- **margin-left**: ex. `style="margin-left: 15px"`
|
74
81
|
- **margin-top**: ex. `style="margin-top: 20px"`
|
82
|
+
- **position**: `absolute`, ex. `style="position: absolute; left: 20px; top: 100px"`
|
75
83
|
- **src**: for *img* tag, ex. `<img src="image.jpg"/>`
|
76
84
|
- **text-align**: `left` | `center` | `right` | `justify`, ex. `style="text-align: center"`
|
77
85
|
- **text-decoration**: `underline`, ex. `style="text-decoration: underline"`
|
86
|
+
- **top**: see *position (absolute)*
|
78
87
|
- **width**: for *img* tag, support also percentage, ex. `<img src="image.jpg" style="width: 50%; height: 200px"/>`
|
79
88
|
|
89
|
+
For colors, the supported formats are:
|
90
|
+
- 3 hex digits, ex. `color: #FB1`;
|
91
|
+
- 6 hex digits, ex. `color: #abcdef`;
|
92
|
+
- RGB, ex. `color: RGB(64, 0, 128)`;
|
93
|
+
- color name, ex. `color: yellow`.
|
94
|
+
|
95
|
+
## Data attributes
|
96
|
+
|
97
|
+
Some custom data attributes are used to pass options:
|
98
|
+
|
99
|
+
- **dash**: for *hr* tag, accepts an integer or a list of integers), ex. `data-data="2, 4, 3"`
|
100
|
+
- **mode**: allow to specify the text mode (stroke|fill||fill_stroke), ex. `data-mode="stroke"`
|
101
|
+
|
80
102
|
## Document styles
|
81
103
|
|
82
|
-
|
83
|
-
Only single CSS selectors and basic ones are supported. Example:
|
104
|
+
You can define document CSS rules inside an _head_ tag. Example:
|
84
105
|
|
85
106
|
```html
|
86
107
|
<!DOCTYPE html>
|
@@ -105,6 +126,28 @@ Only single CSS selectors and basic ones are supported. Example:
|
|
105
126
|
</html>
|
106
127
|
```
|
107
128
|
|
129
|
+
## Additional notes
|
130
|
+
|
131
|
+
### Rails: generate PDF on the fly
|
132
|
+
|
133
|
+
Sample controller's action to create a PDF from Rails:
|
134
|
+
|
135
|
+
```rb
|
136
|
+
class SomeController < ApplicationController
|
137
|
+
def sample_action
|
138
|
+
respond_to do |format|
|
139
|
+
format.pdf do
|
140
|
+
pdf = Prawn::Document.new
|
141
|
+
PrawnHtml.append_html(pdf, '<h1 style="text-align: center">Just a test</h1>')
|
142
|
+
send_data(pdf.render, filename: 'sample.pdf', type: 'application/pdf')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
More details in this blogpost: [generate PDF from HTML](https://www.blocknot.es/2021-08-20-rails-generate-pdf-from-html/)
|
150
|
+
|
108
151
|
## Do you like it? Star it!
|
109
152
|
|
110
153
|
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,24 +1,180 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'prawn'
|
4
|
-
|
5
|
-
require 'prawn_html/tags/base'
|
6
|
-
Dir["#{__dir__}/prawn_html/tags/*.rb"].sort.each { |f| require f }
|
7
|
-
|
8
|
-
Dir["#{__dir__}/prawn_html/callbacks/*.rb"].sort.each { |f| require f }
|
9
|
-
|
10
|
-
require 'prawn_html/attributes'
|
11
|
-
require 'prawn_html/context'
|
12
|
-
require 'prawn_html/document_renderer'
|
13
|
-
require 'prawn_html/html_handler'
|
14
|
-
|
15
3
|
module PrawnHtml
|
16
4
|
PX = 0.66 # conversion constant for pixel sixes
|
17
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
|
+
|
18
157
|
def append_html(pdf, html)
|
19
|
-
|
20
|
-
|
158
|
+
pdf_wrapper = PdfWrapper.new(pdf)
|
159
|
+
renderer = DocumentRenderer.new(pdf_wrapper)
|
160
|
+
html_parser = PrawnHtml::HtmlParser.new(renderer)
|
161
|
+
html_parser.process(html)
|
21
162
|
end
|
22
163
|
|
23
164
|
module_function :append_html
|
24
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'
|
@@ -3,124 +3,87 @@
|
|
3
3
|
require 'ostruct'
|
4
4
|
|
5
5
|
module PrawnHtml
|
6
|
-
class Attributes
|
7
|
-
attr_reader :
|
6
|
+
class Attributes < OpenStruct
|
7
|
+
attr_reader :styles
|
8
|
+
|
9
|
+
STYLES_APPLY = {
|
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]
|
14
|
+
}.freeze
|
8
15
|
|
9
16
|
STYLES_LIST = {
|
10
|
-
# styles
|
11
|
-
'background' => { key: :background, set: :convert_color
|
12
|
-
'
|
13
|
-
'
|
14
|
-
'font-
|
15
|
-
'font-
|
16
|
-
'font-
|
17
|
-
'
|
18
|
-
|
19
|
-
'
|
20
|
-
|
21
|
-
'
|
22
|
-
|
23
|
-
|
24
|
-
'
|
25
|
-
'
|
26
|
-
|
27
|
-
'
|
28
|
-
'
|
29
|
-
'
|
17
|
+
# text node styles
|
18
|
+
'background' => { key: :background, set: :convert_color },
|
19
|
+
'callback' => { key: :callback, set: :copy_value },
|
20
|
+
'color' => { key: :color, set: :convert_color },
|
21
|
+
'font-family' => { key: :font, set: :unquote },
|
22
|
+
'font-size' => { key: :size, set: :convert_size },
|
23
|
+
'font-style' => { key: :styles, set: :append_styles },
|
24
|
+
'font-weight' => { key: :styles, set: :append_styles },
|
25
|
+
'href' => { key: :link, set: :copy_value },
|
26
|
+
'letter-spacing' => { key: :character_spacing, set: :convert_float },
|
27
|
+
'list-style-type' => { key: :list_style_type, set: :unquote },
|
28
|
+
'text-decoration' => { key: :styles, set: :append_styles },
|
29
|
+
# tag opening styles
|
30
|
+
'break-before' => { key: :break_before, set: :convert_symbol },
|
31
|
+
'margin-top' => { key: :margin_top, set: :convert_size },
|
32
|
+
'padding-top' => { key: :padding_top, set: :convert_size },
|
33
|
+
# tag closing styles
|
34
|
+
'break-after' => { key: :break_after, set: :convert_symbol },
|
35
|
+
'margin-bottom' => { key: :margin_bottom, set: :convert_size },
|
36
|
+
'padding-bottom' => { key: :padding_bottom, set: :convert_size },
|
37
|
+
# block styles
|
38
|
+
'left' => { key: :left, set: :convert_size },
|
39
|
+
'line-height' => { key: :leading, set: :convert_size },
|
40
|
+
'margin-left' => { key: :margin_left, set: :convert_size },
|
41
|
+
'padding-left' => { key: :padding_left, set: :convert_size },
|
42
|
+
'position' => { key: :position, set: :convert_symbol },
|
43
|
+
'text-align' => { key: :align, set: :convert_symbol },
|
44
|
+
'top' => { key: :top, set: :convert_size }
|
30
45
|
}.freeze
|
31
46
|
|
32
47
|
STYLES_MERGE = %i[margin_left padding_left].freeze
|
33
48
|
|
34
49
|
# Init the Attributes
|
35
|
-
|
36
|
-
|
37
|
-
def initialize(attributes)
|
38
|
-
@hash = ::OpenStruct.new(attributes)
|
39
|
-
@options = {}
|
40
|
-
@post_styles = {}
|
41
|
-
@pre_styles = {}
|
50
|
+
def initialize(attributes = {})
|
51
|
+
super
|
42
52
|
@styles = {} # result styles
|
43
|
-
parsed_styles = Attributes.parse_styles(hash.style)
|
44
|
-
process_styles(parsed_styles)
|
45
53
|
end
|
46
54
|
|
47
|
-
# Processes the
|
55
|
+
# Processes the data attributes
|
48
56
|
#
|
49
|
-
# @
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
apply_rule(rule, value)
|
57
|
+
# @return [Hash] hash of data attributes with 'data-' prefix removed and stripped values
|
58
|
+
def data
|
59
|
+
to_h.each_with_object({}) do |(key, value), res|
|
60
|
+
data_key = key.match /\Adata-(.+)/
|
61
|
+
res[data_key[1]] = value.strip if data_key
|
56
62
|
end
|
57
63
|
end
|
58
64
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
val = value&.downcase || +''
|
67
|
-
val.gsub!(/[^a-f0-9]/, '')
|
68
|
-
return val unless val.size == 3
|
69
|
-
|
70
|
-
a, b, c = val.chars
|
71
|
-
a * 2 + b * 2 + c * 2
|
72
|
-
end
|
73
|
-
|
74
|
-
# Converts a decimal number string
|
75
|
-
#
|
76
|
-
# @param value [String] string decimal
|
77
|
-
#
|
78
|
-
# @return [Float] converted and rounded float number
|
79
|
-
def convert_float(value)
|
80
|
-
val = value&.gsub(/[^0-9.]/, '') || ''
|
81
|
-
val.to_f.round(4)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Converts a size string
|
85
|
-
#
|
86
|
-
# @param value [String] size string
|
87
|
-
# @param container_size [Numeric] container size
|
88
|
-
#
|
89
|
-
# @return [Float] converted and rounded size
|
90
|
-
def convert_size(value, container_size = nil)
|
91
|
-
val = value&.gsub(/[^0-9.]/, '') || ''
|
92
|
-
val =
|
93
|
-
if container_size && value.include?('%')
|
94
|
-
val.to_f * container_size * 0.01
|
95
|
-
else
|
96
|
-
val.to_f * PX
|
97
|
-
end
|
98
|
-
# pdf.bounds.height
|
99
|
-
val.round(4)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Converts a string to symbol
|
103
|
-
#
|
104
|
-
# @param value [String] string
|
105
|
-
#
|
106
|
-
# @return [Symbol] symbol
|
107
|
-
def convert_symbol(value)
|
108
|
-
value.to_sym if value && !value.match?(/\A\s*\Z/)
|
109
|
-
end
|
65
|
+
# Merge text styles
|
66
|
+
#
|
67
|
+
# @param text_styles [String] styles to parse and process
|
68
|
+
def merge_text_styles!(text_styles)
|
69
|
+
hash_styles = Attributes.parse_styles(text_styles)
|
70
|
+
process_styles(hash_styles) unless hash_styles.empty?
|
71
|
+
end
|
110
72
|
|
73
|
+
class << self
|
111
74
|
# Merges attributes
|
112
75
|
#
|
113
|
-
# @param
|
76
|
+
# @param attributes [Hash] target attributes hash
|
114
77
|
# @param key [Symbol] key
|
115
78
|
# @param value
|
116
79
|
#
|
117
80
|
# @return [Hash] the updated hash of attributes
|
118
|
-
def merge_attr!(
|
81
|
+
def merge_attr!(attributes, key, value)
|
119
82
|
return unless key
|
120
|
-
return (
|
83
|
+
return (attributes[key] = value) unless Attributes::STYLES_MERGE.include?(key)
|
121
84
|
|
122
|
-
|
123
|
-
|
85
|
+
attributes[key] ||= 0
|
86
|
+
attributes[key] += value
|
124
87
|
end
|
125
88
|
|
126
89
|
# Parses a string of styles
|
@@ -131,27 +94,25 @@ module PrawnHtml
|
|
131
94
|
def parse_styles(styles)
|
132
95
|
(styles || '').scan(/\s*([^:;]+)\s*:\s*([^;]+)\s*/).to_h
|
133
96
|
end
|
134
|
-
|
135
|
-
# Unquotes a string
|
136
|
-
#
|
137
|
-
# @param value [String] string
|
138
|
-
#
|
139
|
-
# @return [String] string without quotes at the beginning/ending
|
140
|
-
def unquote(value)
|
141
|
-
(value&.strip || +'').tap do |val|
|
142
|
-
val.gsub!(/\A['"]|["']\Z/, '')
|
143
|
-
end
|
144
|
-
end
|
145
97
|
end
|
146
98
|
|
147
99
|
private
|
148
100
|
|
149
|
-
def apply_rule(rule, value)
|
150
|
-
|
151
|
-
|
101
|
+
def apply_rule!(result, rule, value)
|
102
|
+
return unless rule
|
103
|
+
|
104
|
+
if rule[:set] == :append_styles
|
105
|
+
(result[rule[:key]] ||= []) << Utils.normalize_style(value)
|
152
106
|
else
|
153
|
-
|
107
|
+
result[rule[:key]] = Utils.send(rule[:set], value)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def process_styles(hash_styles)
|
112
|
+
hash_styles.each do |key, value|
|
113
|
+
apply_rule!(@styles, STYLES_LIST[key], value)
|
154
114
|
end
|
115
|
+
@styles
|
155
116
|
end
|
156
117
|
end
|
157
118
|
end
|