Skip to content

Commit e76c16d

Browse files
Youcef Mammarclmath
authored andcommitted
Add a plugin to load svg files
1 parent 6f6a065 commit e76c16d

File tree

16 files changed

+485
-4
lines changed

16 files changed

+485
-4
lines changed

Gruntfile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ module.exports = function (grunt) {
7676

7777

7878
// By default, lint and run all tests.
79-
grunt.registerTask("default", ["jsbeautifier", "lineending", "jshint", "test:remote"]);
79+
grunt.registerTask("default", ["jshint", "test:remote"]);
8080

8181
// Just lint
82-
grunt.registerTask("lint", ["jsbeautifier", "lineending", "jshint"]);
82+
grunt.registerTask("lint", ["jshint"]);
8383

8484
// Travis build
8585
grunt.registerTask("travis", ["jshint", "test:remote"]);

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Set of AMD plugins for RequireJS. It contains the following plugins:
88
* [jquery](#jquery)
99
* [maybe](#maybe)
1010
* [Promise](#promise)
11+
* [svg](#svg)
1112

1213
## Status
1314

@@ -70,3 +71,7 @@ This plugin provides an ES6 Promise implementation. If the browser does not prov
7071

7172
See [docs/Promise.md](./docs/Promose.md) for documentation.
7273

74+
## svg
75+
This plugins provide an API for loading and bundling svg graphics.
76+
77+
See [docs/svg.md](./docs/svg.md) for documentation.

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"description": "AMD plugins for RequireJS",
55
"dependencies": {
66
"lie": ">=2.8",
7-
"requirejs": "2.1.x"
7+
"requirejs": "2.1.x",
8+
"requirejs-text": "2.0.x"
89
},
910
"devDependencies": {
1011
"jquery": ">=2.1"

docs/svg.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
layout: doc
3+
title: requirejs-dplugins/svg
4+
---
5+
6+
# requirejs-dplugins/svg!
7+
8+
This plugin load svg graphics and declares them in one sprite. This sprite is automatically added to your DOM, so that you can reference included graphics in a `<use>` tag.
9+
10+
## Example
11+
12+
```js
13+
define([
14+
"requirejs-dplugins/svg!./icon1.svg",
15+
"requirejs-dplugins/svg!./icon2.svg"
16+
], function(id1, id2){
17+
// id1 === "icon1" and id2 === "icon2"
18+
})
19+
```
20+
21+
This will fetch `icon1.svg` and `icon2.svg` and add two symbols to the sprite.
22+
```svg
23+
<svg>
24+
...
25+
<symbol id="icon1" viewBox="..." > ... </symbol>
26+
<symbol id="icon2" viewBox="..." > ... </symbol>
27+
</svg>
28+
```
29+
30+
You can then use the icons anytime only with
31+
32+
```
33+
<svg>
34+
<use xlink:href="#icon1"></use>
35+
</svg>
36+
```
37+
38+
If the first `<svg>` tag of your graphic holds an `id` attribute, this id will be used as the reference. Otherwise, the name of the file is used.
39+
40+
## Build
41+
The build step will merge all graphics in one sprite beforehand and save the result in a `<layer>.svg`.
42+
When running the built version, this sprite is fetched as soon as one of the graphic inside is required.
43+
44+
45+
## Creating graphics that work well with this plugin
46+
47+
To work properly, your graphic should include a `viewBox` attribute. The `id` is optional.
48+
As an example, here is the minimal markup your graphic should include:
49+
50+
```svg
51+
<svg id="my-graphic" viewBox="0 0 80 120"> ... </svg>
52+
```
53+

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"grunt-jsbeautifier": "~0.2.2",
1010
"requirejs": "~2.1.10",
1111
"intern": "2.1.x",
12-
"grunt-lineending": "^0.2.2"
12+
"grunt-lineending": "^0.2.2",
13+
"jsdom": "^3.1.2"
1314
},
1415
"licenses": [
1516
{

samples/svg.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Svg</title>
5+
6+
<script type="text/javascript" src="../../requirejs/require.js"></script>
7+
8+
<script type="text/javascript">
9+
require.config({
10+
baseUrl: "..",
11+
paths: {
12+
'requirejs-text': '../requirejs-text/'
13+
}
14+
});
15+
require([
16+
"svg!./samples/svg/add.svg",
17+
"svg!./samples/svg/download.svg"
18+
]);
19+
</script>
20+
</head>
21+
<body>
22+
23+
<svg>
24+
<use xlink:href="#add"></use>
25+
</svg>
26+
<svg>
27+
<use xlink:href="#download"></use>
28+
</svg>
29+
30+
</body>
31+
</html>

samples/svg/add.svg

Lines changed: 11 additions & 0 deletions
Loading

samples/svg/download.svg

Lines changed: 10 additions & 0 deletions
Loading

svg.js

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/**
2+
* Svg loading plugin.
3+
*
4+
* This plugins loads SVG files and merges them into one SVG sprite
5+
*
6+
* @example:
7+
* To load the svg file `myicons/myicon.svg`:
8+
* ```
9+
* require(["requirejs-dplugins/svg!myicons/myicon.svg"], function (){
10+
* // myicon was added to the sprite
11+
* });
12+
* ```
13+
* @module requirejs-dplugins/svg
14+
*/
15+
16+
define([
17+
"./has",
18+
"./Promise!",
19+
"module"
20+
], function (has, Promise, module) {
21+
"use strict";
22+
23+
var cache = {}, // paths of loaded svgs
24+
SPRITE_ID = 'requirejs-dplugins-svg',
25+
sprite = null;
26+
27+
28+
var loadSVG = {
29+
id: module.id,
30+
31+
/**
32+
* Loads an svg file.
33+
* @param {string} path - The svg file to load.
34+
* @param {Function} require - A local require function to use to load other modules.
35+
* @param {Function} onload - A function to call when the specified svg file have been loaded.
36+
* @method
37+
*/
38+
load: function (path, require, onload) {
39+
if (has("builder")) { // when building
40+
cache[path] = true;
41+
onload();
42+
} else { // when running
43+
44+
// special case: when running a built version
45+
// Replace graphic by corresponding sprite.
46+
var layersMap = module.config().layersMap;
47+
if (layersMap) {
48+
path = layersMap[path] || path;
49+
}
50+
51+
var filename = getFilename(path);
52+
if (path in cache) {
53+
cache[path].then(function (graphic) {
54+
onload(graphic.id);
55+
});
56+
} else {
57+
if (!sprite) {
58+
sprite = createSprite(document, SPRITE_ID);
59+
document.body.appendChild(sprite);
60+
}
61+
cache[path] = new Promise(function (resolve) {
62+
require(['requirejs-text/text!' + path], function (svgText) {
63+
var graphic = extractGraphic(document, svgText, filename),
64+
symbol = createSymbol(document, graphic.id, graphic.element, graphic.viewBox);
65+
sprite.appendChild(symbol);
66+
cache[path] = graphic.id;
67+
resolve(graphic);
68+
});
69+
});
70+
71+
cache[path].then(function (graphic) {
72+
onload(graphic.id);
73+
});
74+
}
75+
}
76+
}
77+
};
78+
79+
if (has("builder")) {
80+
// build variables
81+
var writePluginFiles;
82+
83+
var buildFunctions = {
84+
/**
85+
* Writes the layersMap configuration to the corresponding modules layer.
86+
* The configuration will look like this:
87+
* ```js
88+
* require.config({
89+
* config: {
90+
* "requirejs-dplugins/svg": {
91+
* layersMap: {
92+
* "file1.svg": "path/to/layer.svg",
93+
* "file2.svg": "path/to/layer.svg"
94+
* }
95+
* }
96+
* }
97+
* });
98+
* ```
99+
*
100+
* @param {Function} write - This function takes a string as argument
101+
* and writes it to the modules layer.
102+
* @param {string} mid - Current module id.
103+
* @param {string} dest - Current svg sprite path.
104+
* @param {Array} loadList - List of svg files contained in current sprite.
105+
*/
106+
writeConfig: function (write, mid, destMid, loadList) {
107+
var svgConf = {
108+
config: {},
109+
paths: {}
110+
};
111+
svgConf.config[mid] = {
112+
layersMap: {}
113+
};
114+
loadList.forEach(function (path) {
115+
svgConf.config[mid].layersMap[path] = destMid;
116+
});
117+
118+
write("require.config(" + JSON.stringify(svgConf) + ");");
119+
},
120+
121+
/**
122+
* Concatenates all svg files required by a modules layer and write the result.
123+
*
124+
* @param {Function} writePluginFiles - The write function provided by the builder to `writeFile`.
125+
* and writes it to the modules layer.
126+
* @param {string} dest - Current svg sprite path.
127+
* @param {Array} loadList - List of svg files contained in current sprite.
128+
*/
129+
writeLayer: function (writePluginFiles, dest, loadList) {
130+
var fs = require.nodeRequire("fs"),
131+
jsdom = require.nodeRequire("jsdom").jsdom;
132+
133+
var document = jsdom("<html></html>").parentWindow.document;
134+
var sprite = createSprite(document);
135+
136+
loadList.forEach(function (path) {
137+
var filename = getFilename(path),
138+
svgText = fs.readFileSync(require.toUrl(path), "utf8"),
139+
graphic = extractGraphic(document, svgText, filename),
140+
symbol = createSymbol(document, graphic.id, graphic.element, graphic.viewBox);
141+
sprite.appendChild(symbol);
142+
});
143+
144+
writePluginFiles(dest, sprite.outerHTML);
145+
}
146+
};
147+
148+
149+
loadSVG.writeFile = function (pluginName, resource, require, write) {
150+
writePluginFiles = write;
151+
};
152+
153+
loadSVG.addModules = function (pluginName, resource, addModules) {
154+
addModules(["requirejs-text/text"]);
155+
};
156+
157+
loadSVG.onLayerEnd = function (write, layer) {
158+
if (layer.name && layer.path) {
159+
var dest = layer.path.replace(/^(.*\/)?(.*).js$/, "$1/$2.svg"),
160+
destMid = layer.name + ".svg";
161+
162+
var loadList = Object.keys(cache);
163+
164+
// Write layer file and config
165+
buildFunctions.writeLayer(writePluginFiles, dest, loadList);
166+
buildFunctions.writeConfig(write, module.id, destMid, loadList);
167+
168+
// Reset cache
169+
cache = {};
170+
}
171+
};
172+
173+
}
174+
175+
return loadSVG;
176+
177+
178+
// takes a path and returns the filename
179+
function getFilename(filepath) {
180+
return filepath.replace(/.*\/(.*)\.svg$/, "$1");
181+
}
182+
183+
// makes a symbol out of an svg graphic
184+
function extractGraphic(document, svgText, filename) {
185+
var div = document.createElement("div");
186+
div.innerHTML = svgText;
187+
var element = div.querySelector("svg"),
188+
id = element.getAttribute("id") || filename,
189+
viewBox = element.getAttribute("viewbox") || element.getAttribute("viewBox") || "";
190+
return {
191+
id: id,
192+
viewBox: viewBox,
193+
element: element
194+
};
195+
}
196+
197+
// makes symbol from svg element
198+
function createSymbol(document, id, element, viewBox) {
199+
var symbol = document.createElementNS("http://www.w3.org/2000/svg", "symbol");
200+
symbol.setAttribute("id", id);
201+
while (element.firstChild) {
202+
symbol.appendChild(element.firstChild);
203+
}
204+
viewBox && symbol.setAttribute("viewBox", viewBox);
205+
return symbol;
206+
}
207+
208+
// creates empty sprite
209+
function createSprite(document, id) {
210+
var sprite = document.createElementNS("http://www.w3.org/2000/svg", "svg");
211+
sprite.setAttribute("style", "display: none");
212+
id && sprite.setAttribute("id", id);
213+
return sprite;
214+
}
215+
});

tests/unit/all.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Listing of all the plugin unit tests
22
define([
3+
"./svg",
34
"./css",
45
"./has",
56
"./i18n",

0 commit comments

Comments
 (0)