prawn-html 0.6.0 → 0.6.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b659b809526c4c961782f613e6946613232dd836ac056ca48d3dabebdbf9a02
4
- data.tar.gz: 2549b8b8b872b44f3d6f424236249e7795f97afeadf95299bf06836fb979a13a
3
+ metadata.gz: 4593c000107eaa95af317e336d16e34a7cfcffadef95e736eedaebce1c1723f0
4
+ data.tar.gz: da05881be31d5a4058b41176336d72cd1c1e190a1a1fd59b36f671f6a7e5c98e
5
5
  SHA512:
6
- metadata.gz: b58a21e4424c89db5ff388ab2507ec502ea283ba9e6234d46f3688e477ba21944ee72f813cc9ddb4454426f5e4cc7397531ffa34c74eeb7795a0bbbeaa8d34ed
7
- data.tar.gz: 0e3cfad427968577135c8c8791f698b3c5d6e95463b9364d0630d9caf87407f378c3fb725bfe11349cad210d1d0c3bba1a90555ebb9219c620e674fff0413ff8
6
+ metadata.gz: a8061299f670a1b0f895ac521e4bb6f242125830152bd3eaccb0c33dee3d6aaa1ad2ad179197a2d1ad3cb9aad28fe38aefdc18db1fd55d4148f7870e5b68038a
7
+ data.tar.gz: ab1e8d1c552f6d105ddd9ffbd565b3d1f816857d48649b5dbc89e18495e4257175d0047a7dea1be1974b26ee81e085254c37e9aa84b0da253667a159ea772bda
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Prawn HTML
2
2
  [![gem version](https://badge.fury.io/rb/prawn-html.svg)](https://rubygems.org/gems/prawn-html)
3
+ [![gem downloads](https://badgen.net/rubygems/dt/prawn-html)](https://rubygems.org/gems/prawn-html)
4
+ [![maintainability](https://api.codeclimate.com/v1/badges/db674db00817d56ca1e9/maintainability)](https://codeclimate.com/github/blocknotes/prawn-html/maintainability)
3
5
  [![linters](https://github.com/blocknotes/prawn-html/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/prawn-html/actions/workflows/linters.yml)
4
6
  [![specs](https://github.com/blocknotes/prawn-html/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/prawn-html/actions/workflows/specs.yml)
5
7
 
@@ -35,34 +37,34 @@ To check some examples with the PDF output see [examples](examples/) folder.
35
37
 
36
38
  ## Supported tags & attributes
37
39
 
38
- HTML tags:
39
-
40
- - **a**: link
41
- - **b**: bold
42
- - **blockquote**: block quotation element
43
- - **br**: new line
44
- - **code**: inline code element
45
- - **del**: strike-through
46
- - **div**: block element
47
- - **em**: italic
48
- - **h1** - **h6**: headings
49
- - **hr**: horizontal line
50
- - **i**: italic
51
- - **ins**: underline
52
- - **img**: image
53
- - **li**: list item
54
- - **mark**: highlight
55
- - **ol**: ordered list
56
- - **p**: block element
57
- - **pre**: preformatted text element
58
- - **s**: strike-through
59
- - **small**: smaller text
60
- - **span**: inline element
61
- - **strong**: bold
62
- - **sub**: subscript element
63
- - **sup**: superscript element
64
- - **u**: underline
65
- - **ul**: unordered list
40
+ HTML tags (using MDN definitions):
41
+
42
+ - **a**: the Anchor element
43
+ - **b**: the Bring Attention To element
44
+ - **blockquote**: the Block Quotation element
45
+ - **br**: the Line Break element
46
+ - **code**: the Inline Code element
47
+ - **del**: the Deleted Text element
48
+ - **div**: the Content Division element
49
+ - **em**: the Emphasis element
50
+ - **h1** - **h6**: the HTML Section Heading elements
51
+ - **hr**: the Thematic Break (Horizontal Rule) element
52
+ - **i**: the Idiomatic Text element
53
+ - **ins**: the added text element
54
+ - **img**: the Image Embed element
55
+ - **li**: the list item element
56
+ - **mark**: the Mark Text element
57
+ - **ol**: the Ordered List element
58
+ - **p**: the Paragraph element
59
+ - **pre**: the Preformatted Text element
60
+ - **s**: the strike-through text element
61
+ - **small**: the side comment element
62
+ - **span**: the generic inline element
63
+ - **strong**: the Strong Importance element
64
+ - **sub**: the Subscript element
65
+ - **sup**: the Superscript element
66
+ - **u**: the Unarticulated Annotation (Underline) element
67
+ - **ul**: the Unordered List element
66
68
 
67
69
  CSS attributes (dimensional units are ignored and considered in pixel):
68
70
 
data/lib/prawn-html.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PrawnHtml
4
+ ADJUST_LEADING = { nil => 0.18, 'Courier' => -0.07, 'Helvetica' => -0.17, 'Times-Roman' => 0.03 }.freeze
4
5
  PX = 0.6 # conversion constant for pixel sixes
5
6
 
6
7
  COLORS = {
@@ -154,7 +154,7 @@ module PrawnHtml
154
154
  return (@initial << rule) if value == 'initial'
155
155
 
156
156
  if rule[:set] == :append_styles
157
- val = Utils.normalize_style(value)
157
+ val = Utils.normalize_style(value, rule[:values])
158
158
  (merged_styles[rule[:key]] ||= []) << val if val
159
159
  else
160
160
  opts = rule[:options] ? options[rule[:options]] : nil
@@ -62,15 +62,28 @@ module PrawnHtml
62
62
  end
63
63
  end
64
64
 
65
+ # :nocov:
66
+ def inspect
67
+ map(&:class).map(&:to_s).join(', ')
68
+ end
69
+ # :nocov:
70
+
65
71
  # Remove the last element from the context
66
72
  def remove_last
67
73
  last.on_context_remove(self) if last.respond_to?(:on_context_remove)
68
74
  @merged_styles = nil
69
75
  @last_text_node = false
70
- @previous_tag = last.tag
76
+ @previous_tag = last
71
77
  pop
72
78
  end
73
79
 
80
+ # White space is equal to 'pre'?
81
+ #
82
+ # @return [boolean] white space property of the last element is equal to 'pre'
83
+ def white_space_pre?
84
+ last && last.styles[:white_space] == :pre
85
+ end
86
+
74
87
  private
75
88
 
76
89
  def evaluate_element_styles(element, res)
@@ -9,9 +9,12 @@ module PrawnHtml
9
9
  #
10
10
  # @param pdf [PdfWrapper] target PDF wrapper
11
11
  def initialize(pdf)
12
+ @before_content = []
12
13
  @buffer = []
13
14
  @context = Context.new
14
15
  @last_margin = 0
16
+ @last_text = ''
17
+ @last_tag_open = false
15
18
  @pdf = pdf
16
19
  end
17
20
 
@@ -22,6 +25,8 @@ module PrawnHtml
22
25
  render_if_needed(element)
23
26
  apply_tag_close_styles(element)
24
27
  context.remove_last
28
+ @last_tag_open = false
29
+ @last_text = ''
25
30
  end
26
31
 
27
32
  # On tag open callback
@@ -38,6 +43,8 @@ module PrawnHtml
38
43
  options = { width: pdf.page_width, height: pdf.page_height }
39
44
  tag_class.new(tag_name, attributes: attributes, options: options).tap do |element|
40
45
  setup_element(element, element_styles: element_styles)
46
+ @before_content.push(element.before_content) if element.respond_to?(:before_content)
47
+ @last_tag_open = true
41
48
  end
42
49
  end
43
50
 
@@ -47,9 +54,10 @@ module PrawnHtml
47
54
  #
48
55
  # @return [NilClass] nil value (=> no element)
49
56
  def on_text_node(content)
50
- return if content.match?(/\A\s*\Z/)
57
+ return if context.previous_tag&.block? && content.match?(/\A\s*\Z/)
51
58
 
52
- buffer << context.merged_styles.merge(text: prepare_text(content))
59
+ text = prepare_text(content)
60
+ buffer << context.merged_styles.merge(text: text) unless text.empty?
53
61
  context.last_text_node = true
54
62
  nil
55
63
  end
@@ -70,17 +78,13 @@ module PrawnHtml
70
78
  attr_reader :buffer, :context, :last_margin, :pdf
71
79
 
72
80
  def setup_element(element, element_styles:)
73
- add_space_if_needed unless render_if_needed(element)
81
+ render_if_needed(element)
74
82
  context.add(element)
75
83
  element.process_styles(element_styles: element_styles)
76
84
  apply_tag_open_styles(element)
77
85
  element.custom_render(pdf, context) if element.respond_to?(:custom_render)
78
86
  end
79
87
 
80
- def add_space_if_needed
81
- buffer << SPACE if buffer.any? && !context.last_text_node && ![NEW_LINE, SPACE].include?(buffer.last)
82
- end
83
-
84
88
  def render_if_needed(element)
85
89
  render_needed = element&.block? && buffer.any? && buffer.last != NEW_LINE
86
90
  return false unless render_needed
@@ -104,10 +108,14 @@ module PrawnHtml
104
108
  end
105
109
 
106
110
  def prepare_text(content)
107
- white_space_pre = context.last && context.last.styles[:white_space] == :pre
108
- text = ::Oga::HTML::Entities.decode(context.before_content)
109
- text += white_space_pre ? content : content.gsub(/\A\s*\n\s*|\s*\n\s*\Z/, '').delete("\n").squeeze(' ')
110
- text
111
+ text = @before_content.any? ? ::Oga::HTML::Entities.decode(@before_content.join) : ''
112
+ @before_content.clear
113
+
114
+ return (@last_text = text + content) if context.white_space_pre?
115
+
116
+ content = content.lstrip if @last_text[-1] == ' ' || @last_tag_open
117
+ text += content.tr("\n", ' ').squeeze(' ')
118
+ @last_text = text
111
119
  end
112
120
 
113
121
  def output_content(buffer, block_styles)
@@ -129,7 +137,10 @@ module PrawnHtml
129
137
  def adjust_leading(buffer, leading)
130
138
  return leading if leading
131
139
 
132
- (buffer.map { |item| item[:size] || Context::DEFAULT_STYLES[:size] }.max * 0.055).round(4)
140
+ leadings = buffer.map do |item|
141
+ (item[:size] || Context::DEFAULT_STYLES[:size]) * (ADJUST_LEADING[item[:font]] || ADJUST_LEADING[nil])
142
+ end
143
+ leadings.max.round(4)
133
144
  end
134
145
 
135
146
  def bounds(buffer, options, block_styles)
@@ -12,7 +12,7 @@ module PrawnHtml
12
12
  end
13
13
 
14
14
  def custom_render(pdf, context)
15
- return if context.last_text_node || context.previous_tag != :br
15
+ return if context.last_text_node || !context.previous_tag.is_a?(Br)
16
16
 
17
17
  pdf.advance_cursor(BR_SPACING)
18
18
  end
@@ -13,7 +13,9 @@ module PrawnHtml
13
13
  end
14
14
 
15
15
  def before_content
16
- @counter ? "#{@counter}. " : "#{@symbol} "
16
+ return if @before_content_once
17
+
18
+ @before_content_once = @counter ? "#{@counter}. " : "#{@symbol} "
17
19
  end
18
20
 
19
21
  def block_styles
@@ -45,7 +45,7 @@ module PrawnHtml
45
45
 
46
46
  if val.match /\A#([a-f0-9]{3})\Z/ # rubocop:disable Performance/RedundantMatch
47
47
  r, g, b = Regexp.last_match[1].chars
48
- return r * 2 + g * 2 + b * 2
48
+ return (r * 2) + (g * 2) + (b * 2)
49
49
  end
50
50
  if val.match /\Argb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\Z/ # rubocop:disable Performance/RedundantMatch
51
51
  r, g, b = Regexp.last_match[1..3].map { |v| v.to_i.to_s(16) }
@@ -103,11 +103,13 @@ module PrawnHtml
103
103
  # Normalize a style value
104
104
  #
105
105
  # @param value [String] string value
106
+ # @param accepted_values [Array] allowlist of valid values (symbols)
106
107
  #
107
108
  # @return [Symbol] style value or nil
108
- def normalize_style(value)
109
+ def normalize_style(value, accepted_values)
109
110
  val = value&.strip&.downcase
110
- NORMALIZE_STYLES[val]
111
+ ret = NORMALIZE_STYLES[val]
112
+ accepted_values.include?(ret) ? ret : nil
111
113
  end
112
114
 
113
115
  # Unquotes a string
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PrawnHtml # :nodoc:
4
- VERSION = '0.6.0'
4
+ VERSION = '0.6.5'
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.6.0
4
+ version: 0.6.5
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-09-14 00:00:00.000000000 Z
11
+ date: 2022-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oga
@@ -83,7 +83,10 @@ files:
83
83
  homepage: https://github.com/blocknotes/prawn-html
84
84
  licenses:
85
85
  - MIT
86
- metadata: {}
86
+ metadata:
87
+ homepage_uri: https://github.com/blocknotes/prawn-html
88
+ source_code_uri: https://github.com/blocknotes/prawn-html
89
+ rubygems_mfa_required: 'true'
87
90
  post_install_message:
88
91
  rdoc_options: []
89
92
  require_paths:
@@ -99,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
102
  - !ruby/object:Gem::Version
100
103
  version: '0'
101
104
  requirements: []
102
- rubygems_version: 3.1.4
105
+ rubygems_version: 3.1.6
103
106
  signing_key:
104
107
  specification_version: 4
105
108
  summary: Prawn PDF - HTML renderer