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 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