esvg 4.1.0 → 4.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/esvg/helpers.rb +3 -3
- data/lib/esvg/svg.rb +90 -81
- data/lib/esvg/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27d93663b8b9b36654390502132bf232efe68c66
|
4
|
+
data.tar.gz: 43344a22127df181e71d73602dbe0764e51d13e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc486ddf04d4b6692407740dc3d1c808181587ce8d92c0e3a78b33c35c4631d1913b961d649b2179e4e9378d4c230e2d8c53cf8e513568246511686387e3c7b2
|
7
|
+
data.tar.gz: 1d1e3f0476e4c2dee4eb68d2814712407b0e84eb8faf1e5bd49b9b5729bfa95181c106ce5ddd98e6053bb54245907702d8bfe07992dcb2c337d573f7eb65eb20
|
data/lib/esvg/helpers.rb
CHANGED
@@ -10,10 +10,10 @@ module Esvg::Helpers
|
|
10
10
|
|
11
11
|
|
12
12
|
def embed_svgs(*keys)
|
13
|
-
if Rails.env.production?
|
14
|
-
esvg.build_paths(keys).
|
13
|
+
if !Rails.env.production?
|
14
|
+
esvg.build_paths(keys).map do |path|
|
15
15
|
javascript_include_tag(path)
|
16
|
-
end.join("\n")
|
16
|
+
end.join("\n").html_safe
|
17
17
|
else
|
18
18
|
esvg.embed_script(keys).html_safe
|
19
19
|
end
|
data/lib/esvg/svg.rb
CHANGED
@@ -22,7 +22,7 @@ module Esvg
|
|
22
22
|
CONFIG_RAILS = {
|
23
23
|
source: "app/assets/svgs",
|
24
24
|
assets: "app/assets/javascripts",
|
25
|
-
build: "public/
|
25
|
+
build: "public/javascripts",
|
26
26
|
temp: "tmp"
|
27
27
|
}
|
28
28
|
|
@@ -77,7 +77,6 @@ module Esvg
|
|
77
77
|
# Get a list of svg files and modification times
|
78
78
|
#
|
79
79
|
find_files
|
80
|
-
write_cache
|
81
80
|
|
82
81
|
@last_read = Time.now.to_i
|
83
82
|
|
@@ -90,6 +89,7 @@ module Esvg
|
|
90
89
|
|
91
90
|
def find_files
|
92
91
|
files = Dir[File.join(config[:source], '**/*.svg')].uniq.sort
|
92
|
+
@svg_symbols = {}
|
93
93
|
|
94
94
|
# Remove deleted files from svg cache
|
95
95
|
(svgs.keys - file_keys(files)).each { |f| svgs.delete(f) }
|
@@ -97,16 +97,18 @@ module Esvg
|
|
97
97
|
dirs = {}
|
98
98
|
|
99
99
|
files.each do |path|
|
100
|
-
|
101
100
|
mtime = File.mtime(path).to_i
|
102
101
|
key = file_key path
|
103
102
|
dkey = dir_key path
|
104
103
|
|
105
104
|
# Use cache if possible
|
106
105
|
if svgs[key].nil? || svgs[key][:last_modified] != mtime
|
107
|
-
svgs[key] = process_file(path, mtime
|
106
|
+
svgs[key] = process_file(path, mtime)
|
108
107
|
end
|
109
108
|
|
109
|
+
# Name may have changed due to flatten config
|
110
|
+
svgs[key][:name] = file_name(path)
|
111
|
+
|
110
112
|
dirs[dkey] ||= {}
|
111
113
|
(dirs[dkey][:files] ||= []) << key
|
112
114
|
|
@@ -117,31 +119,22 @@ module Esvg
|
|
117
119
|
|
118
120
|
dirs = sort(dirs)
|
119
121
|
|
120
|
-
# Remove deleted directories from svg_symbols cache
|
121
|
-
(svg_symbols.keys - dirs.keys).each {|dir| svg_symbols.delete(dir) }
|
122
|
-
|
123
122
|
dirs.each do |dir, data|
|
124
123
|
|
125
124
|
# overwrite cache if
|
126
125
|
if svg_symbols[dir].nil? || # No cache for this dir yet
|
127
126
|
svg_symbols[dir][:last_modified] != data[:last_modified] || # New or updated file
|
128
|
-
svg_symbols[dir][:optimized] != optimize? || # Cache is unoptimized
|
129
127
|
svg_symbols[dir][:files] != data[:files] # Changed files
|
130
128
|
|
131
|
-
symbols = data[:files].map { |f| svgs[f][:content] }.join
|
132
129
|
attributes = data[:files].map { |f| svgs[f][:attr] }
|
130
|
+
mtimes = data[:files].map { |f| svgs[f][:last_modified] }.join
|
133
131
|
|
134
132
|
svg_symbols[dir] = data.merge({
|
135
133
|
name: dir,
|
136
|
-
|
137
|
-
|
138
|
-
version: config[:version] || Digest::MD5.hexdigest(symbols),
|
139
|
-
asset: File.basename(dir).start_with?('_')
|
134
|
+
asset: File.basename(dir).start_with?('_'),
|
135
|
+
version: config[:version] || Digest::MD5.hexdigest(mtimes)
|
140
136
|
})
|
141
137
|
|
142
|
-
end
|
143
|
-
|
144
|
-
svg_symbols.keys.each do |dir|
|
145
138
|
svg_symbols[dir][:path] = write_path(dir)
|
146
139
|
end
|
147
140
|
end
|
@@ -152,15 +145,12 @@ module Esvg
|
|
152
145
|
|
153
146
|
def read_cache
|
154
147
|
@svgs = YAML.load(read_tmp '.svgs') || {}
|
155
|
-
@svg_symbols = YAML.load(read_tmp '.svg_symbols') || {}
|
156
148
|
end
|
157
149
|
|
158
150
|
def write_cache
|
159
151
|
return if production?
|
160
152
|
|
161
153
|
write_tmp '.svgs', sort(@svgs).to_yaml
|
162
|
-
write_tmp '.svg_symbols', sort(@svg_symbols).to_yaml
|
163
|
-
|
164
154
|
end
|
165
155
|
|
166
156
|
def sort(hash)
|
@@ -195,26 +185,22 @@ module Esvg
|
|
195
185
|
end.map { |k| svg_symbols[k] }
|
196
186
|
end
|
197
187
|
|
198
|
-
def process_file(
|
199
|
-
content = File.read(
|
200
|
-
id = id(
|
188
|
+
def process_file(path, mtime)
|
189
|
+
content = File.read(path)
|
190
|
+
id = id(file_key(path))
|
201
191
|
size_attr = dimensions(content)
|
202
192
|
|
203
|
-
|
204
|
-
|
193
|
+
{
|
194
|
+
path: path,
|
205
195
|
use: %Q{<use xlink:href="##{id}"/>},
|
206
196
|
last_modified: mtime,
|
207
|
-
attr: { id: id }.merge(size_attr)
|
197
|
+
attr: { id: id }.merge(size_attr),
|
198
|
+
content: content
|
208
199
|
}
|
209
|
-
# Add attributes
|
210
|
-
svg[:content] = prep_svg(content, svg[:attr])
|
211
|
-
|
212
|
-
svg
|
213
200
|
end
|
214
201
|
|
215
202
|
def use(file, options={})
|
216
|
-
if
|
217
|
-
svg = svgs[name]
|
203
|
+
if svg = find_svg(file, options[:fallback])
|
218
204
|
|
219
205
|
if options[:color]
|
220
206
|
options[:style] ||= ''
|
@@ -225,7 +211,7 @@ module Esvg
|
|
225
211
|
fill: options[:fill],
|
226
212
|
style: options[:style],
|
227
213
|
viewBox: svg[:attr][:viewBox],
|
228
|
-
class: [config[:class], svg[:
|
214
|
+
class: [config[:class], id(svg[:name]), options[:class]].compact.join(' ')
|
229
215
|
}
|
230
216
|
|
231
217
|
# If user doesn't pass a size or set scale: true
|
@@ -283,14 +269,17 @@ module Esvg
|
|
283
269
|
end
|
284
270
|
|
285
271
|
def exist?(name, fallback=nil)
|
272
|
+
!find_svg(name, fallback).nil?
|
273
|
+
end
|
274
|
+
|
275
|
+
def find_svg(name, fallback=nil)
|
286
276
|
name = get_alias dasherize(name)
|
287
277
|
|
288
|
-
if svgs[name]
|
289
|
-
|
290
|
-
|
291
|
-
|
278
|
+
if svg = svgs.values.find { |v| v[:name] == name }
|
279
|
+
svg
|
280
|
+
elsif fallback
|
281
|
+
find_svg(fallback)
|
292
282
|
end
|
293
|
-
|
294
283
|
end
|
295
284
|
|
296
285
|
alias_method :exists?, :exist?
|
@@ -344,7 +333,9 @@ module Esvg
|
|
344
333
|
paths = []
|
345
334
|
|
346
335
|
files.each do |file|
|
347
|
-
|
336
|
+
content = js(file[:name])
|
337
|
+
|
338
|
+
write_file(file[:path], content)
|
348
339
|
puts "Writing #{file[:path]}" if config[:print]
|
349
340
|
paths << file[:path]
|
350
341
|
|
@@ -354,17 +345,29 @@ module Esvg
|
|
354
345
|
end
|
355
346
|
end
|
356
347
|
|
348
|
+
write_cache
|
349
|
+
|
357
350
|
paths
|
358
351
|
end
|
359
352
|
|
360
353
|
def symbols(keys)
|
361
354
|
symbols = valid_keys(keys).map { |key|
|
362
|
-
|
355
|
+
# Build on demand
|
356
|
+
build_symbols(svg_symbols[key][:files])
|
363
357
|
}.join.gsub(/\n/,'')
|
364
358
|
|
365
359
|
%Q{<svg id="esvg-#{key_id(keys)}" version="1.1" style="height:0;position:absolute">#{symbols}</svg>}
|
366
360
|
end
|
367
361
|
|
362
|
+
def build_symbols(files)
|
363
|
+
files.map { |file|
|
364
|
+
if svgs[file][:optimized_at].nil? || svgs[file][:optimized_at] < svgs[file][:last_modified]
|
365
|
+
svgs[file][:optimized_content] = optimize(svgs[file])
|
366
|
+
end
|
367
|
+
svgs[file][:optimized_content]
|
368
|
+
}.join.gsub(/\n/,'')
|
369
|
+
end
|
370
|
+
|
368
371
|
def js(key)
|
369
372
|
keys = valid_keys(key)
|
370
373
|
return if keys.empty?
|
@@ -471,10 +474,16 @@ module Esvg
|
|
471
474
|
|
472
475
|
private
|
473
476
|
|
477
|
+
def file_key(path)
|
478
|
+
dasherize sub_path(path).sub('.svg','')
|
479
|
+
end
|
480
|
+
|
474
481
|
def dir_key(path)
|
475
482
|
dir = File.dirname(flatten_path(path))
|
476
483
|
|
477
484
|
# Flattened paths which should be treated as assets will use '_' as their dir key
|
485
|
+
# - flatten: _foo - _foo/icon.svg will have a dirkey of _
|
486
|
+
# - filename: _icons - treats all root or flattened files as assets
|
478
487
|
if dir == '.' && ( sub_path(path).start_with?('_') || config[:filename].start_with?('_') )
|
479
488
|
'_'
|
480
489
|
else
|
@@ -482,6 +491,10 @@ module Esvg
|
|
482
491
|
end
|
483
492
|
end
|
484
493
|
|
494
|
+
def file_name(path)
|
495
|
+
dasherize flatten_path(path).sub('.svg','')
|
496
|
+
end
|
497
|
+
|
485
498
|
def sub_path(path)
|
486
499
|
path.sub("#{config[:source]}/",'')
|
487
500
|
end
|
@@ -490,10 +503,6 @@ module Esvg
|
|
490
503
|
sub_path(path).sub(Regexp.new(config[:flatten]), '')
|
491
504
|
end
|
492
505
|
|
493
|
-
def file_key(path)
|
494
|
-
dasherize flatten_path(path).sub('.svg', '')
|
495
|
-
end
|
496
|
-
|
497
506
|
def file_keys(paths)
|
498
507
|
paths.flatten.map { |p| file_key(p) }
|
499
508
|
end
|
@@ -518,31 +527,60 @@ module Esvg
|
|
518
527
|
end
|
519
528
|
end
|
520
529
|
|
521
|
-
def
|
522
|
-
|
530
|
+
def svgo?
|
531
|
+
!!(config[:optimize] && svgo_cmd)
|
532
|
+
end
|
533
|
+
|
534
|
+
def optimize(svg)
|
535
|
+
svg[:optimized_content] = pre_optimize svg[:content]
|
536
|
+
svg[:optimized_content] = sub_def_ids svg
|
537
|
+
|
538
|
+
if svgo?
|
539
|
+
response = Open3.capture3(%Q{#{} --disable=removeUselessDefs -s '#{svg[:content]}' -o -})
|
540
|
+
svg[:optimized_content] = response[0] if response[2].success?
|
541
|
+
end
|
542
|
+
|
543
|
+
svg[:optimized_at] = Time.now.to_i
|
544
|
+
svg[:optimized_content] = post_optimize svg
|
545
|
+
end
|
546
|
+
|
547
|
+
def pre_optimize(svg)
|
548
|
+
reg = %w(xmlns xmlns:xlink xml:space version).map { |m| "#{m}=\".+?\"" }.join('|')
|
549
|
+
svg.gsub(Regexp.new(reg), '') # Remove unwanted attributes
|
550
|
+
.gsub(/<?.+\?>/,'').gsub(/<!.+?>/,'') # Get rid of doctypes and comments
|
523
551
|
.gsub(/\n/, '') # Remove endlines
|
524
552
|
.gsub(/\s{2,}/, ' ') # Remove whitespace
|
525
553
|
.gsub(/>\s+</, '><') # Remove whitespace between tags
|
526
554
|
.gsub(/\s?fill="(#0{3,6}|black|rgba?\(0,0,0\))"/,'') # Strip black fill
|
527
555
|
.gsub(/style="([^"]*?)fill:(.+?);/m, 'fill="\2" style="\1') # Make fill a property instead of a style
|
528
556
|
.gsub(/style="([^"]*?)fill-opacity:(.+?);/m, 'fill-opacity="\2" style="\1') # Move fill-opacity a property instead of a style
|
557
|
+
end
|
529
558
|
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
content = set_attributes content, attr
|
534
|
-
content.gsub(/<\/svg/,'</symbol') # Replace svgs with symbols
|
559
|
+
def post_optimize(svg)
|
560
|
+
svg[:optimized_content] = set_attributes(svg)
|
561
|
+
.gsub(/<\/svg/,'</symbol') # Replace svgs with symbols
|
535
562
|
.gsub(/class="def-/,'id="def-') # Replace <def> classes with ids (classes are generated in sub_def_ids)
|
536
|
-
.gsub(/\s{2,}/,'') # Remove extra spaces
|
537
563
|
.gsub(/\w+=""/,'') # Remove empty attributes
|
538
564
|
end
|
539
565
|
|
566
|
+
def set_attributes(svg)
|
567
|
+
svg[:attr].keys.each { |key| svg[:optimized_content].sub!(/ #{key}=".+?"/,'') }
|
568
|
+
svg[:optimized_content].sub(/<svg/, "<symbol #{attributes(svg[:attr])}")
|
569
|
+
end
|
570
|
+
|
571
|
+
def svgo_cmd
|
572
|
+
find_node_module('svgo')
|
573
|
+
end
|
574
|
+
|
540
575
|
# Scans <def> blocks for IDs
|
541
576
|
# If urls(#id) are used, ensure these IDs are unique to this file
|
542
577
|
# Only replace IDs if urls exist to avoid replacing defs
|
543
578
|
# used in other svg files
|
544
579
|
#
|
545
|
-
def sub_def_ids(
|
580
|
+
def sub_def_ids(svg)
|
581
|
+
content = svg[:optimized_content]
|
582
|
+
name = svg[:attr][:id]
|
583
|
+
|
546
584
|
return content unless !!content.match(/<defs>/)
|
547
585
|
|
548
586
|
content.scan(/<defs>.+<\/defs>/m).flatten.each do |defs|
|
@@ -562,35 +600,6 @@ module Esvg
|
|
562
600
|
content
|
563
601
|
end
|
564
602
|
|
565
|
-
def strip_attributes(svg)
|
566
|
-
reg = %w(xmlns xmlns:xlink xml:space version).map { |m| "#{m}=\".+?\"" }.join('|')
|
567
|
-
|
568
|
-
svg.gsub(Regexp.new(reg), '')
|
569
|
-
end
|
570
|
-
|
571
|
-
def set_attributes(svg, attr)
|
572
|
-
attr.keys.each { |key| svg.sub!(/ #{key}=".+?"/,'') }
|
573
|
-
svg.sub(/<svg/, "<symbol #{attributes(attr)}")
|
574
|
-
end
|
575
|
-
|
576
|
-
def optimize?
|
577
|
-
!!(config[:optimize] && svgo_cmd)
|
578
|
-
end
|
579
|
-
|
580
|
-
def svgo_cmd
|
581
|
-
find_node_module('svgo')
|
582
|
-
end
|
583
|
-
|
584
|
-
|
585
|
-
def optimize(svg)
|
586
|
-
path = write_tmp '.svgo-tmp', svg
|
587
|
-
command = "#{svgo_cmd} --disable=removeUselessDefs '#{path}' -o -"
|
588
|
-
svg = `#{command}`
|
589
|
-
FileUtils.rm(path) if File.exist? path
|
590
|
-
|
591
|
-
svg
|
592
|
-
end
|
593
|
-
|
594
603
|
def compress(file)
|
595
604
|
return if !config[:compress]
|
596
605
|
|
data/lib/esvg/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: esvg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.1.
|
4
|
+
version: 4.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Mathis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|