esvg 2.9.2 → 3.0.0
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/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/README.md +3 -6
- data/exe/esvg +2 -2
- data/lib/esvg/svg.rb +113 -100
- 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: ba9eff2466177493f9b6fbfcf2986422e2760edc
|
4
|
+
data.tar.gz: 4cc3286214cf2f60ae8b256365e2ada919d96288
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 642fc2ecce236255aaed03baf2e23128fd2976112d44ee4537abe06cb57bc353df6fd84faabdbbbc43f4df6dff76cde3ef5ec4fa162c391ff4a601aea208a8b0
|
7
|
+
data.tar.gz: 565a3b3b5c172dc953ffb69225022dc2f8e3d79e76e6e8e502625527c71c64fc8ef0c00a4c7a8b400345f0847f8032d62e0b161043b3ea0aa2248bcedb5d797f
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Esvg
|
2
2
|
|
3
|
-
Easily embed optimized SVGs in JS
|
3
|
+
Easily embed optimized SVGs in JS or HTML. Use as a standalone tool or with Rails.
|
4
4
|
|
5
5
|
1. Converts a directory full of SVGs into a single optimized SVG using symbols.
|
6
6
|
2. Uses Javascript to inject SVGs into pages, so it's easily cacheable.
|
@@ -97,7 +97,6 @@ $ esvg PATH [options]
|
|
97
97
|
$ esvg # Read icons from current directory, write js to ./esvg.js
|
98
98
|
$ esvg icons # Read icons from 'icons' directory, write js to ./esvg.js
|
99
99
|
$ esvg --output embedded # Read icons from current directory, write js to embedded/esvg.js
|
100
|
-
$ esvg -f --format # Embed icons in Stylesheet and write to ./esvg.scss
|
101
100
|
$ esvg -c --config foo.yml # Read confguration from foo.yml (otherwise, defaults to esvg.yml, or config/esvg.yml)
|
102
101
|
```
|
103
102
|
|
@@ -108,17 +107,15 @@ If you're using esvg from the command line, configuration files are read from `.
|
|
108
107
|
```
|
109
108
|
path: . # Where to find SVG icons (Rails defaults to app/assets/esvg)
|
110
109
|
output_path: . # Where to write output files (CLI only)
|
111
|
-
format: js # Format for output (js, html
|
110
|
+
format: js # Format for output (js, html)
|
112
111
|
|
113
112
|
base_class: svg-icon # Select all icons with this base classname
|
114
|
-
namespace: icon # Namespace for symbol ids
|
113
|
+
namespace: icon # Namespace for symbol ids
|
115
114
|
namespace_before: true # Add namespace before, e.g. icon-kitten
|
116
115
|
|
117
116
|
alias: # Add aliases for icon names
|
118
117
|
comment: chat # use "chat" to reference comment.svg
|
119
118
|
error: bad, broken # Use "bad" or "broken" to reference error.svg
|
120
|
-
|
121
|
-
font_size: 1em # Default size for SVGs (if embeded in stylesheets)
|
122
119
|
```
|
123
120
|
|
124
121
|
## Contributing
|
data/exe/esvg
CHANGED
@@ -8,11 +8,11 @@ require 'esvg'
|
|
8
8
|
options = {}
|
9
9
|
|
10
10
|
OptionParser.new do |opts|
|
11
|
-
opts.on("-f", "--format TYPE", String, "Options:
|
11
|
+
opts.on("-f", "--format TYPE", String, "Options: js, html (defaults to js)") do |format|
|
12
12
|
options[:format] = format
|
13
13
|
end
|
14
14
|
|
15
|
-
opts.on("-o", "--output PATH", String, "Where should JS/
|
15
|
+
opts.on("-o", "--output PATH", String, "Where should JS/HTML files be written, (default: current directory)") do |path|
|
16
16
|
options[:output_path] = path
|
17
17
|
end
|
18
18
|
|
data/lib/esvg/svg.rb
CHANGED
@@ -3,7 +3,7 @@ require 'json'
|
|
3
3
|
|
4
4
|
module Esvg
|
5
5
|
class SVG
|
6
|
-
attr_accessor :files, :svgs, :last_read
|
6
|
+
attr_accessor :files, :svgs, :last_read, :svg_cache
|
7
7
|
|
8
8
|
CONFIG = {
|
9
9
|
base_class: 'svg-icon',
|
@@ -14,20 +14,20 @@ module Esvg
|
|
14
14
|
verbose: false,
|
15
15
|
format: 'js',
|
16
16
|
throttle_read: 4,
|
17
|
+
flatten: [],
|
17
18
|
alias: {}
|
18
19
|
}
|
19
20
|
|
20
21
|
CONFIG_RAILS = {
|
21
22
|
path: "app/assets/esvg",
|
22
23
|
js_path: "app/assets/javascripts/esvg.js",
|
23
|
-
css_path: "app/assets/stylesheets/esvg.css"
|
24
24
|
}
|
25
25
|
|
26
26
|
def initialize(options={})
|
27
27
|
config(options)
|
28
28
|
|
29
29
|
@last_read = nil
|
30
|
-
@
|
30
|
+
@svg_cache = {}
|
31
31
|
|
32
32
|
read_files
|
33
33
|
end
|
@@ -56,11 +56,12 @@ module Esvg
|
|
56
56
|
config[:output_path] = File.expand_path(config[:output_path])
|
57
57
|
end
|
58
58
|
|
59
|
-
config[:js_path]
|
60
|
-
config[:
|
61
|
-
config[:html_path]
|
59
|
+
config[:js_path] ||= File.join(config[:output_path], 'esvg.js')
|
60
|
+
config[:js_core_path] ||= config[:js_path].sub(/[^\/]+?\./, '_esvg-core.')
|
61
|
+
config[:html_path] ||= File.join(config[:output_path], 'esvg.html')
|
62
62
|
config.delete(:output_path)
|
63
63
|
config[:aliases] = load_aliases(config[:alias])
|
64
|
+
config[:flatten] = config[:flatten].map { |dir| File.join(dir, '/') }.join('|')
|
64
65
|
|
65
66
|
config
|
66
67
|
end
|
@@ -95,8 +96,6 @@ module Esvg
|
|
95
96
|
html
|
96
97
|
elsif config[:format] == "js"
|
97
98
|
js
|
98
|
-
elsif config[:format] == "css"
|
99
|
-
css
|
100
99
|
end
|
101
100
|
|
102
101
|
if Esvg.rails?
|
@@ -133,24 +132,42 @@ module Esvg
|
|
133
132
|
# Add new svgs, update modified svgs, remove deleted svgs
|
134
133
|
#
|
135
134
|
def process_files
|
136
|
-
|
137
|
-
name = file_key(file)
|
135
|
+
@svgs = {}
|
138
136
|
|
139
|
-
|
140
|
-
|
137
|
+
files.each do |path, mtime|
|
138
|
+
key = file_key( path )
|
139
|
+
|
140
|
+
if svg_cache[key].nil? || svg_cache[key][:last_modified] != mtime
|
141
|
+
svg_cache[key] = process_file(path, mtime, key)
|
141
142
|
end
|
143
|
+
|
144
|
+
svgs[File.dirname( flatten_path( path ) )] ||= {}
|
145
|
+
svgs[File.dirname( flatten_path( path ) )][key] = svg_cache[key]
|
142
146
|
end
|
143
147
|
|
144
148
|
# Remove deleted svgs
|
145
149
|
#
|
146
|
-
(
|
147
|
-
|
150
|
+
(svg_cache.keys - files.keys.map {|file| file_key(file) }).each do |f|
|
151
|
+
svg_cache.delete(f)
|
148
152
|
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
def flatten_path(path)
|
157
|
+
root_path = File.expand_path(config[:path])
|
158
|
+
|
159
|
+
path.sub("#{root_path}/",'').sub('.svg', '')
|
160
|
+
.sub(Regexp.new(config[:flatten]), '')
|
161
|
+
end
|
162
|
+
|
163
|
+
def file_key(path)
|
164
|
+
dasherize flatten_path(path)
|
149
165
|
end
|
150
166
|
|
151
167
|
def process_file(file, mtime, name)
|
152
168
|
content = File.read(file).gsub(/<?.+\?>/,'').gsub(/<!.+?>/,'')
|
153
169
|
{
|
170
|
+
name: name,
|
154
171
|
content: content,
|
155
172
|
use: use_svg(name, content),
|
156
173
|
last_modified: mtime
|
@@ -158,12 +175,13 @@ module Esvg
|
|
158
175
|
end
|
159
176
|
|
160
177
|
def use_svg(file, content)
|
161
|
-
name = classname
|
162
|
-
|
178
|
+
name = classname get_alias(file)
|
179
|
+
viewbox = content.scan(/<svg.+(viewBox=["'](.+?)["'])/).flatten.first
|
180
|
+
%Q{<svg class="#{config[:base_class]} #{name}" #{viewbox}><use xlink:href="##{name}"/></svg>}
|
163
181
|
end
|
164
182
|
|
165
183
|
def svg_icon(file, options={})
|
166
|
-
name = dasherize
|
184
|
+
name = dasherize file
|
167
185
|
|
168
186
|
if !exist?(name)
|
169
187
|
if fallback = options.delete(:fallback)
|
@@ -228,31 +246,30 @@ module Esvg
|
|
228
246
|
|
229
247
|
def use_icon(name)
|
230
248
|
name = get_alias(name)
|
231
|
-
|
249
|
+
svg_cache[name][:use]
|
232
250
|
end
|
233
251
|
|
234
252
|
def exist?(name)
|
235
253
|
name = get_alias(name)
|
236
|
-
!
|
254
|
+
!svg_cache[name].nil?
|
237
255
|
end
|
238
256
|
|
239
257
|
alias_method :exists?, :exist?
|
240
258
|
|
241
259
|
def classname(name)
|
242
|
-
name = dasherize(name)
|
243
260
|
if config[:namespace_before]
|
244
|
-
"#{config[:namespace]}-#{name}"
|
261
|
+
dasherize "#{config[:namespace]}-#{name}"
|
245
262
|
else
|
246
|
-
"#{name}-#{config[:namespace]}"
|
263
|
+
dasherize "#{name}-#{config[:namespace]}"
|
247
264
|
end
|
248
265
|
end
|
249
266
|
|
250
267
|
def dasherize(input)
|
251
|
-
input.gsub(/[\W,_]/, '-').gsub(/-{2,}/, '-')
|
268
|
+
input.gsub(/[\W,_]/, '-').sub(/^-/,'').gsub(/-{2,}/, '-')
|
252
269
|
end
|
253
270
|
|
254
271
|
def find_files
|
255
|
-
path = File.expand_path(File.join(config[:path], '
|
272
|
+
path = File.expand_path(File.join(config[:path], '**/*.svg'))
|
256
273
|
Dir[path].uniq
|
257
274
|
end
|
258
275
|
|
@@ -275,17 +292,18 @@ module Esvg
|
|
275
292
|
|
276
293
|
def write
|
277
294
|
return if @files.empty?
|
278
|
-
|
295
|
+
write_paths = case config[:format]
|
279
296
|
when "html"
|
280
297
|
write_html
|
281
298
|
when "js"
|
282
299
|
write_js
|
283
|
-
when "css"
|
284
|
-
write_css
|
285
300
|
end
|
286
301
|
|
287
|
-
|
288
|
-
|
302
|
+
write_paths.each do |path|
|
303
|
+
puts "Written to #{log_path path}" if config[:cli]
|
304
|
+
end
|
305
|
+
|
306
|
+
write_paths
|
289
307
|
end
|
290
308
|
|
291
309
|
def log_path(path)
|
@@ -299,18 +317,34 @@ module Esvg
|
|
299
317
|
end
|
300
318
|
|
301
319
|
def write_js
|
302
|
-
|
303
|
-
config[:js_path]
|
304
|
-
end
|
320
|
+
paths = []
|
305
321
|
|
306
|
-
|
307
|
-
|
308
|
-
|
322
|
+
unless config[:js_core_path] == false
|
323
|
+
path = config[:js_core_path]
|
324
|
+
write_file path, js_core
|
325
|
+
|
326
|
+
paths.push path
|
327
|
+
end
|
328
|
+
|
329
|
+
svgs.each do |key, files|
|
330
|
+
path = write_path(:js_path, key)
|
331
|
+
write_file path, js(key)
|
332
|
+
paths.push path
|
333
|
+
end
|
334
|
+
|
335
|
+
paths
|
309
336
|
end
|
310
|
-
|
337
|
+
|
311
338
|
def write_html
|
312
|
-
|
313
|
-
|
339
|
+
paths = []
|
340
|
+
|
341
|
+
svgs.each do |key, files|
|
342
|
+
path = write_path(:html_path, key)
|
343
|
+
write_file path, html(key)
|
344
|
+
paths.push path
|
345
|
+
end
|
346
|
+
|
347
|
+
paths
|
314
348
|
end
|
315
349
|
|
316
350
|
def write_file(path, contents)
|
@@ -320,40 +354,12 @@ module Esvg
|
|
320
354
|
end
|
321
355
|
end
|
322
356
|
|
323
|
-
def
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
font-size: #{config[:font_size]};
|
329
|
-
clip: auto;
|
330
|
-
background-size: auto;
|
331
|
-
background-repeat: no-repeat;
|
332
|
-
background-position: center center;
|
333
|
-
display: inline-block;
|
334
|
-
overflow: hidden;
|
335
|
-
background-size: auto 1em;
|
336
|
-
height: 1em;
|
337
|
-
width: 1em;
|
338
|
-
color: inherit;
|
339
|
-
fill: currentColor;
|
340
|
-
vertical-align: middle;
|
341
|
-
line-height: 1em;
|
342
|
-
}}
|
343
|
-
styles << preamble
|
344
|
-
|
345
|
-
svgs.each do |name, data|
|
346
|
-
if data[:css]
|
347
|
-
styles << css
|
348
|
-
else
|
349
|
-
svg_css = data[:content].gsub(/</, '%3C') # escape <
|
350
|
-
.gsub(/>/, '%3E') # escape >
|
351
|
-
.gsub(/#/, '%23') # escape #
|
352
|
-
.gsub(/\n/,'') # remove newlines
|
353
|
-
styles << data[:css] = ".#{classname(name)} { background-image: url('data:image/svg+xml;utf-8,#{svg_css}'); }"
|
354
|
-
end
|
357
|
+
def write_path(path, key)
|
358
|
+
if key == "."
|
359
|
+
config[path]
|
360
|
+
else
|
361
|
+
config[path].sub(/[^\/]+?\./, key+'.')
|
355
362
|
end
|
356
|
-
styles.join("\n")
|
357
363
|
end
|
358
364
|
|
359
365
|
def prep_svg(file, content)
|
@@ -361,10 +367,9 @@ module Esvg
|
|
361
367
|
.gsub(/\n/, '') # Remove endlines
|
362
368
|
.gsub(/\s{2,}/, ' ') # Remove whitespace
|
363
369
|
.gsub(/>\s+</, '><') # Remove whitespace between tags
|
370
|
+
.gsub(/\s?fill="(#0{3,6}|black|rgba?\(0,0,0\))"/,'') # Strip black fill
|
364
371
|
.gsub(/style="([^"]*?)fill:(.+?);/m, 'fill="\2" style="\1') # Make fill a property instead of a style
|
365
372
|
.gsub(/style="([^"]*?)fill-opacity:(.+?);/m, 'fill-opacity="\2" style="\1') # Move fill-opacity a property instead of a style
|
366
|
-
.gsub(/\s?style=".*?";?/,'') # Strip style property
|
367
|
-
.gsub(/\s?fill="(#0{3,6}|black|rgba?\(0,0,0\))"/,'') # Strip black fill
|
368
373
|
end
|
369
374
|
|
370
375
|
def optimize(svg)
|
@@ -377,28 +382,31 @@ module Esvg
|
|
377
382
|
svg
|
378
383
|
end
|
379
384
|
|
380
|
-
def html
|
381
|
-
if
|
385
|
+
def html(key)
|
386
|
+
if svgs[key].empty?
|
382
387
|
''
|
383
388
|
else
|
384
389
|
symbols = []
|
385
|
-
svgs.each do |name, data|
|
390
|
+
svgs[key].each do |name, data|
|
386
391
|
symbols << prep_svg(name, data[:content])
|
387
392
|
end
|
388
393
|
|
389
394
|
symbols = optimize(symbols.join).gsub(/class=/,'id=').gsub(/svg/,'symbol')
|
390
395
|
|
391
|
-
%Q{<svg id="esvg
|
396
|
+
%Q{<svg id="esvg-#{key_id(key)}" version="1.1" style="height:0;position:absolute">#{symbols}</svg>}
|
392
397
|
end
|
393
398
|
end
|
394
399
|
|
395
|
-
def
|
400
|
+
def key_id(key)
|
401
|
+
(key == '.') ? 'symbols' : classname(key)
|
402
|
+
end
|
403
|
+
|
404
|
+
def svg_to_js(key)
|
405
|
+
html(key).gsub(/\n/,'').gsub("'"){"\\'"}
|
406
|
+
end
|
407
|
+
|
408
|
+
def js_core
|
396
409
|
%Q{var esvg = {
|
397
|
-
embed: function(){
|
398
|
-
if (!document.querySelector('#esvg-symbols')) {
|
399
|
-
document.querySelector('body').insertAdjacentHTML('afterbegin', '#{html.gsub(/\n/,'').gsub("'"){"\\'"}}')
|
400
|
-
}
|
401
|
-
},
|
402
410
|
icon: function(name, classnames) {
|
403
411
|
var svgName = this.iconName(name)
|
404
412
|
var element = document.querySelector('#'+svgName)
|
@@ -423,16 +431,6 @@ module Esvg
|
|
423
431
|
dasherize: function(input) {
|
424
432
|
return input.replace(/[\W,_]/g, '-').replace(/-{2,}/g, '-')
|
425
433
|
},
|
426
|
-
load: function(){
|
427
|
-
// If DOM is already ready, embed SVGs
|
428
|
-
if (document.readyState == 'interactive') { this.embed() }
|
429
|
-
|
430
|
-
// Handle Turbolinks (or other things that fire page change events)
|
431
|
-
document.addEventListener("page:change", function(event) { this.embed() }.bind(this))
|
432
|
-
|
433
|
-
// Handle standard DOM ready events
|
434
|
-
document.addEventListener("DOMContentLoaded", function(event) { this.embed() }.bind(this))
|
435
|
-
},
|
436
434
|
aliases: #{config[:aliases].to_json},
|
437
435
|
alias: function(name) {
|
438
436
|
var aliased = this.aliases[name]
|
@@ -444,13 +442,33 @@ module Esvg
|
|
444
442
|
}
|
445
443
|
}
|
446
444
|
|
447
|
-
esvg.load()
|
448
|
-
|
449
445
|
// Work with module exports:
|
450
446
|
if(typeof(module) != 'undefined') { module.exports = esvg }
|
451
447
|
}
|
452
448
|
end
|
453
449
|
|
450
|
+
def js(key)
|
451
|
+
%Q{(function(){
|
452
|
+
|
453
|
+
function embed() {
|
454
|
+
if (!document.querySelector('#esvg-#{key_id(key)}')) {
|
455
|
+
document.querySelector('body').insertAdjacentHTML('afterbegin', '#{svg_to_js(key)}')
|
456
|
+
}
|
457
|
+
}
|
458
|
+
|
459
|
+
// If DOM is already ready, embed SVGs
|
460
|
+
if (document.readyState == 'interactive') { embed() }
|
461
|
+
|
462
|
+
// Handle Turbolinks page change events
|
463
|
+
if ( window.Turbolinks ) {
|
464
|
+
document.addEventListener("turbolinks:load", function(event) { embed() })
|
465
|
+
}
|
466
|
+
|
467
|
+
// Handle standard DOM ready events
|
468
|
+
document.addEventListener("DOMContentLoaded", function(event) { embed() })
|
469
|
+
})()}
|
470
|
+
end
|
471
|
+
|
454
472
|
def find_node_module(cmd)
|
455
473
|
require 'open3'
|
456
474
|
|
@@ -466,11 +484,6 @@ if(typeof(module) != 'undefined') { module.exports = esvg }
|
|
466
484
|
end
|
467
485
|
end
|
468
486
|
|
469
|
-
def file_key(name)
|
470
|
-
dasherize(File.basename(name, ".*"))
|
471
|
-
end
|
472
|
-
|
473
|
-
|
474
487
|
def symbolize_keys(hash)
|
475
488
|
h = {}
|
476
489
|
hash.each {|k,v| h[k.to_sym] = v }
|
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
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Mathis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|