esvg 3.2.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/README.md +50 -37
- data/exe/esvg +7 -11
- data/lib/esvg.rb +13 -2
- data/lib/esvg/helpers.rb +15 -8
- data/lib/esvg/svg.rb +471 -314
- 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: 103e4a996c91ea83c6ce587b3f6c7f9f21e1f3ab
|
4
|
+
data.tar.gz: e221e24b800402c241ade048d560fd578086d741
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48afc2004b3768882d80f17d338bf476116584005694c20e737ccdc0a411a67fcc1446aa50641ddcfbe214e6ed861f8e848a610b26c042129db653f23433a577
|
7
|
+
data.tar.gz: e2637534ae3808537b3b8619433d959584d9f69a2b0a078d6a8b77e964e5cbbb1647480629f55269b9639d3bc5a7c7c54ff4e3adb0f5dae988bcc1421df83503
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Esvg
|
2
2
|
|
3
|
-
|
3
|
+
Easly slip optimized, cached svgs into your workflow using standalone CLI or the simple Rails integration.
|
4
4
|
|
5
|
-
1. Converts a directory full of SVGs into a
|
6
|
-
2.
|
5
|
+
1. Converts a directory full of SVGs into a an optimized SVG using symbols for each file.
|
6
|
+
2. Build a Javascript file to inject SVGs into pages, so it's easily cacheable.
|
7
7
|
3. Offers Rails application helpers for placing icons in your views.
|
8
8
|
|
9
9
|
[![Gem Version](http://img.shields.io/gem/v/esvg.svg)](https://rubygems.org/gems/esvg)
|
@@ -28,63 +28,75 @@ Or install it yourself as:
|
|
28
28
|
|
29
29
|
## Usage: Rails
|
30
30
|
|
31
|
-
|
31
|
+
Add `Esvg.precompile_assets` to your `config/initializers/assets.rb` to add build with `rake assets:precomile`.
|
32
32
|
|
33
|
-
|
33
|
+
Add SVG files to your `app/assets/svgs/` directory.
|
34
34
|
|
35
|
-
|
35
|
+
for example:
|
36
36
|
|
37
37
|
```
|
38
|
-
|
38
|
+
app/assets/svgs
|
39
|
+
- logo.svg
|
40
|
+
- share.svg
|
41
|
+
- thumbs-up.svg
|
39
42
|
```
|
40
43
|
|
41
|
-
|
44
|
+
### Inject SVG symbols
|
45
|
+
|
46
|
+
Add this to a page or layout where SVGs should be available
|
42
47
|
|
43
48
|
```
|
44
|
-
|
49
|
+
<%= embed_svgs %>
|
45
50
|
```
|
46
51
|
|
47
|
-
|
52
|
+
**During development:**
|
53
|
+
|
54
|
+
This will embed a `<script>` which will place svg symbols at the top of your site's `<body>` as soon as the DOM is ready, and after any Turbolinks page load events.
|
55
|
+
|
56
|
+
**In Production:**
|
57
|
+
|
58
|
+
The `embed_svgs` view helper will write a `javascript_include_tag` to include the script (rather than embeding it in the page).
|
59
|
+
When you run `rake assets:precompile` this script will be built to `public/assets/svgs-{fingerprint}.js` (and a gzipped version).
|
60
|
+
|
61
|
+
This allows browsers to cache the javascript files and reduce the weight of downloading svgs for each page.
|
48
62
|
|
49
|
-
###
|
63
|
+
### Placing an SVG
|
50
64
|
|
51
|
-
To place an SVG
|
65
|
+
To place an SVG, use the `use_svg` vew helper. This helper will embed an SVG `use` tag which will reference the appropriate symbol. Here's how it works.
|
52
66
|
|
53
67
|
```
|
54
|
-
# Syntax:
|
68
|
+
# Syntax: use_svg name, [options]
|
55
69
|
|
56
70
|
# Standard example
|
57
|
-
<%=
|
71
|
+
<%= use_svg 'logo' %>
|
58
72
|
|
59
73
|
# Output:
|
60
|
-
# <svg class="
|
74
|
+
# <svg class="svg-symbol svg-logo"><use xlink:href="#svg-logo"/></svg>
|
61
75
|
|
62
76
|
# Add custom classnames
|
63
|
-
<%=
|
77
|
+
<%= use_svg 'share', class: 'disabled' %>
|
64
78
|
|
65
79
|
# Output:
|
66
|
-
# <svg class="
|
67
|
-
|
68
|
-
# Provide fallback icon if an icon is missing
|
69
|
-
<%= svg_icon 'missing', fallback: 'kitten' %>
|
70
|
-
|
71
|
-
# Output:
|
72
|
-
# <svg class="icon kitten-icon"><use xlink:href="#kitten-icon"/></svg>
|
80
|
+
# <svg class="svg-symbol svg-share disabled"><use xlink:href="#svg-share"/></svg>
|
73
81
|
|
74
82
|
# Add custom styles
|
75
|
-
<%=
|
83
|
+
<%= use_svg 'logo', style: 'fill: #c0ffee' %>
|
76
84
|
|
77
85
|
# Output:
|
78
|
-
# <svg class="
|
86
|
+
# <svg class="svg-symbol svg-logo" style="fill: #coffee;"><use xlink:href="#svg-logo"/></svg>
|
79
87
|
|
80
88
|
# Add title and desc tags for SVG accessibility.
|
81
|
-
<%=
|
89
|
+
<%= use_svg 'kitten', title: "Mr. Snuggles", desc: "A graphic of a cat snuggling a ball of yarn" %>
|
82
90
|
|
83
91
|
# Output:
|
84
92
|
# <svg class="icon kitten-icon"><use xlink:href="#kitten-icon"/>
|
85
93
|
# <title>Mr. Snuggles</title>
|
86
94
|
# <desc>A graphic of a cat snuggling a ball of yarn</desc>
|
87
95
|
# </svg>
|
96
|
+
|
97
|
+
# Provide fallback icon if an icon is missing (great for when you are generating icon names from code)
|
98
|
+
<%= use_svg 'missing', fallback: 'default' %>
|
99
|
+
|
88
100
|
```
|
89
101
|
|
90
102
|
## Usage: stand-alone CLI
|
@@ -94,10 +106,10 @@ To place an SVG icon, use the `svg_icon` helper. This helper will embed an SVG `
|
|
94
106
|
$ esvg PATH [options]
|
95
107
|
|
96
108
|
# Examples:
|
97
|
-
$ esvg
|
98
|
-
$ esvg icons
|
99
|
-
$ esvg --output
|
100
|
-
$ esvg -c --config foo.yml
|
109
|
+
$ esvg # Read icons from current directory, write js to ./svgs.js
|
110
|
+
$ esvg icons # Read icons from 'icons' directory, write js to ./svgs.js
|
111
|
+
$ esvg --output build # Read icons from current directory, write js to build/svgs.js
|
112
|
+
$ esvg -c --config foo.yml # Read confguration from foo.yml (otherwise, defaults to esvg.yml, or config/esvg.yml)
|
101
113
|
```
|
102
114
|
|
103
115
|
## Configuration
|
@@ -105,13 +117,14 @@ $ esvg -c --config foo.yml # Read confguration from foo.yml (otherwise, def
|
|
105
117
|
If you're using esvg from the command line, configuration files are read from `./esvg.yml` or you can pass a path with the `--config` option to read the config file from elsewhere.
|
106
118
|
|
107
119
|
```
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
120
|
+
source: . # Where to find SVG icons (Rails defaults to app/assets/esvg)
|
121
|
+
build: . # Where to write build files
|
122
|
+
assets: . # Where to write asset files (builds for directories beginning in _)
|
123
|
+
tmp: . # Write temporary cache files (will write to #{dir}/.esvg-cache/
|
124
|
+
|
125
|
+
class: svg-symbol # All svgs with `use_svg` will have this base classname
|
126
|
+
namespace: svg # Namespace for symbol ids, e.g 'svg-logo'
|
127
|
+
namespace_before: true # Add namespace before, e.g. 'svg-logo', false would be 'logo-svg'
|
115
128
|
|
116
129
|
alias: # Add aliases for icon names
|
117
130
|
comment: chat # use "chat" to reference comment.svg
|
data/exe/esvg
CHANGED
@@ -8,12 +8,8 @@ require 'esvg'
|
|
8
8
|
options = {}
|
9
9
|
|
10
10
|
OptionParser.new do |opts|
|
11
|
-
opts.on("-f", "--format TYPE", String, "Options: js, html (defaults to js)") do |format|
|
12
|
-
options[:format] = format
|
13
|
-
end
|
14
|
-
|
15
11
|
opts.on("-o", "--output PATH", String, "Where should JS/HTML files be written, (default: current directory)") do |path|
|
16
|
-
options[:
|
12
|
+
options[:build] = path
|
17
13
|
end
|
18
14
|
|
19
15
|
opts.on("-c", "--config PATH", String, "Path to a config file (default: esvg.yml, config/esvg.yml)") do |path|
|
@@ -24,11 +20,11 @@ OptionParser.new do |opts|
|
|
24
20
|
options[:rails] = true
|
25
21
|
end
|
26
22
|
|
27
|
-
opts.on("-O", "--optimize", "Optimize svgs with svgo") do
|
28
|
-
options[:optimize] =
|
23
|
+
opts.on("-O", "--optimize", "Optimize svgs with svgo") do
|
24
|
+
options[:optimize] = true
|
29
25
|
end
|
30
26
|
|
31
|
-
opts.on("-v", "--version", "Print version") do
|
27
|
+
opts.on("-v", "--version", "Print version") do
|
32
28
|
options[:version] = true
|
33
29
|
end
|
34
30
|
|
@@ -39,9 +35,9 @@ if options[:version]
|
|
39
35
|
else
|
40
36
|
|
41
37
|
if path = ARGV.shift
|
42
|
-
options[:
|
38
|
+
options[:source] = path
|
43
39
|
end
|
44
40
|
|
45
|
-
options[:
|
46
|
-
esvg = Esvg::SVG.new(options).
|
41
|
+
options[:print] = true
|
42
|
+
esvg = Esvg::SVG.new(options).build
|
47
43
|
end
|
data/lib/esvg.rb
CHANGED
@@ -19,12 +19,23 @@ module Esvg
|
|
19
19
|
@svgs
|
20
20
|
end
|
21
21
|
|
22
|
-
def embed
|
23
|
-
new.embed
|
22
|
+
def embed(key)
|
23
|
+
new.embed(key)
|
24
24
|
end
|
25
25
|
|
26
26
|
def rails?
|
27
27
|
defined?(Rails)
|
28
28
|
end
|
29
29
|
|
30
|
+
def build(options={})
|
31
|
+
new(options).build
|
32
|
+
end
|
33
|
+
|
34
|
+
def precompile_assets
|
35
|
+
if rails? && defined?(Rake)
|
36
|
+
::Rake::Task['assets:precompile'].enhance do
|
37
|
+
build(compress: true, print: true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
30
41
|
end
|
data/lib/esvg/helpers.rb
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
module Esvg::Helpers
|
2
|
-
def svg_icons(options={})
|
3
|
-
svgs = Esvg.svgs
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
def embed_svgs(*keys)
|
4
|
+
if Rails.env.production?
|
5
|
+
esvg_files.build_paths(keys).each do |path|
|
6
|
+
javascript_include_tag(path)
|
7
|
+
end.join("\n")
|
8
|
+
else
|
9
|
+
esvg_files.embed_script(keys).html_safe
|
7
10
|
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def use_svg(name, options={})
|
14
|
+
esvg_files.use(name, options).html_safe
|
15
|
+
end
|
16
|
+
|
17
|
+
def esvg_files
|
18
|
+
svgs = Esvg.svgs || Esvg.new()
|
8
19
|
|
9
20
|
svgs.read_files if Rails.env.development?
|
10
21
|
|
11
22
|
svgs
|
12
23
|
end
|
13
|
-
|
14
|
-
def svg_icon(name, options={})
|
15
|
-
svg_icons.use(name, options).html_safe
|
16
|
-
end
|
17
24
|
end
|
data/lib/esvg/svg.rb
CHANGED
@@ -1,34 +1,38 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'json'
|
3
|
+
require 'zlib'
|
3
4
|
|
4
5
|
module Esvg
|
5
6
|
class SVG
|
6
|
-
attr_accessor :
|
7
|
+
attr_accessor :svgs, :last_read, :svg_symbols
|
7
8
|
|
8
9
|
CONFIG = {
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
filename: 'svgs',
|
11
|
+
class: 'svg-symbol',
|
12
|
+
namespace: 'svg',
|
13
|
+
core: true,
|
12
14
|
namespace_before: true,
|
13
|
-
|
14
|
-
|
15
|
-
format: 'js',
|
15
|
+
optimize: false,
|
16
|
+
compress: false,
|
16
17
|
throttle_read: 4,
|
17
18
|
flatten: [],
|
18
19
|
alias: {}
|
19
20
|
}
|
20
21
|
|
21
22
|
CONFIG_RAILS = {
|
22
|
-
|
23
|
-
|
23
|
+
source: "app/assets/svgs",
|
24
|
+
assets: "app/assets/javascripts",
|
25
|
+
build: "public/assets",
|
26
|
+
temp: "tmp"
|
24
27
|
}
|
25
28
|
|
26
29
|
def initialize(options={})
|
27
30
|
config(options)
|
28
31
|
|
32
|
+
@modules = {}
|
29
33
|
@last_read = nil
|
30
|
-
@svg_cache = {}
|
31
34
|
|
35
|
+
read_cache
|
32
36
|
read_files
|
33
37
|
end
|
34
38
|
|
@@ -36,10 +40,10 @@ module Esvg
|
|
36
40
|
@config ||= begin
|
37
41
|
paths = [options[:config_file], 'config/esvg.yml', 'esvg.yml'].compact
|
38
42
|
|
39
|
-
config = CONFIG
|
43
|
+
config = CONFIG.dup
|
40
44
|
|
41
45
|
if Esvg.rails? || options[:rails]
|
42
|
-
config.merge!(CONFIG_RAILS)
|
46
|
+
config.merge!(CONFIG_RAILS)
|
43
47
|
end
|
44
48
|
|
45
49
|
if path = paths.select{ |p| File.exist?(p)}.first
|
@@ -47,61 +51,21 @@ module Esvg
|
|
47
51
|
end
|
48
52
|
|
49
53
|
config.merge!(options)
|
50
|
-
|
51
|
-
config[:path] ||= Dir.pwd
|
52
|
-
config[:output_path] ||= Dir.pwd
|
53
54
|
|
54
|
-
|
55
|
-
config[:path] = File.expand_path(config[:path])
|
56
|
-
config[:output_path] = File.expand_path(config[:output_path])
|
57
|
-
end
|
55
|
+
config[:filename] = File.basename(config[:filename], '.*')
|
58
56
|
|
59
|
-
config[:
|
60
|
-
config[:
|
61
|
-
config[:
|
62
|
-
config.
|
63
|
-
config[:aliases] = load_aliases(config[:alias])
|
64
|
-
config[:flatten] = config[:flatten].map { |dir| File.join(dir, '/') }.join('|')
|
57
|
+
config[:pwd] = File.expand_path Dir.pwd
|
58
|
+
config[:source] = File.expand_path config[:source] || config[:pwd]
|
59
|
+
config[:build] = File.expand_path config[:build] || config[:pwd]
|
60
|
+
config[:assets] = File.expand_path config[:assets] || config[:pwd]
|
65
61
|
|
66
|
-
config
|
67
|
-
|
68
|
-
end
|
62
|
+
config[:temp] = config[:pwd] if config[:temp].nil?
|
63
|
+
config[:temp] = File.expand_path File.join(config[:temp], '.esvg-cache')
|
69
64
|
|
70
|
-
|
71
|
-
|
72
|
-
# Converts configuration YAML:
|
73
|
-
# alias:
|
74
|
-
# foo: bar
|
75
|
-
# baz: zip, zop
|
76
|
-
# To output:
|
77
|
-
# { :bar => "foo", :zip => "baz", :zop => "baz" }
|
78
|
-
#
|
79
|
-
def load_aliases(aliases)
|
80
|
-
a = {}
|
81
|
-
aliases.each do |name,alternates|
|
82
|
-
alternates.split(',').each do |val|
|
83
|
-
a[dasherize(val.strip).to_sym] = dasherize(name.to_s)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
a
|
87
|
-
end
|
88
|
-
|
89
|
-
def get_alias(name)
|
90
|
-
config[:aliases][dasherize(name).to_sym] || name
|
91
|
-
end
|
92
|
-
|
93
|
-
def embed
|
94
|
-
return if files.empty?
|
95
|
-
output = if config[:format] == "html"
|
96
|
-
html
|
97
|
-
elsif config[:format] == "js"
|
98
|
-
js
|
99
|
-
end
|
65
|
+
config[:aliases] = load_aliases(config[:alias])
|
66
|
+
config[:flatten] = [config[:flatten]].flatten.map { |dir| File.join(dir, '/') }.join('|')
|
100
67
|
|
101
|
-
|
102
|
-
output.html_safe
|
103
|
-
else
|
104
|
-
output
|
68
|
+
config
|
105
69
|
end
|
106
70
|
end
|
107
71
|
|
@@ -110,157 +74,219 @@ module Esvg
|
|
110
74
|
return
|
111
75
|
end
|
112
76
|
|
113
|
-
@files = {}
|
114
|
-
|
115
77
|
# Get a list of svg files and modification times
|
116
78
|
#
|
117
|
-
find_files
|
118
|
-
|
119
|
-
end
|
79
|
+
find_files
|
80
|
+
write_cache
|
120
81
|
|
121
82
|
@last_read = Time.now.to_i
|
122
83
|
|
123
|
-
puts "Read #{
|
84
|
+
puts "Read #{svgs.size} files from #{config[:source]}" if config[:print]
|
124
85
|
|
125
|
-
|
126
|
-
|
127
|
-
if files.empty? && config[:cli]
|
128
|
-
puts "No svgs found at #{config[:path]}"
|
86
|
+
if svgs.empty? && config[:print]
|
87
|
+
puts "No svgs found at #{config[:source]}"
|
129
88
|
end
|
130
89
|
end
|
131
90
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
91
|
+
def find_files
|
92
|
+
files = Dir[File.join(config[:source], '**/*.svg')].uniq.sort
|
93
|
+
|
94
|
+
# Remove deleted files from svg cache
|
95
|
+
(svgs.keys - file_keys(files)).each { |f| svgs.delete(f) }
|
96
|
+
|
97
|
+
dirs = {}
|
98
|
+
|
99
|
+
files.each do |path|
|
136
100
|
|
137
|
-
|
138
|
-
key = file_key
|
101
|
+
mtime = File.mtime(path).to_i
|
102
|
+
key = file_key path
|
103
|
+
dkey = dir_key path
|
139
104
|
|
140
|
-
|
141
|
-
|
105
|
+
# Use cache if possible
|
106
|
+
if svgs[key].nil? || svgs[key][:last_modified] != mtime
|
107
|
+
svgs[key] = process_file(path, mtime, key)
|
142
108
|
end
|
143
109
|
|
144
|
-
|
145
|
-
|
110
|
+
dirs[dkey] ||= {}
|
111
|
+
(dirs[dkey][:files] ||= []) << key
|
112
|
+
|
113
|
+
if dirs[dkey][:last_modified].nil? || dirs[dkey][:last_modified] < mtime
|
114
|
+
dirs[dkey][:last_modified] = mtime
|
115
|
+
end
|
146
116
|
end
|
147
117
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
118
|
+
dirs = sort(dirs)
|
119
|
+
|
120
|
+
# Remove deleted directories from svg_symbols cache
|
121
|
+
(svg_symbols.keys - dirs.keys).each {|dir| svg_symbols.delete(dir) }
|
122
|
+
|
123
|
+
dirs.each do |dir, data|
|
124
|
+
|
125
|
+
# overwrite cache if
|
126
|
+
if svg_symbols[dir].nil? || # No cache for this dir yet
|
127
|
+
svg_symbols[dir][:last_modified] != data[:last_modified] || # New or updated file
|
128
|
+
svg_symbols[dir][:optimized] != optimize? || # Cache is unoptimized
|
129
|
+
svg_symbols[dir][:files] != data[:files] # Changed files
|
130
|
+
|
131
|
+
symbols = data[:files].map { |f| svgs[f][:content] }.join
|
132
|
+
attributes = data[:files].map { |f| svgs[f][:attr] }
|
133
|
+
|
134
|
+
svg_symbols[dir] = data.merge({
|
135
|
+
name: dir,
|
136
|
+
symbols: optimize(symbols, attributes),
|
137
|
+
optimized: optimize?,
|
138
|
+
version: config[:version] || Digest::MD5.hexdigest(symbols),
|
139
|
+
asset: File.basename(dir).start_with?('_')
|
140
|
+
})
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
svg_symbols.keys.each do |dir|
|
145
|
+
svg_symbols[dir][:path] = write_path(dir)
|
146
|
+
end
|
152
147
|
end
|
148
|
+
|
149
|
+
@svg_symbols = sort(@svg_symbols)
|
150
|
+
@svgs = sort(@svgs)
|
151
|
+
end
|
152
|
+
|
153
|
+
def read_cache
|
154
|
+
@svgs = YAML.load(read_tmp '.svgs') || {}
|
155
|
+
@svg_symbols = YAML.load(read_tmp '.svg_symbols') || {}
|
156
|
+
end
|
157
|
+
|
158
|
+
def write_cache
|
159
|
+
return if production?
|
160
|
+
|
161
|
+
write_tmp '.svgs', sort(@svgs).to_yaml
|
162
|
+
write_tmp '.svg_symbols', sort(@svg_symbols).to_yaml
|
163
|
+
|
153
164
|
end
|
154
165
|
|
155
|
-
def
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
config[:flatten].include?(key)
|
166
|
+
def sort(hash)
|
167
|
+
sorted = {}
|
168
|
+
hash.sort.each do |h|
|
169
|
+
sorted[h.first] = h.last
|
160
170
|
end
|
171
|
+
sorted
|
172
|
+
end
|
161
173
|
|
162
|
-
|
174
|
+
def embed_script(key=nil)
|
175
|
+
if script = js(key)
|
176
|
+
"<script>#{script}</script>"
|
177
|
+
else
|
178
|
+
''
|
179
|
+
end
|
163
180
|
end
|
164
181
|
|
165
|
-
def
|
166
|
-
|
182
|
+
def build_paths(keys=nil)
|
183
|
+
build_files(keys).map { |s| File.basename(s[:path]) }
|
184
|
+
end
|
167
185
|
|
168
|
-
|
169
|
-
|
186
|
+
def build_files(keys=nil)
|
187
|
+
valid_keys(keys).reject do |k|
|
188
|
+
svg_symbols[k][:asset]
|
189
|
+
end.map { |k| svg_symbols[k] }
|
170
190
|
end
|
171
191
|
|
172
|
-
def
|
173
|
-
|
192
|
+
def asset_files(keys=nil)
|
193
|
+
valid_keys(keys).select do |k|
|
194
|
+
svg_symbols[k][:asset]
|
195
|
+
end.map { |k| svg_symbols[k] }
|
174
196
|
end
|
175
197
|
|
176
198
|
def process_file(file, mtime, name)
|
177
|
-
content
|
178
|
-
|
199
|
+
content = File.read(file)
|
200
|
+
classname = classname(name)
|
201
|
+
size_attr = dimensions(content)
|
202
|
+
|
203
|
+
svg = {
|
179
204
|
name: name,
|
180
|
-
|
181
|
-
|
182
|
-
|
205
|
+
use: %Q{<use xlink:href="##{classname}"/>},
|
206
|
+
last_modified: mtime,
|
207
|
+
attr: { class: classname }.merge(dimensions(content))
|
183
208
|
}
|
184
|
-
|
209
|
+
# Add attributes
|
210
|
+
svg[:content] = prep_svg(content, svg[:attr])
|
185
211
|
|
186
|
-
|
187
|
-
name = classname get_alias(file)
|
188
|
-
viewbox = content.scan(/<svg.+(viewBox=["'](.+?)["'])/).flatten.first
|
189
|
-
%Q{<svg class="#{config[:base_class]} #{name}" #{viewbox}><use xlink:href="##{name}"/></svg>}
|
212
|
+
svg
|
190
213
|
end
|
191
214
|
|
192
|
-
def
|
193
|
-
name =
|
194
|
-
|
195
|
-
if !exist?(name)
|
196
|
-
if fallback = options.delete(:fallback)
|
197
|
-
svg_icon(fallback, options)
|
198
|
-
else
|
199
|
-
if Esvg.rails? && Rails.env.production?
|
200
|
-
return ''
|
201
|
-
else
|
202
|
-
raise "no svg named '#{get_alias(file)}' exists at #{config[:path]}"
|
203
|
-
end
|
204
|
-
end
|
205
|
-
else
|
206
|
-
|
207
|
-
embed = use_icon(name)
|
208
|
-
embed = embed.sub(/class="(.+?)"/, 'class="\1 '+options[:class]+'"') if options[:class]
|
215
|
+
def use(file, options={})
|
216
|
+
if name = exist?(file, options[:fallback])
|
217
|
+
svg = svgs[name]
|
209
218
|
|
210
219
|
if options[:color]
|
211
220
|
options[:style] ||= ''
|
212
|
-
options[:style] += "
|
221
|
+
options[:style] += "color:#{options[:color]};#{options[:style]}"
|
213
222
|
end
|
214
223
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
224
|
+
attr = {
|
225
|
+
fill: options[:fill],
|
226
|
+
style: options[:style],
|
227
|
+
viewbox: svg[:attr][:viewbox],
|
228
|
+
classname: [config[:class], svg[:attr][:class], options[:class]].compact.join(' ')
|
229
|
+
}
|
219
230
|
|
220
|
-
|
231
|
+
# If user doesn't pass a size or set scale: true
|
232
|
+
if !(options[:width] || options[:height] || options[:scale])
|
221
233
|
|
222
|
-
|
223
|
-
|
234
|
+
# default to svg dimensions
|
235
|
+
attr[:width] = svg[:attr][:width]
|
236
|
+
attr[:height] = svg[:attr][:height]
|
224
237
|
else
|
225
|
-
|
238
|
+
|
239
|
+
# Add sizes (nil options will be stripped)
|
240
|
+
attr[:width] = options[:width]
|
241
|
+
attr[:height] = options[:height]
|
226
242
|
end
|
227
|
-
end
|
228
|
-
end
|
229
243
|
|
230
|
-
|
244
|
+
use = %Q{<svg #{attributes(attr)}>#{svg[:use]}#{title(options)}#{desc(options)}</svg>}
|
231
245
|
|
232
|
-
|
233
|
-
|
234
|
-
content = content.to_s
|
235
|
-
if tag.match(/#{attr}/)
|
236
|
-
if append
|
237
|
-
tag.sub(/#{attr}="(.+?)"/, attr+'="\1'+append+content+'"')
|
246
|
+
if Esvg.rails?
|
247
|
+
use.html_safe
|
238
248
|
else
|
239
|
-
|
249
|
+
use
|
240
250
|
end
|
241
251
|
else
|
242
|
-
|
252
|
+
if production?
|
253
|
+
return ''
|
254
|
+
else
|
255
|
+
raise "no svg named '#{get_alias(file)}' exists at #{config[:source]}"
|
256
|
+
end
|
243
257
|
end
|
244
258
|
end
|
245
259
|
|
260
|
+
alias :svg_icon :use
|
261
|
+
|
246
262
|
def dimensions(input)
|
247
|
-
|
248
|
-
|
249
|
-
coords = dimension.last.split(' ')
|
263
|
+
viewbox = input.scan(/<svg.+(viewBox=["'](.+?)["'])/).flatten.last
|
264
|
+
coords = viewbox.split(' ')
|
250
265
|
|
251
|
-
|
252
|
-
|
253
|
-
|
266
|
+
{
|
267
|
+
viewbox: viewbox,
|
268
|
+
width: coords[2].to_i - coords[0].to_i,
|
269
|
+
height: coords[3].to_i - coords[1].to_i
|
270
|
+
}
|
254
271
|
end
|
255
272
|
|
256
|
-
def
|
257
|
-
|
258
|
-
|
273
|
+
def attributes(hash)
|
274
|
+
att = []
|
275
|
+
hash.each do |key, value|
|
276
|
+
att << %Q{#{key}="#{value}"} unless value.nil?
|
277
|
+
end
|
278
|
+
att.join(' ')
|
259
279
|
end
|
260
280
|
|
261
|
-
def exist?(name)
|
262
|
-
name = get_alias(name)
|
263
|
-
|
281
|
+
def exist?(name, fallback=nil)
|
282
|
+
name = get_alias dasherize(name)
|
283
|
+
|
284
|
+
if svgs[name].nil?
|
285
|
+
exist?(fallback) if fallback
|
286
|
+
else
|
287
|
+
name
|
288
|
+
end
|
289
|
+
|
264
290
|
end
|
265
291
|
|
266
292
|
alias_method :exists?, :exist?
|
@@ -277,12 +303,6 @@ module Esvg
|
|
277
303
|
input.gsub(/[\W,_]/, '-').sub(/^-/,'').gsub(/-{2,}/, '-')
|
278
304
|
end
|
279
305
|
|
280
|
-
def find_files
|
281
|
-
path = File.expand_path(File.join(config[:path], '**/*.svg'))
|
282
|
-
Dir[path].uniq
|
283
|
-
end
|
284
|
-
|
285
|
-
|
286
306
|
def title(options)
|
287
307
|
if options[:title]
|
288
308
|
"<title>#{options[:title]}</title>"
|
@@ -299,104 +319,224 @@ module Esvg
|
|
299
319
|
end
|
300
320
|
end
|
301
321
|
|
302
|
-
def
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
322
|
+
def version(key)
|
323
|
+
svg_symbols[key][:version]
|
324
|
+
end
|
325
|
+
|
326
|
+
def build
|
327
|
+
paths = write_files svg_symbols.values
|
328
|
+
|
329
|
+
if config[:core]
|
330
|
+
path = File.join config[:assets], "_esvg.js"
|
331
|
+
write_file(path, js_core)
|
332
|
+
paths << path
|
309
333
|
end
|
310
334
|
|
311
|
-
|
312
|
-
|
335
|
+
paths
|
336
|
+
end
|
337
|
+
|
338
|
+
def write_files(files)
|
339
|
+
paths = []
|
340
|
+
|
341
|
+
files.each do |file|
|
342
|
+
if file[:asset] || !File.exist?(file[:path])
|
343
|
+
write_file(file[:path], js(file[:name]))
|
344
|
+
puts "Writing #{file[:path]}" if config[:print]
|
345
|
+
paths << file[:path]
|
346
|
+
|
347
|
+
if !file[:asset] && gz = compress(file[:path])
|
348
|
+
puts "Writing #{gz}" if config[:print]
|
349
|
+
paths << gz
|
350
|
+
end
|
351
|
+
end
|
313
352
|
end
|
314
353
|
|
315
|
-
|
354
|
+
paths
|
316
355
|
end
|
317
356
|
|
318
|
-
def
|
319
|
-
|
357
|
+
def symbols(keys)
|
358
|
+
symbols = valid_keys(keys).map { |key|
|
359
|
+
svg_symbols[key][:symbols]
|
360
|
+
}.join.gsub(/\n/,'')
|
361
|
+
|
362
|
+
%Q{<svg id="esvg-#{key_id(keys)}" version="1.1" style="height:0;position:absolute">#{symbols}</svg>}
|
320
363
|
end
|
321
364
|
|
322
|
-
def
|
323
|
-
|
324
|
-
|
325
|
-
|
365
|
+
def js(key)
|
366
|
+
keys = valid_keys(key)
|
367
|
+
return if keys.empty?
|
368
|
+
|
369
|
+
script key_id(keys), symbols(keys).gsub('/n','').gsub("'"){"\\'"}
|
326
370
|
end
|
327
371
|
|
328
|
-
def
|
329
|
-
|
372
|
+
def script(id, symbols)
|
373
|
+
%Q{(function(){
|
330
374
|
|
331
|
-
|
332
|
-
|
333
|
-
|
375
|
+
function embed() {
|
376
|
+
if (!document.querySelector('#esvg-#{id}')) {
|
377
|
+
document.querySelector('body').insertAdjacentHTML('afterbegin', '#{symbols}')
|
378
|
+
}
|
379
|
+
}
|
334
380
|
|
335
|
-
|
336
|
-
|
381
|
+
// If DOM is already ready, embed SVGs
|
382
|
+
if (document.readyState == 'interactive') { embed() }
|
337
383
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
end
|
384
|
+
// Handle Turbolinks page change events
|
385
|
+
if ( window.Turbolinks ) {
|
386
|
+
document.addEventListener("turbolinks:load", function(event) { embed() })
|
387
|
+
}
|
343
388
|
|
344
|
-
|
389
|
+
// Handle standard DOM ready events
|
390
|
+
document.addEventListener("DOMContentLoaded", function(event) { embed() })
|
391
|
+
})()}
|
345
392
|
end
|
346
393
|
|
347
|
-
def
|
348
|
-
|
394
|
+
def js_core
|
395
|
+
%Q{(function(){
|
396
|
+
var names
|
349
397
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
398
|
+
function attr( source, name ){
|
399
|
+
if (typeof source == 'object')
|
400
|
+
return name+'="'+source.getAttribute(name)+'" '
|
401
|
+
else
|
402
|
+
return name+'="'+source+'" ' }
|
355
403
|
|
356
|
-
|
357
|
-
|
404
|
+
function dasherize( input ) {
|
405
|
+
return input.replace(/[\\W,_]/g, '-').replace(/-{2,}/g, '-')
|
406
|
+
}
|
358
407
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
408
|
+
function svgName( name ) {
|
409
|
+
#{if config[:namespace_before]
|
410
|
+
%Q{return "#{config[:namespace]}-"+dasherize( name )}
|
411
|
+
else
|
412
|
+
%Q{return dasherize( name )+"-#{config[:namespace]}"}
|
413
|
+
end}
|
414
|
+
}
|
415
|
+
|
416
|
+
function use( name, options ) {
|
417
|
+
options = options || {}
|
418
|
+
var id = dasherize( svgName( name ) )
|
419
|
+
var symbol = svgs()[id]
|
420
|
+
|
421
|
+
if ( symbol ) {
|
422
|
+
var svg = document.createRange().createContextualFragment( '<svg><use xlink:href="#'+id+'"/></svg>' ).firstChild;
|
423
|
+
svg.setAttribute( 'class', '#{config[:class]} '+id+' '+( options.classname || '' ).trim() )
|
424
|
+
svg.setAttribute( 'viewBox', symbol.getAttribute( 'viewBox' ) )
|
425
|
+
|
426
|
+
if ( !( options.width || options.height || options.scale ) ) {
|
427
|
+
|
428
|
+
svg.setAttribute('width', symbol.getAttribute('width'))
|
429
|
+
svg.setAttribute('height', symbol.getAttribute('height'))
|
430
|
+
|
431
|
+
} else {
|
432
|
+
|
433
|
+
if ( options.width ) svg.setAttribute( 'width', options.width )
|
434
|
+
if ( options.height ) svg.setAttribute( 'height', options.height )
|
435
|
+
}
|
436
|
+
|
437
|
+
return svg
|
438
|
+
} else {
|
439
|
+
console.error('Cannot find "'+name+'" svg symbol. Ensure that svg scripts are loaded')
|
440
|
+
}
|
441
|
+
}
|
442
|
+
|
443
|
+
function svgs(){
|
444
|
+
if ( !names ) {
|
445
|
+
names = {}
|
446
|
+
for( var symbol of document.querySelectorAll( 'svg[id^=esvg] symbol' ) ) {
|
447
|
+
names[symbol.id] = symbol
|
448
|
+
}
|
449
|
+
}
|
450
|
+
return names
|
451
|
+
}
|
452
|
+
|
453
|
+
var esvg = {
|
454
|
+
svgs: svgs,
|
455
|
+
use: use
|
456
|
+
}
|
457
|
+
|
458
|
+
// Handle Turbolinks page change events
|
459
|
+
if ( window.Turbolinks ) {
|
460
|
+
document.addEventListener( "turbolinks:load", function( event ) { names = null; esvg.svgs() })
|
461
|
+
}
|
462
|
+
|
463
|
+
if( typeof( module ) != 'undefined' ) { module.exports = esvg }
|
464
|
+
else window.esvg = esvg
|
465
|
+
|
466
|
+
})()}
|
364
467
|
end
|
365
468
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
469
|
+
private
|
470
|
+
|
471
|
+
def dir_key(path)
|
472
|
+
dir = File.dirname(flatten_path(path))
|
473
|
+
|
474
|
+
# Flattened paths which should be treated as assets will use '_' as their dir key
|
475
|
+
if dir == '.' && ( sub_path(path).start_with?('_') || config[:filename].start_with?('_') )
|
476
|
+
'_'
|
477
|
+
else
|
478
|
+
dir
|
371
479
|
end
|
480
|
+
end
|
372
481
|
|
373
|
-
|
482
|
+
def sub_path(path)
|
483
|
+
path.sub("#{config[:source]}/",'')
|
374
484
|
end
|
375
485
|
|
376
|
-
def
|
377
|
-
|
378
|
-
|
486
|
+
def flatten_path(path)
|
487
|
+
sub_path(path).sub(Regexp.new(config[:flatten]), '')
|
488
|
+
end
|
379
489
|
|
380
|
-
|
381
|
-
|
490
|
+
def file_key(path)
|
491
|
+
dasherize flatten_path(path).sub('.svg', '')
|
492
|
+
end
|
493
|
+
|
494
|
+
def file_keys(paths)
|
495
|
+
paths.flatten.map { |p| file_key(p) }
|
496
|
+
end
|
497
|
+
|
498
|
+
def write_path(key)
|
499
|
+
name = if key == '_' # Root level asset file
|
500
|
+
"_#{config[:filename]}".sub(/_+/, '_')
|
501
|
+
elsif key == '.' # Root level build file
|
502
|
+
config[:filename]
|
382
503
|
else
|
383
|
-
|
504
|
+
"#{key}"
|
505
|
+
end
|
506
|
+
|
507
|
+
# Is it an asset, or a build file
|
508
|
+
if name.start_with?('_')
|
509
|
+
File.join config[:assets], "#{name}.js"
|
510
|
+
else
|
511
|
+
File.join config[:build], "#{name}-#{version(key)}.js"
|
384
512
|
end
|
385
513
|
end
|
386
514
|
|
515
|
+
def prep_svg(content, attr)
|
516
|
+
content = content.gsub(/<?.+\?>/,'').gsub(/<!.+?>/,'') # Get rid of doctypes and comments
|
517
|
+
.gsub(/\n/, '') # Remove endlines
|
518
|
+
.gsub(/\s{2,}/, ' ') # Remove whitespace
|
519
|
+
.gsub(/>\s+</, '><') # Remove whitespace between tags
|
520
|
+
.gsub(/\s?fill="(#0{3,6}|black|rgba?\(0,0,0\))"/,'') # Strip black fill
|
521
|
+
.gsub(/style="([^"]*?)fill:(.+?);/m, 'fill="\2" style="\1') # Make fill a property instead of a style
|
522
|
+
.gsub(/style="([^"]*?)fill-opacity:(.+?);/m, 'fill-opacity="\2" style="\1') # Move fill-opacity a property instead of a style
|
523
|
+
|
524
|
+
sub_def_ids(content, attr[:class])
|
525
|
+
end
|
526
|
+
|
387
527
|
# Scans <def> blocks for IDs
|
388
528
|
# If urls(#id) are used, ensure these IDs are unique to this file
|
389
529
|
# Only replace IDs if urls exist to avoid replacing defs
|
390
530
|
# used in other svg files
|
391
531
|
#
|
392
|
-
def sub_def_ids(
|
532
|
+
def sub_def_ids(content, classname)
|
393
533
|
return content unless !!content.match(/<defs>/)
|
394
534
|
|
395
535
|
content.scan(/<defs>.+<\/defs>/m).flatten.each do |defs|
|
396
536
|
defs.scan(/id="(.+?)"/).flatten.uniq.each_with_index do |id, index|
|
397
537
|
|
398
538
|
if content.match(/url\(##{id}\)/)
|
399
|
-
new_id = "#{classname
|
539
|
+
new_id = "#{classname}-def#{index}"
|
400
540
|
|
401
541
|
content = content.gsub(/id="#{id}"/, %Q{class="#{new_id}"})
|
402
542
|
.gsub(/url\(##{id}\)/, "url(##{new_id})" )
|
@@ -409,127 +549,106 @@ module Esvg
|
|
409
549
|
content
|
410
550
|
end
|
411
551
|
|
412
|
-
def
|
413
|
-
|
414
|
-
|
415
|
-
.gsub(/\s{2,}/, ' ') # Remove whitespace
|
416
|
-
.gsub(/>\s+</, '><') # Remove whitespace between tags
|
417
|
-
.gsub(/\s?fill="(#0{3,6}|black|rgba?\(0,0,0\))"/,'') # Strip black fill
|
418
|
-
.gsub(/style="([^"]*?)fill:(.+?);/m, 'fill="\2" style="\1') # Make fill a property instead of a style
|
419
|
-
.gsub(/style="([^"]*?)fill-opacity:(.+?);/m, 'fill-opacity="\2" style="\1') # Move fill-opacity a property instead of a style
|
552
|
+
def optimize?
|
553
|
+
!!(config[:optimize] && svgo_cmd)
|
554
|
+
end
|
420
555
|
|
421
|
-
|
556
|
+
def svgo_cmd
|
557
|
+
find_node_module('svgo')
|
422
558
|
end
|
423
559
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
560
|
+
|
561
|
+
def optimize(svg, attributes)
|
562
|
+
if optimize?
|
563
|
+
path = write_tmp '.svgo-tmp', svg
|
564
|
+
command = "#{svgo_cmd} --disable=removeUselessDefs '#{path}' -o -"
|
565
|
+
svg = `#{command}`
|
566
|
+
FileUtils.rm(path) if File.exist? path
|
429
567
|
end
|
430
568
|
|
431
|
-
svg
|
569
|
+
id_symbols(svg, attributes)
|
432
570
|
end
|
433
571
|
|
434
|
-
def
|
435
|
-
|
436
|
-
|
437
|
-
else
|
438
|
-
symbols = []
|
439
|
-
svgs[key].each do |name, data|
|
440
|
-
symbols << prep_svg(name, data[:content])
|
441
|
-
end
|
442
|
-
|
443
|
-
symbols = optimize(symbols.join).gsub(/class=/,'id=').gsub(/svg/,'symbol')
|
444
|
-
|
445
|
-
%Q{<svg id="esvg-#{key_id(key)}" version="1.1" style="height:0;position:absolute">#{symbols}</svg>}
|
572
|
+
def id_symbols(svg, attr)
|
573
|
+
svg.gsub(/<svg.+?>/).with_index do |match, index|
|
574
|
+
%Q{<symbol #{attributes(attr[index])}>} # Remove clutter from svg declaration
|
446
575
|
end
|
576
|
+
.gsub(/<\/svg/,'</symbol') # Replace svgs with symbols
|
577
|
+
.gsub(/class=/,'id=') # Replace classes with ids (classes are generated here)
|
578
|
+
.gsub(/\w+=""/,'') # Remove empty attributes
|
447
579
|
end
|
448
580
|
|
449
|
-
def
|
450
|
-
|
451
|
-
end
|
581
|
+
def compress(file)
|
582
|
+
return if !config[:compress]
|
452
583
|
|
453
|
-
|
454
|
-
|
455
|
-
end
|
584
|
+
mtime = File.mtime(file)
|
585
|
+
gz_file = "#{file}.gz"
|
456
586
|
|
457
|
-
|
458
|
-
%Q{var esvg = {
|
459
|
-
icon: function(name, classnames) {
|
460
|
-
var svgName = this.iconName(name)
|
461
|
-
var element = document.querySelector('#'+svgName)
|
587
|
+
return if (File.exist?(gz_file) && File.mtime(gz_file) >= mtime)
|
462
588
|
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
iconName: function(name) {
|
470
|
-
var before = #{config[:namespace_before]}
|
471
|
-
if (before) {
|
472
|
-
return "#{config[:namespace]}-"+this.dasherize(name)
|
473
|
-
} else {
|
474
|
-
return name+"-#{config[:namespace]}"
|
475
|
-
}
|
476
|
-
},
|
477
|
-
dimensions: function(el) {
|
478
|
-
return 'viewBox="'+el.getAttribute('viewBox')+'" width="'+el.getAttribute('width')+'" height="'+el.getAttribute('height')+'"'
|
479
|
-
},
|
480
|
-
dasherize: function(input) {
|
481
|
-
return input.replace(/[\W,_]/g, '-').replace(/-{2,}/g, '-')
|
482
|
-
},
|
483
|
-
aliases: #{config[:aliases].to_json},
|
484
|
-
alias: function(name) {
|
485
|
-
var aliased = this.aliases[name]
|
486
|
-
if (typeof(aliased) != "undefined") {
|
487
|
-
return aliased
|
488
|
-
} else {
|
489
|
-
return name
|
490
|
-
}
|
491
|
-
}
|
492
|
-
}
|
589
|
+
File.open(gz_file, "wb") do |dest|
|
590
|
+
gz = ::Zlib::GzipWriter.new(dest, Zlib::BEST_COMPRESSION)
|
591
|
+
gz.mtime = mtime.to_i
|
592
|
+
IO.copy_stream(open(file), gz)
|
593
|
+
gz.close
|
594
|
+
end
|
493
595
|
|
494
|
-
|
495
|
-
|
496
|
-
|
596
|
+
File.utime(mtime, mtime, gz_file)
|
597
|
+
|
598
|
+
gz_file
|
497
599
|
end
|
498
600
|
|
499
|
-
def
|
500
|
-
|
601
|
+
def write_tmp(name, content)
|
602
|
+
path = File.join(config[:temp], name)
|
603
|
+
FileUtils.mkdir_p(File.dirname(path))
|
604
|
+
write_file path, content
|
605
|
+
path
|
606
|
+
end
|
501
607
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
608
|
+
def read_tmp(name)
|
609
|
+
path = File.join(config[:temp], name)
|
610
|
+
if File.exist? path
|
611
|
+
File.read path
|
612
|
+
else
|
613
|
+
''
|
614
|
+
end
|
615
|
+
end
|
507
616
|
|
508
|
-
|
509
|
-
|
617
|
+
def log_path(path)
|
618
|
+
File.expand_path(path).sub(config[:pwd], '').sub(/^\//,'')
|
619
|
+
end
|
510
620
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
621
|
+
def write_file(path, contents)
|
622
|
+
FileUtils.mkdir_p(File.expand_path(File.dirname(path)))
|
623
|
+
File.open(path, 'w') do |io|
|
624
|
+
io.write(contents)
|
625
|
+
end
|
626
|
+
end
|
515
627
|
|
516
|
-
|
517
|
-
|
518
|
-
|
628
|
+
def key_id(keys)
|
629
|
+
keys.map do |key|
|
630
|
+
(key == '.') ? 'symbols' : classname(key)
|
631
|
+
end.join('-')
|
519
632
|
end
|
520
633
|
|
634
|
+
# Determine if an NPM module is installed by checking paths with `npm bin`
|
635
|
+
# Returns path to binary if installed
|
521
636
|
def find_node_module(cmd)
|
522
637
|
require 'open3'
|
523
638
|
|
524
|
-
|
639
|
+
return @modules[cmd] unless @modules[cmd].nil?
|
525
640
|
|
526
|
-
|
527
|
-
|
528
|
-
"$(npm bin)/#{cmd}"
|
641
|
+
@modules[cmd] = begin
|
642
|
+
local = "$(npm bin)/#{cmd}"
|
643
|
+
global = "$(npm -g bin)/#{cmd}"
|
529
644
|
|
530
|
-
|
531
|
-
|
532
|
-
|
645
|
+
if Open3.capture3(local)[2].success?
|
646
|
+
local
|
647
|
+
elsif Open3.capture3(global)[2].success?
|
648
|
+
global
|
649
|
+
else
|
650
|
+
false
|
651
|
+
end
|
533
652
|
end
|
534
653
|
end
|
535
654
|
|
@@ -539,5 +658,43 @@ if(typeof(module) != 'undefined') { module.exports = esvg }
|
|
539
658
|
h
|
540
659
|
end
|
541
660
|
|
661
|
+
# Return non-empty key names for groups of svgs
|
662
|
+
def valid_keys(keys)
|
663
|
+
if keys.nil? || keys.empty?
|
664
|
+
svg_symbols.keys
|
665
|
+
else
|
666
|
+
keys = [keys].flatten.map { |k| dasherize k }
|
667
|
+
svg_symbols.keys.select { |k| keys.include? dasherize(k) }
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
# Load aliases from configuration.
|
672
|
+
# returns a hash of aliasees mapped to a name.
|
673
|
+
# Converts configuration YAML:
|
674
|
+
# alias:
|
675
|
+
# foo: bar
|
676
|
+
# baz: zip, zop
|
677
|
+
# To output:
|
678
|
+
# { :bar => "foo", :zip => "baz", :zop => "baz" }
|
679
|
+
#
|
680
|
+
def load_aliases(aliases)
|
681
|
+
a = {}
|
682
|
+
aliases.each do |name,alternates|
|
683
|
+
alternates.split(',').each do |val|
|
684
|
+
a[dasherize(val.strip).to_sym] = dasherize(name.to_s)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
a
|
688
|
+
end
|
689
|
+
|
690
|
+
def get_alias(name)
|
691
|
+
config[:aliases][dasherize(name).to_sym] || name
|
692
|
+
end
|
693
|
+
|
694
|
+
def production?
|
695
|
+
config[:produciton] || if Esvg.rails?
|
696
|
+
Rails.env.production?
|
697
|
+
end
|
698
|
+
end
|
542
699
|
end
|
543
700
|
end
|
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: 4.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: 2017-05-
|
11
|
+
date: 2017-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|