jekyll-inline-svg 0.0.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +17 -0
- data/jekyll-inline-svg.gemspec +1 -1
- data/lib/jekyll-inline-svg.rb +59 -18
- data/spec/fixtures/_config.yml +0 -5
- data/spec/fixtures/files/square.svg +1 -0
- data/spec/fixtures/index.html +10 -0
- data/spec/jekyll-inline-svg_spec.rb +67 -43
- 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: 5f7ec02900a1781590f77c085955e691f67c2413
|
4
|
+
data.tar.gz: c85d53a5af01ba620036633997fbf3573143650d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e07e67d5aaf9eb24629a31dbaaa9b76e4224c8b6ef517967944fe1b784aff9180deb4d09d0542b9852d4a6f69104dda173d722e8b76628b051c0fac846a80f1d
|
7
|
+
data.tar.gz: 7c82653e38eaafd4f2dba396e8bc09fd06154318d14cc7609125d9cb9c077d564a051fb0ecbd5f8b6f6d89add676f942810b9bdd1c5e3dacf06d9a9043d5f984
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -15,6 +15,13 @@ gems:
|
|
15
15
|
- jekyll-inline-svg
|
16
16
|
```
|
17
17
|
|
18
|
+
Optimization is opt-in and can be enabled by adding this to your `_config.yml`
|
19
|
+
|
20
|
+
```
|
21
|
+
svg:
|
22
|
+
optimize: true
|
23
|
+
```
|
24
|
+
|
18
25
|
## Usage
|
19
26
|
|
20
27
|
Use the Liquid tag in your pages :
|
@@ -48,6 +55,9 @@ Liquid variables will be interpreted if enclosed in double brackets :
|
|
48
55
|
{% assign size=40 %}
|
49
56
|
{% svg "/path/to/{{site.foo-name}}.svg" width="{{size}}" %}
|
50
57
|
```
|
58
|
+
`height` is automatically set to match `width` if omitted. It can't be left unset because IE11 won't use the viewport attribute to calculate the image's aspect ratio.
|
59
|
+
|
60
|
+
|
51
61
|
|
52
62
|
Relative paths and absolute paths will both be interpreted from Jekyll's configured [source directory](https://jekyllrb.com/docs/configuration/). So both :
|
53
63
|
|
@@ -74,3 +84,10 @@ Some processing is done to remove useless data :
|
|
74
84
|
If any important data gets removed, or the output SVG looks different from input, it's a bug. Please file an issue to this repository describing your problem.
|
75
85
|
|
76
86
|
It does not perform any input validation on attributes. They will be appended as-is to the root node.
|
87
|
+
|
88
|
+
## Motivations
|
89
|
+
|
90
|
+
This has been creeated specifically to display svg icons in html pages.
|
91
|
+
|
92
|
+
PNG/BMP sprites are clearly a no go in a world where "a screen" can be anything from 4" to 150", ranging from 480p to 4k. So what are our vector alternatives?
|
93
|
+
Font-icons are [bad](https://cloudfour.com/thinks/seriously-dont-use-icon-fonts/). While **xlink** looks like an ideal solution, with an elegant : `<use xlink:href="/path/to/icons.svg#play"></use>`, it's badly supported in IE (up to ie11). And embedding SVGs in an `<img>` is not going to cut it. Inlined SVG icons, in my opinion, is the best option we got right now. It's also where the industry seems to be going, with big actors like [github](https://github.com/blog/2112-delivering-octicons-with-svg) starting to transition from font-icons to inlined SVG.
|
data/jekyll-inline-svg.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
A Liquid tag to inline and optimize SVG images in your HTML
|
8
8
|
Supports custom DOM Attributes parameters and variables interpretation.
|
9
9
|
EOF
|
10
|
-
spec.version = "0.0
|
10
|
+
spec.version = "1.0.0"
|
11
11
|
spec.authors = ["Sebastien DUMETZ"]
|
12
12
|
spec.email = "s.dumetz@holusion.com"
|
13
13
|
spec.homepage = "https://github.com/sdumetz/jekyll-inline-svg"
|
data/lib/jekyll-inline-svg.rb
CHANGED
@@ -1,21 +1,14 @@
|
|
1
|
+
require "nokogiri"
|
1
2
|
require 'svg_optimizer'
|
2
3
|
require 'jekyll/liquid_extensions'
|
3
|
-
|
4
|
-
# remove "width" and "height" attributes
|
5
|
-
def process
|
6
|
-
xml.root.remove_attribute("height")
|
7
|
-
xml.root.remove_attribute("width")
|
8
|
-
end
|
9
|
-
end
|
4
|
+
|
10
5
|
PLUGINS_BLACKLIST = [
|
11
6
|
SvgOptimizer::Plugins::CleanupId,
|
12
7
|
]
|
13
8
|
|
14
9
|
PLUGINS = SvgOptimizer::DEFAULT_PLUGINS.delete_if {|plugin|
|
15
10
|
PLUGINS_BLACKLIST.include? plugin
|
16
|
-
}
|
17
|
-
RemoveSize
|
18
|
-
]
|
11
|
+
}
|
19
12
|
|
20
13
|
|
21
14
|
module Jekyll
|
@@ -33,10 +26,13 @@ module Jekyll
|
|
33
26
|
^(?<path>[^\s"']+|"[^"]*"|'[^']*')
|
34
27
|
(?<params>.*)
|
35
28
|
!x
|
29
|
+
PARAM_SYNTAX= %r!
|
30
|
+
([\w-]+)\s*=\s*
|
31
|
+
(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))
|
32
|
+
!x
|
36
33
|
|
37
34
|
def initialize(tag_name, input, tokens)
|
38
35
|
super
|
39
|
-
|
40
36
|
@svg, @params = JekyllInlineSvg.parse_params(input)
|
41
37
|
end
|
42
38
|
|
@@ -47,23 +43,68 @@ module Jekyll
|
|
47
43
|
end
|
48
44
|
markup
|
49
45
|
end
|
50
|
-
|
46
|
+
def split_params(markup, context)
|
47
|
+
params={}
|
48
|
+
while (match = PARAM_SYNTAX.match(markup))
|
49
|
+
markup = markup[match.end(0)..-1]
|
50
|
+
value = if match[2]
|
51
|
+
interpolate(match[2].gsub(%r!\\"!, '"'), context)
|
52
|
+
elsif match[3]
|
53
|
+
interpolate(match[3].gsub(%r!\\'!, "'"),context)
|
54
|
+
elsif match[4]
|
55
|
+
lookup_variable(context, match[4])
|
56
|
+
end
|
57
|
+
params[match[1]] = value
|
58
|
+
end
|
59
|
+
return params
|
60
|
+
end
|
51
61
|
#Parse parameters. Returns : [svg_path, parameters]
|
52
62
|
# Does not interpret variables as it's done at render time
|
53
63
|
def self.parse_params(input)
|
54
64
|
matched = input.strip.match(PATH_SYNTAX)
|
55
|
-
|
65
|
+
path = matched["path"].gsub("\"","").gsub("'","").strip
|
66
|
+
markup = matched["params"].strip
|
67
|
+
return path, markup
|
68
|
+
end
|
69
|
+
def fmt(params)
|
70
|
+
r = params.to_a.select{|v| v[1] != ""}.map {|v| %!#{v[0]}="#{v[1]}"!}
|
71
|
+
r.join(" ")
|
72
|
+
end
|
73
|
+
def create_plugin(params)
|
74
|
+
mod = Class.new(SvgOptimizer::Plugins::Base) do
|
75
|
+
def self.set (p)
|
76
|
+
@@params = p
|
77
|
+
end
|
78
|
+
def process
|
79
|
+
@@params.each {|key,val| xml.root.set_attribute(key,val)}
|
80
|
+
return xml
|
81
|
+
end
|
82
|
+
end
|
83
|
+
mod.set(params)
|
84
|
+
return mod
|
56
85
|
end
|
57
86
|
def render(context)
|
58
87
|
#global site variable
|
59
88
|
site = context.registers[:site]
|
60
89
|
#check if given name is a variable. Otherwise use it as a file name
|
61
90
|
svg_file = Jekyll.sanitized_path(site.source, interpolate(@svg,context))
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
91
|
+
#replace variables with their current value
|
92
|
+
params = split_params(@params,context)
|
93
|
+
#because ie11 require to have a height AND a width
|
94
|
+
if params.key? "width" and ! params.key? "height"
|
95
|
+
params["height"] = params["width"]
|
96
|
+
end
|
97
|
+
#params = @params
|
98
|
+
file = File.open(svg_file, "rb").read
|
99
|
+
conf = lookup_variable(context,"site.svg")
|
100
|
+
if conf["optimize"] == true
|
101
|
+
xml = SvgOptimizer.optimize(file, [create_plugin(params)] + PLUGINS)
|
102
|
+
else
|
103
|
+
xml = Nokogiri::XML(file)
|
104
|
+
params.each {|key,val| xml.root.set_attribute(key,val)}
|
105
|
+
xml = xml.to_xml
|
106
|
+
end
|
107
|
+
return xml
|
67
108
|
end
|
68
109
|
end
|
69
110
|
end
|
data/spec/fixtures/_config.yml
CHANGED
data/spec/fixtures/index.html
CHANGED
@@ -7,6 +7,12 @@ Hello world
|
|
7
7
|
{% svg files/square.svg %}
|
8
8
|
</div>
|
9
9
|
|
10
|
+
<div id="height">
|
11
|
+
{% svg files/square.svg width=24 %}
|
12
|
+
{% svg files/square.svg width=24 height=48 %}
|
13
|
+
{% svg files/square.svg width=24 height="" %}
|
14
|
+
</div>
|
15
|
+
|
10
16
|
<div id="path">
|
11
17
|
<label>Resolve relative and absolute paths to site's source</label>
|
12
18
|
{% svg files/square.svg %}
|
@@ -24,3 +30,7 @@ Hello world
|
|
24
30
|
{% svg /files/{{page.svgname}}.svg %}
|
25
31
|
{% svg /files/square.svg id="name-{{page.svgname}}" class="class-{{page.svgclass}}" %}
|
26
32
|
</div>
|
33
|
+
|
34
|
+
<div id="optimize">
|
35
|
+
{% svg /files/{{page.svgname}}.svg data-foo="" %}
|
36
|
+
</div>
|
@@ -45,50 +45,74 @@ describe(Jekyll::Tags::JekyllInlineSvg) do
|
|
45
45
|
expect(params).to eq("id='bar' style=\"hello\"")
|
46
46
|
end
|
47
47
|
end
|
48
|
+
[
|
49
|
+
Jekyll.configuration({
|
50
|
+
"source" => source_dir,
|
51
|
+
"destination" => dest_dir,
|
52
|
+
"url" => "http://example.org",
|
53
|
+
}),
|
54
|
+
Jekyll.configuration({
|
55
|
+
"source" => source_dir,
|
56
|
+
"destination" => dest_dir,
|
57
|
+
"url" => "http://example.org",
|
58
|
+
"svg" => { "optimize" => true}
|
59
|
+
})
|
60
|
+
].each do |config|
|
61
|
+
is_opt = config["svg"] and config["svg"]["optimize"] == true
|
62
|
+
describe "Integration (with #{is_opt ? "" : "no"} optimisation)" do
|
63
|
+
before(:context) do
|
64
|
+
site = Jekyll::Site.new(config)
|
65
|
+
site.process
|
66
|
+
@data = parse("index.html")
|
67
|
+
@base = @data.css("#base").css("svg").first
|
68
|
+
end
|
69
|
+
it "render site" do
|
70
|
+
expect(File.exist?(dest_dir("index.html"))).to be_truthy
|
71
|
+
end
|
72
|
+
it "exports svg" do
|
73
|
+
data = @data.xpath("//svg")
|
74
|
+
expect(data).to be_truthy
|
75
|
+
expect(data.first).to be_truthy
|
76
|
+
expect(@base).to be_truthy
|
77
|
+
# Do not strip other width and height attributes
|
78
|
+
end
|
79
|
+
it "add a height if only width is given" do
|
80
|
+
data = @data.css("#height").css("svg")
|
81
|
+
expect(data).to be_truthy
|
82
|
+
expect(data[0].get_attribute("height")).to eql("24")
|
83
|
+
expect(data[0].get_attribute("width")).to eql("24")
|
84
|
+
# do not set height if given
|
85
|
+
expect(data[1].get_attribute("height")).to eql("48")
|
86
|
+
expect(data[1].get_attribute("width")).to eql("24")
|
87
|
+
#do not set height if forced to empty string
|
88
|
+
expect(data[2].get_attribute("height")).to is_opt ? be_falsy : eql("")
|
48
89
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
data = @data.css("#path").css("svg")
|
76
|
-
expect(data.size).to eq(2)
|
77
|
-
expect(data[0].to_html).to eq(data[1].to_html) #should use to_xml?
|
78
|
-
end
|
79
|
-
it "jails to Jekyll source" do
|
80
|
-
data = @data.css("#jail").css("svg")
|
81
|
-
ref = @base.to_xml
|
82
|
-
expect(data.size).to eq(2)
|
83
|
-
data.each{ |item| expect(item.to_xml).to eql(ref) }
|
84
|
-
end
|
85
|
-
it "interpret variables" do
|
86
|
-
data = @data.css("#interpret").css("svg")
|
87
|
-
ref = @base.to_xml
|
88
|
-
expect(data.size).to eq(2)
|
89
|
-
expect(data[0].to_xml).to eql(ref)
|
90
|
-
expect(data[1].get_attribute("id")).to eql("name-square")
|
91
|
-
expect(data[1].get_attribute("class")).to eql("class-hello")
|
90
|
+
expect(data[2].get_attribute("width")).to eql("24")
|
91
|
+
end
|
92
|
+
it "parse relative paths" do
|
93
|
+
data = @data.css("#path").css("svg")
|
94
|
+
expect(data.size).to eq(2)
|
95
|
+
expect(data[0].to_html).to eq(data[1].to_html) #should use to_xml?
|
96
|
+
end
|
97
|
+
it "jails to Jekyll source" do
|
98
|
+
data = @data.css("#jail").css("svg")
|
99
|
+
ref = @base.to_xml
|
100
|
+
expect(data.size).to eq(2)
|
101
|
+
data.each{ |item| expect(item.to_xml).to eql(ref) }
|
102
|
+
end
|
103
|
+
it "interpret variables" do
|
104
|
+
data = @data.css("#interpret").css("svg")
|
105
|
+
ref = @base.to_xml
|
106
|
+
expect(data.size).to eq(2)
|
107
|
+
expect(data[0].to_xml).to eql(ref)
|
108
|
+
expect(data[1].get_attribute("id")).to eql("name-square")
|
109
|
+
expect(data[1].get_attribute("class")).to eql("class-hello")
|
110
|
+
end
|
111
|
+
it "#{is_opt ? "do" : "do not"} optimize" do
|
112
|
+
data = @data.css("#optimize").css("svg")
|
113
|
+
expect(data.first.get_attribute("data-foo")).to is_opt ? be_falsy : eql("")
|
114
|
+
expect(data.xpath("//comment()").first).to is_opt ? be_falsy : be_truthy
|
115
|
+
end
|
92
116
|
end
|
93
117
|
end
|
94
118
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-inline-svg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastien DUMETZ
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|