wicked_pdf 2.0.2 → 2.8.2
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/.github/workflows/ci.yml +56 -0
- data/.rubocop.yml +57 -1
- data/.rubocop_todo.yml +29 -117
- data/CHANGELOG.md +110 -15
- data/README.md +62 -19
- data/Rakefile +3 -10
- data/gemfiles/5.0.gemfile +2 -2
- data/gemfiles/5.1.gemfile +2 -2
- data/gemfiles/5.2.gemfile +3 -4
- data/gemfiles/6.0.gemfile +3 -4
- data/gemfiles/6.1.gemfile +11 -0
- data/gemfiles/7.0.gemfile +11 -0
- data/generators/wicked_pdf/templates/wicked_pdf.rb +14 -5
- data/lib/wicked_pdf/binary.rb +65 -0
- data/lib/wicked_pdf/option_parser.rb +230 -0
- data/lib/wicked_pdf/pdf_helper.rb +29 -44
- data/lib/wicked_pdf/progress.rb +2 -2
- data/lib/wicked_pdf/railtie.rb +3 -12
- data/lib/wicked_pdf/tempfile.rb +33 -3
- data/lib/wicked_pdf/version.rb +1 -1
- data/lib/wicked_pdf/wicked_pdf_helper/assets.rb +164 -18
- data/lib/wicked_pdf.rb +51 -261
- data/test/fixtures/subdirectory/nested.js +1 -0
- data/test/functional/pdf_helper_test.rb +1 -1
- data/test/functional/wicked_pdf_helper_assets_test.rb +129 -0
- data/test/test_helper.rb +7 -0
- data/test/unit/wicked_pdf_binary_test.rb +26 -0
- data/test/unit/wicked_pdf_option_parser_test.rb +133 -0
- data/test/unit/wicked_pdf_test.rb +16 -156
- data/test/unit/wkhtmltopdf_location_test.rb +0 -2
- data/wicked_pdf.gemspec +5 -5
- metadata +59 -25
- data/.travis.yml +0 -79
- data/gemfiles/4.0.gemfile +0 -7
- data/gemfiles/4.1.gemfile +0 -7
- data/gemfiles/4.2.gemfile +0 -9
- data/gemfiles/rails_edge.gemfile +0 -9
@@ -1,19 +1,99 @@
|
|
1
1
|
require 'net/http'
|
2
|
-
|
3
|
-
require '
|
2
|
+
require 'delegate'
|
3
|
+
require 'stringio'
|
4
4
|
|
5
5
|
class WickedPdf
|
6
6
|
module WickedPdfHelper
|
7
7
|
module Assets
|
8
8
|
ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/
|
9
9
|
|
10
|
+
class MissingAsset < StandardError; end
|
11
|
+
|
12
|
+
class MissingLocalAsset < MissingAsset
|
13
|
+
attr_reader :path
|
14
|
+
|
15
|
+
def initialize(path)
|
16
|
+
@path = path
|
17
|
+
super("Could not find asset '#{path}'")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class MissingRemoteAsset < MissingAsset
|
22
|
+
attr_reader :url, :response
|
23
|
+
|
24
|
+
def initialize(url, response)
|
25
|
+
@url = url
|
26
|
+
@response = response
|
27
|
+
super("Could not fetch asset '#{url}': server responded with #{response.code} #{response.message}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class PropshaftAsset < SimpleDelegator
|
32
|
+
def content_type
|
33
|
+
super.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
content
|
38
|
+
end
|
39
|
+
|
40
|
+
def filename
|
41
|
+
path.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class SprocketsEnvironment
|
46
|
+
def self.instance
|
47
|
+
@instance ||= Sprockets::Railtie.build_environment(Rails.application)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.find_asset(*args)
|
51
|
+
instance.find_asset(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class LocalAsset
|
56
|
+
attr_reader :path
|
57
|
+
|
58
|
+
def initialize(path)
|
59
|
+
@path = path
|
60
|
+
end
|
61
|
+
|
62
|
+
def content_type
|
63
|
+
Mime::Type.lookup_by_extension(File.extname(path).delete('.'))
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
IO.read(path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def filename
|
71
|
+
path.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
10
75
|
def wicked_pdf_asset_base64(path)
|
11
76
|
asset = find_asset(path)
|
12
|
-
raise
|
77
|
+
raise MissingLocalAsset, path if asset.nil?
|
78
|
+
|
13
79
|
base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
|
14
80
|
"data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
|
15
81
|
end
|
16
82
|
|
83
|
+
# Using `image_tag` with URLs when generating PDFs (specifically large PDFs with lots of pages) can cause buffer/stack overflows.
|
84
|
+
#
|
85
|
+
def wicked_pdf_url_base64(url)
|
86
|
+
response = Net::HTTP.get_response(URI(url))
|
87
|
+
|
88
|
+
if response.is_a?(Net::HTTPSuccess)
|
89
|
+
base64 = Base64.encode64(response.body).gsub(/\s+/, '')
|
90
|
+
"data:#{response.content_type};base64,#{Rack::Utils.escape(base64)}"
|
91
|
+
else
|
92
|
+
Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
17
97
|
def wicked_pdf_stylesheet_link_tag(*sources)
|
18
98
|
stylesheet_contents = sources.collect do |source|
|
19
99
|
source = WickedPdfHelper.add_extension(source, 'css')
|
@@ -31,6 +111,7 @@ class WickedPdf
|
|
31
111
|
|
32
112
|
def wicked_pdf_stylesheet_pack_tag(*sources)
|
33
113
|
return unless defined?(Webpacker)
|
114
|
+
|
34
115
|
if running_in_development?
|
35
116
|
stylesheet_pack_tag(*sources)
|
36
117
|
else
|
@@ -79,6 +160,16 @@ class WickedPdf
|
|
79
160
|
end
|
80
161
|
end
|
81
162
|
|
163
|
+
def wicked_pdf_asset_pack_path(asset)
|
164
|
+
return unless defined?(Webpacker)
|
165
|
+
|
166
|
+
if running_in_development?
|
167
|
+
asset_pack_path(asset)
|
168
|
+
else
|
169
|
+
wicked_pdf_asset_path webpacker_source_url(asset)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
82
173
|
private
|
83
174
|
|
84
175
|
# borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
|
@@ -108,8 +199,32 @@ class WickedPdf
|
|
108
199
|
def find_asset(path)
|
109
200
|
if Rails.application.assets.respond_to?(:find_asset)
|
110
201
|
Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
|
202
|
+
elsif defined?(Propshaft::Assembly) && Rails.application.assets.is_a?(Propshaft::Assembly)
|
203
|
+
PropshaftAsset.new(Rails.application.assets.load_path.find(path))
|
204
|
+
elsif Rails.application.respond_to?(:assets_manifest)
|
205
|
+
relative_asset_path = get_asset_path_from_manifest(path)
|
206
|
+
return unless relative_asset_path
|
207
|
+
|
208
|
+
asset_path = File.join(Rails.application.assets_manifest.dir, relative_asset_path)
|
209
|
+
LocalAsset.new(asset_path) if File.file?(asset_path)
|
111
210
|
else
|
112
|
-
|
211
|
+
SprocketsEnvironment.find_asset(path, :base_path => Rails.application.root.to_s)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def get_asset_path_from_manifest(path)
|
216
|
+
assets = Rails.application.assets_manifest.assets
|
217
|
+
|
218
|
+
if File.extname(path).empty?
|
219
|
+
assets.find do |asset, _v|
|
220
|
+
directory = File.dirname(asset)
|
221
|
+
asset_path = File.basename(asset, File.extname(asset))
|
222
|
+
asset_path = File.join(directory, asset_path) if directory != '.'
|
223
|
+
|
224
|
+
asset_path == path
|
225
|
+
end&.last
|
226
|
+
else
|
227
|
+
assets[path]
|
113
228
|
end
|
114
229
|
end
|
115
230
|
|
@@ -133,20 +248,35 @@ class WickedPdf
|
|
133
248
|
end
|
134
249
|
|
135
250
|
def read_asset(source)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
251
|
+
asset = find_asset(source)
|
252
|
+
return asset.to_s.force_encoding('UTF-8') if asset
|
253
|
+
|
254
|
+
unless precompiled_or_absolute_asset?(source)
|
255
|
+
raise MissingLocalAsset, source if WickedPdf.config[:raise_on_missing_assets]
|
256
|
+
|
257
|
+
return
|
258
|
+
end
|
259
|
+
|
260
|
+
pathname = asset_pathname(source)
|
261
|
+
if pathname =~ URI_REGEXP
|
262
|
+
read_from_uri(pathname)
|
263
|
+
elsif File.file?(pathname)
|
264
|
+
IO.read(pathname)
|
265
|
+
elsif WickedPdf.config[:raise_on_missing_assets]
|
266
|
+
raise MissingLocalAsset, pathname if WickedPdf.config[:raise_on_missing_assets]
|
145
267
|
end
|
146
268
|
end
|
147
269
|
|
148
270
|
def read_from_uri(uri)
|
149
|
-
|
271
|
+
response = Net::HTTP.get_response(URI(uri))
|
272
|
+
|
273
|
+
unless response.is_a?(Net::HTTPSuccess)
|
274
|
+
raise MissingRemoteAsset.new(uri, response) if WickedPdf.config[:raise_on_missing_assets]
|
275
|
+
|
276
|
+
return
|
277
|
+
end
|
278
|
+
|
279
|
+
asset = response.body
|
150
280
|
asset.force_encoding('UTF-8') if asset
|
151
281
|
asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
|
152
282
|
asset
|
@@ -161,10 +291,15 @@ class WickedPdf
|
|
161
291
|
end
|
162
292
|
|
163
293
|
def webpacker_source_url(source)
|
164
|
-
return unless
|
294
|
+
return unless webpacker_version
|
295
|
+
|
165
296
|
# In Webpacker 3.2.0 asset_pack_url is introduced
|
166
|
-
if
|
167
|
-
|
297
|
+
if webpacker_version >= '3.2.0'
|
298
|
+
if (host = Rails.application.config.asset_host)
|
299
|
+
asset_pack_path(source, :host => host)
|
300
|
+
else
|
301
|
+
asset_pack_url(source)
|
302
|
+
end
|
168
303
|
else
|
169
304
|
source_path = asset_pack_path(source)
|
170
305
|
# Remove last slash from root path
|
@@ -173,7 +308,8 @@ class WickedPdf
|
|
173
308
|
end
|
174
309
|
|
175
310
|
def running_in_development?
|
176
|
-
return unless
|
311
|
+
return unless webpacker_version
|
312
|
+
|
177
313
|
# :dev_server method was added in webpacker 3.0.0
|
178
314
|
if Webpacker.respond_to?(:dev_server)
|
179
315
|
Webpacker.dev_server.running?
|
@@ -181,6 +317,16 @@ class WickedPdf
|
|
181
317
|
Rails.env.development? || Rails.env.test?
|
182
318
|
end
|
183
319
|
end
|
320
|
+
|
321
|
+
def webpacker_version
|
322
|
+
if defined?(Shakapacker)
|
323
|
+
require 'shakapacker/version'
|
324
|
+
Shakapacker::VERSION
|
325
|
+
elsif defined?(Webpacker)
|
326
|
+
require 'webpacker/version'
|
327
|
+
Webpacker::VERSION
|
328
|
+
end
|
329
|
+
end
|
184
330
|
end
|
185
331
|
end
|
186
332
|
end
|
data/lib/wicked_pdf.rb
CHANGED
@@ -5,33 +5,49 @@ require 'logger'
|
|
5
5
|
require 'digest/md5'
|
6
6
|
require 'rbconfig'
|
7
7
|
require 'open3'
|
8
|
+
require 'ostruct'
|
8
9
|
|
9
10
|
require 'active_support/core_ext/module/attribute_accessors'
|
10
11
|
require 'active_support/core_ext/object/blank'
|
11
12
|
|
12
13
|
require 'wicked_pdf/version'
|
13
14
|
require 'wicked_pdf/railtie'
|
15
|
+
require 'wicked_pdf/option_parser'
|
14
16
|
require 'wicked_pdf/tempfile'
|
17
|
+
require 'wicked_pdf/binary'
|
15
18
|
require 'wicked_pdf/middleware'
|
16
19
|
require 'wicked_pdf/progress'
|
17
20
|
|
18
21
|
class WickedPdf
|
19
22
|
DEFAULT_BINARY_VERSION = Gem::Version.new('0.9.9')
|
20
|
-
BINARY_VERSION_WITHOUT_DASHES = Gem::Version.new('0.12.0')
|
21
|
-
EXE_NAME = 'wkhtmltopdf'.freeze
|
22
23
|
@@config = {}
|
23
|
-
cattr_accessor :config
|
24
|
-
attr_accessor :binary_version
|
24
|
+
cattr_accessor :config, :silence_deprecations
|
25
25
|
|
26
26
|
include Progress
|
27
27
|
|
28
|
+
def self.config=(config)
|
29
|
+
::Kernel.warn 'WickedPdf.config= is deprecated and will be removed in future versions. Use WickedPdf.configure instead.' unless @@silence_deprecations
|
30
|
+
|
31
|
+
@@config = config
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.configure
|
35
|
+
config = OpenStruct.new(@@config)
|
36
|
+
yield config
|
37
|
+
|
38
|
+
@@config.merge! config.to_h
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.clear_config
|
42
|
+
@@config = {}
|
43
|
+
end
|
44
|
+
|
28
45
|
def initialize(wkhtmltopdf_binary_path = nil)
|
29
|
-
@
|
30
|
-
|
31
|
-
raise "Bad #{EXE_NAME}'s path: #{@exe_path}" unless File.exist?(@exe_path)
|
32
|
-
raise "#{EXE_NAME} is not executable" unless File.executable?(@exe_path)
|
46
|
+
@binary = Binary.new(wkhtmltopdf_binary_path, DEFAULT_BINARY_VERSION)
|
47
|
+
end
|
33
48
|
|
34
|
-
|
49
|
+
def binary_version
|
50
|
+
@binary.version
|
35
51
|
end
|
36
52
|
|
37
53
|
def pdf_from_html_file(filepath, options = {})
|
@@ -41,23 +57,24 @@ class WickedPdf
|
|
41
57
|
def pdf_from_string(string, options = {})
|
42
58
|
options = options.dup
|
43
59
|
options.merge!(WickedPdf.config) { |_key, option, _config| option }
|
44
|
-
string_file =
|
45
|
-
string_file.
|
46
|
-
string_file.
|
47
|
-
string_file.close
|
48
|
-
|
49
|
-
pdf = pdf_from_html_file(string_file.path, options)
|
50
|
-
pdf
|
60
|
+
string_file = WickedPdf::Tempfile.new('wicked_pdf.html', options[:temp_path])
|
61
|
+
string_file.write_in_chunks(string)
|
62
|
+
pdf_from_html_file(string_file.path, options)
|
51
63
|
ensure
|
52
|
-
|
64
|
+
if options[:delete_temporary_files] && string_file
|
65
|
+
string_file.close!
|
66
|
+
elsif string_file
|
67
|
+
string_file.close
|
68
|
+
end
|
53
69
|
end
|
54
70
|
|
55
|
-
def pdf_from_url(url, options = {})
|
71
|
+
def pdf_from_url(url, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
|
56
72
|
# merge in global config options
|
57
73
|
options.merge!(WickedPdf.config) { |_key, option, _config| option }
|
58
|
-
generated_pdf_file =
|
59
|
-
command = [@
|
60
|
-
command
|
74
|
+
generated_pdf_file = WickedPdf::Tempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
|
75
|
+
command = [@binary.path]
|
76
|
+
command.unshift(@binary.xvfb_run_path) if options[:use_xvfb]
|
77
|
+
command += option_parser.parse(options)
|
61
78
|
command << url
|
62
79
|
command << generated_pdf_file.path.to_s
|
63
80
|
|
@@ -66,23 +83,24 @@ class WickedPdf
|
|
66
83
|
if track_progress?(options)
|
67
84
|
invoke_with_progress(command, options)
|
68
85
|
else
|
69
|
-
err = Open3.
|
70
|
-
|
71
|
-
end
|
86
|
+
_out, err, status = Open3.capture3(*command)
|
87
|
+
err = [status.to_s, err].join("\n") if !err.empty? || !status.success?
|
72
88
|
end
|
73
89
|
if options[:return_file]
|
74
90
|
return_file = options.delete(:return_file)
|
75
91
|
return generated_pdf_file
|
76
92
|
end
|
77
|
-
|
78
|
-
generated_pdf_file.
|
79
|
-
|
93
|
+
|
94
|
+
pdf = generated_pdf_file.read_in_chunks
|
95
|
+
|
80
96
|
raise "Error generating PDF\n Command Error: #{err}" if options[:raise_on_all_errors] && !err.empty?
|
81
97
|
raise "PDF could not be generated!\n Command Error: #{err}" if pdf && pdf.rstrip.empty?
|
98
|
+
|
82
99
|
pdf
|
83
100
|
rescue StandardError => e
|
84
101
|
raise "Failed to execute:\n#{command}\nError: #{e}"
|
85
102
|
ensure
|
103
|
+
clean_temp_files
|
86
104
|
generated_pdf_file.close! if generated_pdf_file && !return_file
|
87
105
|
end
|
88
106
|
|
@@ -90,6 +108,7 @@ class WickedPdf
|
|
90
108
|
|
91
109
|
def in_development_mode?
|
92
110
|
return Rails.env == 'development' if defined?(Rails.env)
|
111
|
+
|
93
112
|
RAILS_ENV == 'development' if defined?(RAILS_ENV)
|
94
113
|
end
|
95
114
|
|
@@ -101,242 +120,13 @@ class WickedPdf
|
|
101
120
|
Rails.logger.debug '[wicked_pdf]: ' + cmd
|
102
121
|
end
|
103
122
|
|
104
|
-
def
|
105
|
-
|
106
|
-
@binary_version = parse_version(stdout.gets(nil))
|
107
|
-
rescue StandardError
|
108
|
-
DEFAULT_BINARY_VERSION
|
109
|
-
end
|
110
|
-
|
111
|
-
def parse_version(version_info)
|
112
|
-
match_data = /wkhtmltopdf\s*(\d*\.\d*\.\d*\w*)/.match(version_info)
|
113
|
-
if match_data && (match_data.length == 2)
|
114
|
-
Gem::Version.new(match_data[1])
|
115
|
-
else
|
116
|
-
DEFAULT_BINARY_VERSION
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def parse_options(options)
|
121
|
-
[
|
122
|
-
parse_extra(options),
|
123
|
-
parse_others(options),
|
124
|
-
parse_global(options),
|
125
|
-
parse_outline(options.delete(:outline)),
|
126
|
-
parse_header_footer(:header => options.delete(:header),
|
127
|
-
:footer => options.delete(:footer),
|
128
|
-
:layout => options[:layout]),
|
129
|
-
parse_cover(options.delete(:cover)),
|
130
|
-
parse_toc(options.delete(:toc)),
|
131
|
-
parse_basic_auth(options)
|
132
|
-
].flatten
|
133
|
-
end
|
134
|
-
|
135
|
-
def parse_extra(options)
|
136
|
-
return [] if options[:extra].nil?
|
137
|
-
return options[:extra].split if options[:extra].respond_to?(:split)
|
138
|
-
options[:extra]
|
139
|
-
end
|
140
|
-
|
141
|
-
def parse_basic_auth(options)
|
142
|
-
if options[:basic_auth]
|
143
|
-
user, passwd = Base64.decode64(options[:basic_auth]).split(':')
|
144
|
-
['--username', user, '--password', passwd]
|
145
|
-
else
|
146
|
-
[]
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def make_option(name, value, type = :string)
|
151
|
-
if value.is_a?(Array)
|
152
|
-
return value.collect { |v| make_option(name, v, type) }
|
153
|
-
end
|
154
|
-
if type == :name_value
|
155
|
-
parts = value.to_s.split(' ')
|
156
|
-
["--#{name.tr('_', '-')}", *parts]
|
157
|
-
elsif type == :boolean
|
158
|
-
if value
|
159
|
-
["--#{name.tr('_', '-')}"]
|
160
|
-
else
|
161
|
-
[]
|
162
|
-
end
|
163
|
-
else
|
164
|
-
["--#{name.tr('_', '-')}", value.to_s]
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def valid_option(name)
|
169
|
-
if binary_version < BINARY_VERSION_WITHOUT_DASHES
|
170
|
-
"--#{name}"
|
171
|
-
else
|
172
|
-
name
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def make_options(options, names, prefix = '', type = :string)
|
177
|
-
return [] if options.nil?
|
178
|
-
names.collect do |o|
|
179
|
-
if options[o].blank?
|
180
|
-
[]
|
181
|
-
else
|
182
|
-
make_option("#{prefix.blank? ? '' : prefix + '-'}#{o}",
|
183
|
-
options[o],
|
184
|
-
type)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def parse_header_footer(options)
|
190
|
-
r = []
|
191
|
-
unless options.blank?
|
192
|
-
[:header, :footer].collect do |hf|
|
193
|
-
next if options[hf].blank?
|
194
|
-
opt_hf = options[hf]
|
195
|
-
r += make_options(opt_hf, [:center, :font_name, :left, :right], hf.to_s)
|
196
|
-
r += make_options(opt_hf, [:font_size, :spacing], hf.to_s, :numeric)
|
197
|
-
r += make_options(opt_hf, [:line], hf.to_s, :boolean)
|
198
|
-
if options[hf] && options[hf][:content]
|
199
|
-
@hf_tempfiles = [] unless defined?(@hf_tempfiles)
|
200
|
-
@hf_tempfiles.push(tf = WickedPdfTempfile.new("wicked_#{hf}_pdf.html"))
|
201
|
-
tf.write options[hf][:content]
|
202
|
-
tf.flush
|
203
|
-
options[hf][:html] = {}
|
204
|
-
options[hf][:html][:url] = "file:///#{tf.path}"
|
205
|
-
end
|
206
|
-
unless opt_hf[:html].blank?
|
207
|
-
r += make_option("#{hf}-html", opt_hf[:html][:url]) unless opt_hf[:html][:url].blank?
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
r
|
212
|
-
end
|
213
|
-
|
214
|
-
def parse_cover(argument)
|
215
|
-
arg = argument.to_s
|
216
|
-
return [] if arg.blank?
|
217
|
-
# Filesystem path or URL - hand off to wkhtmltopdf
|
218
|
-
if argument.is_a?(Pathname) || (arg[0, 4] == 'http')
|
219
|
-
[valid_option('cover'), arg]
|
220
|
-
else # HTML content
|
221
|
-
@hf_tempfiles ||= []
|
222
|
-
@hf_tempfiles << tf = WickedPdfTempfile.new('wicked_cover_pdf.html')
|
223
|
-
tf.write arg
|
224
|
-
tf.flush
|
225
|
-
[valid_option('cover'), tf.path]
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def parse_toc(options)
|
230
|
-
return [] if options.nil?
|
231
|
-
r = [valid_option('toc')]
|
232
|
-
unless options.blank?
|
233
|
-
r += make_options(options, [:font_name, :header_text], 'toc')
|
234
|
-
r += make_options(options, [:xsl_style_sheet])
|
235
|
-
r += make_options(options, [:depth,
|
236
|
-
:header_fs,
|
237
|
-
:text_size_shrink,
|
238
|
-
:l1_font_size,
|
239
|
-
:l2_font_size,
|
240
|
-
:l3_font_size,
|
241
|
-
:l4_font_size,
|
242
|
-
:l5_font_size,
|
243
|
-
:l6_font_size,
|
244
|
-
:l7_font_size,
|
245
|
-
:level_indentation,
|
246
|
-
:l1_indentation,
|
247
|
-
:l2_indentation,
|
248
|
-
:l3_indentation,
|
249
|
-
:l4_indentation,
|
250
|
-
:l5_indentation,
|
251
|
-
:l6_indentation,
|
252
|
-
:l7_indentation], 'toc', :numeric)
|
253
|
-
r += make_options(options, [:no_dots,
|
254
|
-
:disable_links,
|
255
|
-
:disable_back_links], 'toc', :boolean)
|
256
|
-
r += make_options(options, [:disable_dotted_lines,
|
257
|
-
:disable_toc_links], nil, :boolean)
|
258
|
-
end
|
259
|
-
r
|
123
|
+
def option_parser
|
124
|
+
@option_parser ||= OptionParser.new(binary_version)
|
260
125
|
end
|
261
126
|
|
262
|
-
def
|
263
|
-
|
264
|
-
unless options.blank?
|
265
|
-
r = make_options(options, [:outline], '', :boolean)
|
266
|
-
r += make_options(options, [:outline_depth], '', :numeric)
|
267
|
-
end
|
268
|
-
r
|
269
|
-
end
|
270
|
-
|
271
|
-
def parse_margins(options)
|
272
|
-
make_options(options, [:top, :bottom, :left, :right], 'margin', :numeric)
|
273
|
-
end
|
127
|
+
def clean_temp_files
|
128
|
+
return unless option_parser.hf_tempfiles.present?
|
274
129
|
|
275
|
-
|
276
|
-
r = []
|
277
|
-
unless options.blank?
|
278
|
-
r += make_options(options, [:orientation,
|
279
|
-
:dpi,
|
280
|
-
:page_size,
|
281
|
-
:page_width,
|
282
|
-
:title,
|
283
|
-
:log_level])
|
284
|
-
r += make_options(options, [:lowquality,
|
285
|
-
:grayscale,
|
286
|
-
:no_pdf_compression,
|
287
|
-
:quiet], '', :boolean)
|
288
|
-
r += make_options(options, [:image_dpi,
|
289
|
-
:image_quality,
|
290
|
-
:page_height], '', :numeric)
|
291
|
-
r += parse_margins(options.delete(:margin))
|
292
|
-
end
|
293
|
-
r
|
294
|
-
end
|
295
|
-
|
296
|
-
def parse_others(options)
|
297
|
-
r = []
|
298
|
-
unless options.blank?
|
299
|
-
r += make_options(options, [:proxy,
|
300
|
-
:username,
|
301
|
-
:password,
|
302
|
-
:encoding,
|
303
|
-
:user_style_sheet,
|
304
|
-
:viewport_size,
|
305
|
-
:window_status])
|
306
|
-
r += make_options(options, [:cookie,
|
307
|
-
:post], '', :name_value)
|
308
|
-
r += make_options(options, [:redirect_delay,
|
309
|
-
:zoom,
|
310
|
-
:page_offset,
|
311
|
-
:javascript_delay], '', :numeric)
|
312
|
-
r += make_options(options, [:book,
|
313
|
-
:default_header,
|
314
|
-
:disable_javascript,
|
315
|
-
:enable_plugins,
|
316
|
-
:disable_internal_links,
|
317
|
-
:disable_external_links,
|
318
|
-
:print_media_type,
|
319
|
-
:disable_smart_shrinking,
|
320
|
-
:use_xserver,
|
321
|
-
:no_background,
|
322
|
-
:images,
|
323
|
-
:no_images,
|
324
|
-
:no_stop_slow_scripts], '', :boolean)
|
325
|
-
end
|
326
|
-
r
|
327
|
-
end
|
328
|
-
|
329
|
-
def find_wkhtmltopdf_binary_path
|
330
|
-
possible_locations = (ENV['PATH'].split(':') + %w[/usr/bin /usr/local/bin]).uniq
|
331
|
-
possible_locations += %w[~/bin] if ENV.key?('HOME')
|
332
|
-
exe_path ||= WickedPdf.config[:exe_path] unless WickedPdf.config.empty?
|
333
|
-
exe_path ||= begin
|
334
|
-
detected_path = (defined?(Bundler) ? Bundler.which('wkhtmltopdf') : `which wkhtmltopdf`).chomp
|
335
|
-
detected_path.present? && detected_path
|
336
|
-
rescue StandardError
|
337
|
-
nil
|
338
|
-
end
|
339
|
-
exe_path ||= possible_locations.map { |l| File.expand_path("#{l}/#{EXE_NAME}") }.find { |location| File.exist?(location) }
|
340
|
-
exe_path || ''
|
130
|
+
option_parser.hf_tempfiles.each { |file| File.delete(file) }
|
341
131
|
end
|
342
132
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
// Nested js
|
@@ -76,7 +76,7 @@ class PdfHelperTest < ActionController::TestCase
|
|
76
76
|
|
77
77
|
# test that calling render does not trigger infinite loop
|
78
78
|
ac = ActionController::Base.new
|
79
|
-
assert_equal [
|
79
|
+
assert_equal %i[base patched], ac.render(:cats)
|
80
80
|
rescue SystemStackError
|
81
81
|
assert_equal true, false # force spec failure
|
82
82
|
ensure
|