esvg 2.9.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fcb20cbdb2766a9c94db529a3ccbdc7a0815b766
4
- data.tar.gz: 79366cde7d7087e46293dde3e90b3f23b8595f96
3
+ metadata.gz: ba9eff2466177493f9b6fbfcf2986422e2760edc
4
+ data.tar.gz: 4cc3286214cf2f60ae8b256365e2ada919d96288
5
5
  SHA512:
6
- metadata.gz: aaa404d0ebb54899e4f4699ab7aae135d2171ee0ba99c86428164b0a843454df4d77adf575f1f82b23c49a605fd4bd7d207f35e551333feba7afd95af4ddfa85
7
- data.tar.gz: 2e7ebad89d8d5cea1c7faef06eb6d28dde80b56d123cbd77cb015592f6bd5b5ae5cb3fd3840407ddbe2afd388e34999b7704fbb4d936da4e5725c29e799c3587
6
+ metadata.gz: 642fc2ecce236255aaed03baf2e23128fd2976112d44ee4537abe06cb57bc353df6fd84faabdbbbc43f4df6dff76cde3ef5ec4fa162c391ff4a601aea208a8b0
7
+ data.tar.gz: 565a3b3b5c172dc953ffb69225022dc2f8e3d79e76e6e8e502625527c71c64fc8ef0c00a4c7a8b400345f0847f8032d62e0b161043b3ea0aa2248bcedb5d797f
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  /test/build
11
11
  /test/optimized
12
12
  .DS_Store
13
+ node_modules
data/.travis.yml CHANGED
@@ -2,4 +2,4 @@ language: ruby
2
2
  rvm:
3
3
  - 2.1.2
4
4
  before_install: gem install bundler -v 1.10.3
5
- script: bundle exec clash 1-4
5
+ script: bundle exec clash
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Esvg
2
2
 
3
- Easily embed optimized SVGs in JS, HTML, or CSS. Use as a standalone tool or with Rails.
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, css)
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 or CSS classnames
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: css, js, html (defaults to js)") do |format|
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/SCSS/HTML files be written, (default: current directory)") do |path|
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
- @svgs = {}
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] ||= File.join(config[:output_path], 'esvg.js')
60
- config[:css_path] ||= File.join(config[:output_path], 'esvg.css')
61
- config[:html_path] ||= File.join(config[:output_path], 'esvg.html')
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
- files.each do |file, mtime|
137
- name = file_key(file)
135
+ @svgs = {}
138
136
 
139
- if svgs[name].nil? || svgs[name][:last_modified] != mtime
140
- svgs[name] = process_file(file, mtime, name)
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
- (svgs.keys - files.keys.map {|file| file_key(file) }).each do |file|
147
- svgs.delete(file)
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(get_alias(file))
162
- %Q{<svg class="#{config[:base_class]} #{name}" #{dimensions(content)}><use xlink:href="##{name}"/></svg>}
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(file)
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
- svgs[name][:use]
249
+ svg_cache[name][:use]
232
250
  end
233
251
 
234
252
  def exist?(name)
235
253
  name = get_alias(name)
236
- !svgs[name].nil?
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], '*.svg'))
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
- write_path = case config[:format]
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
- puts "Written to #{log_path write_path}" if config[:cli]
288
- write_path
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
- write_file config[:js_path], js
303
- config[:js_path]
304
- end
320
+ paths = []
305
321
 
306
- def write_css
307
- write_file config[:css_path], css
308
- config[:css_path]
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
- write_file config[:html_path], html
313
- config[:html_path]
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 css
324
- styles = []
325
-
326
- classes = svgs.keys.map{|k| ".#{classname(k)}"}.join(', ')
327
- preamble = %Q{#{classes} {
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 @files.empty?
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-symbols" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none">#{symbols}</svg>}
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 js
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
@@ -1,3 +1,3 @@
1
1
  module Esvg
2
- VERSION = "2.9.2"
2
+ VERSION = "3.0.0"
3
3
  end
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: 2.9.2
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: 2016-08-31 00:00:00.000000000 Z
11
+ date: 2017-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler