1
1
/**
2
2
* Svg loading plugin.
3
3
*
4
- * This plugins loads SVG files and merges them into one SVG sprite
4
+ * This plugin loads an svg graphic and defines it in the DOM, so you can reference it in a `<use>` tag.
5
5
*
6
6
* @example :
7
7
* To load the svg file `myicons/myicon.svg`:
8
8
* ```
9
- * require(["requirejs-dplugins/svg!myicons/myicon.svg"], function (){
10
- * // myicon was added to the sprite
9
+ * require(["requirejs-dplugins/svg!myicons/myicon.svg"], function (myiconId ){
10
+ * // myicon was added to the DOM
11
11
* });
12
12
* ```
13
13
* @module requirejs-dplugins/svg
16
16
define ( [
17
17
"./has" ,
18
18
"./Promise!" ,
19
- "module"
20
- ] , function ( has , Promise , module ) {
19
+ "module" ,
20
+ "require" ,
21
+ "requirejs-text/text" ,
22
+ "requirejs-domready/domReady"
23
+ ] , function ( has , Promise , module , localRequire , textPlugin ) {
21
24
"use strict" ;
22
25
23
- var cache = { } , // paths of loaded svgs
26
+ var loaded = { } , // paths of loaded svgs
24
27
SPRITE_ID = 'requirejs-dplugins-svg' ,
25
28
sprite = null ;
26
29
@@ -31,47 +34,43 @@ define([
31
34
/**
32
35
* Loads an svg file.
33
36
* @param {string } path - The svg file to load.
34
- * @param {Function } require - A local require function to use to load other modules .
37
+ * @param {Function } resourceRequire - A require function local to the module calling the svg plugin .
35
38
* @param {Function } onload - A function to call when the specified svg file have been loaded.
36
39
* @method
37
40
*/
38
- load : function ( path , require , onload ) {
41
+ load : function ( path , resourceRequire , onload ) {
39
42
if ( has ( "builder" ) ) { // when building
40
- cache [ path ] = true ;
43
+ loaded [ path ] = true ;
41
44
onload ( ) ;
42
45
} else { // when running
43
-
44
46
// special case: when running a built version
45
47
// Replace graphic by corresponding sprite.
48
+ var idInLayer ;
46
49
var layersMap = module . config ( ) . layersMap ;
47
- if ( layersMap ) {
48
- path = layersMap [ path ] || path ;
50
+ if ( layersMap && layersMap [ path ] ) {
51
+ idInLayer = layersMap [ path ] . id ;
52
+ path = layersMap [ path ] . redirectTo ;
49
53
}
50
54
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 ) ;
55
+ if ( ! ( path in loaded ) ) {
56
+ loaded [ path ] = new Promise ( function ( resolve ) {
57
+ localRequire ( [ "requirejs-domready/domReady!" ] , function ( ) {
58
+ textPlugin . load ( path , resourceRequire , function ( svgText ) {
59
+ if ( ! sprite ) {
60
+ sprite = createSprite ( document , SPRITE_ID ) ;
61
+ document . body . appendChild ( sprite ) ;
62
+ }
63
+ var symbol = extractGraphicAsSymbol ( document , svgText ) ;
64
+ sprite . appendChild ( symbol ) ;
65
+ resolve ( symbol . getAttribute ( "id" ) ) ;
66
+ } ) ;
68
67
} ) ;
69
68
} ) ;
70
-
71
- cache [ path ] . then ( function ( graphic ) {
72
- onload ( graphic . id ) ;
73
- } ) ;
74
69
}
70
+
71
+ loaded [ path ] . then ( function ( symbolId ) {
72
+ onload ( idInLayer || symbolId ) ;
73
+ } ) ;
75
74
}
76
75
}
77
76
} ;
@@ -89,8 +88,8 @@ define([
89
88
* config: {
90
89
* "requirejs-dplugins/svg": {
91
90
* layersMap: {
92
- * "file1.svg": "path/to/layer.svg",
93
- * "file2.svg": "path/to/layer.svg"
91
+ * "file1.svg": {redirectTo: "path/to/layer.svg", id: "id-inside-file-1"} ,
92
+ * "file2.svg": {redirectTo: "path/to/layer.svg", id: "id-inside-file-2"}
94
93
* }
95
94
* }
96
95
* }
@@ -101,19 +100,19 @@ define([
101
100
* and writes it to the modules layer.
102
101
* @param {string } mid - Current module id.
103
102
* @param {string } dest - Current svg sprite path.
104
- * @param {Array } loadList - List of svg files contained in current sprite.
103
+ * @param {Array } loaded - Maps the paths of the svg files contained in current sprite to their ids .
105
104
*/
106
- writeConfig : function ( write , mid , destMid , loadList ) {
105
+ writeConfig : function ( write , mid , destMid , loaded ) {
107
106
var svgConf = {
108
107
config : { } ,
109
108
paths : { }
110
109
} ;
111
110
svgConf . config [ mid ] = {
112
111
layersMap : { }
113
112
} ;
114
- loadList . forEach ( function ( path ) {
115
- svgConf . config [ mid ] . layersMap [ path ] = destMid ;
116
- } ) ;
113
+ for ( var path in loaded ) {
114
+ svgConf . config [ mid ] . layersMap [ path ] = { redirectTo : destMid , id : loaded [ path ] } ;
115
+ }
117
116
118
117
write ( "require.config(" + JSON . stringify ( svgConf ) + ");" ) ;
119
118
} ,
@@ -124,84 +123,101 @@ define([
124
123
* @param {Function } writePluginFiles - The write function provided by the builder to `writeFile`.
125
124
* and writes it to the modules layer.
126
125
* @param {string } dest - Current svg sprite path.
127
- * @param {Array } loadList - List of svg files contained in current sprite.
126
+ * @param {Array } loaded - Maps the paths of the svg files contained in current sprite to their ids .
128
127
*/
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 ) ;
128
+ writeLayer : function ( writePluginFiles , dest , loaded ) {
129
+ function tryRequire ( paths ) {
130
+ var module ;
131
+ var path = paths . shift ( ) ;
132
+ if ( path ) {
133
+ try {
134
+ // This is a node-require so it is synchronous.
135
+ module = require . nodeRequire ( path ) ;
136
+ } catch ( e ) {
137
+ if ( e . code === "MODULE_NOT_FOUND" ) {
138
+ return tryRequire ( paths ) ;
139
+ } else {
140
+ throw e ;
141
+ }
142
+ }
143
+ }
144
+ return module ;
145
+ }
135
146
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
- } ) ;
147
+ var fs = require . nodeRequire ( "fs" ) ,
148
+ jsDomPath = require . getNodePath ( require . toUrl ( module . id ) . replace ( / [ ^ \/ ] * $ / , "node_modules/jsdom" ) ) ,
149
+ jsDomModule = tryRequire ( [ jsDomPath , "jsdom" ] ) ;
150
+
151
+ var path , url , svgText ;
152
+ if ( ! jsDomModule ) {
153
+ console . log ( ">> WARNING: Node module jsdom not found. Skipping SVG bundling. If you" +
154
+ " want SVG bundling run 'npm install jsdom' in your console." ) ;
155
+ for ( path in loaded ) {
156
+ url = require . toUrl ( path ) ;
157
+ svgText = fs . readFileSync ( url , "utf8" ) ;
158
+ writePluginFiles ( url , svgText ) ;
159
+ }
160
+ return false ;
161
+ } else {
162
+ var jsdom = jsDomModule . jsdom ,
163
+ document = jsdom ( "<html></html>" ) ,
164
+ sprite = createSprite ( document ) ;
165
+
166
+ for ( path in loaded ) {
167
+ url = require . toUrl ( path ) ;
168
+ svgText = fs . readFileSync ( url , "utf8" ) ;
169
+ var symbol = extractGraphicAsSymbol ( document , svgText ) ;
170
+ sprite . appendChild ( symbol ) ;
171
+ loaded [ path ] = symbol . getAttribute ( "id" ) ;
172
+ }
143
173
144
- writePluginFiles ( dest , sprite . outerHTML ) ;
174
+ writePluginFiles ( dest , sprite . outerHTML ) ;
175
+ return true ;
176
+ }
145
177
}
146
178
} ;
147
179
148
-
149
180
loadSVG . writeFile = function ( pluginName , resource , require , write ) {
150
181
writePluginFiles = write ;
151
182
} ;
152
183
153
- loadSVG . addModules = function ( pluginName , resource , addModules ) {
154
- addModules ( [ "requirejs-text/text" ] ) ;
155
- } ;
156
-
157
184
loadSVG . onLayerEnd = function ( write , layer ) {
158
185
if ( layer . name && layer . path ) {
159
186
var dest = layer . path . replace ( / ^ ( .* \/ ) ? ( .* ) .j s $ / , "$1/$2.svg" ) ,
160
187
destMid = layer . name + ".svg" ;
161
188
162
- var loadList = Object . keys ( cache ) ;
163
-
164
189
// Write layer file and config
165
- buildFunctions . writeLayer ( writePluginFiles , dest , loadList ) ;
166
- buildFunctions . writeConfig ( write , module . id , destMid , loadList ) ;
190
+ var success = buildFunctions . writeLayer ( writePluginFiles , dest , loaded ) ;
191
+ success && buildFunctions . writeConfig ( write , module . id , destMid , loaded ) ;
167
192
168
193
// Reset cache
169
- cache = { } ;
194
+ loaded = { } ;
170
195
}
171
196
} ;
172
197
173
198
}
174
199
175
200
return loadSVG ;
176
201
177
-
178
- // takes a path and returns the filename
179
- function getFilename ( filepath ) {
180
- return filepath . replace ( / .* \/ ( .* ) \. s v g $ / , "$1" ) ;
181
- }
182
-
183
202
// makes a symbol out of an svg graphic
184
- function extractGraphic ( document , svgText , filename ) {
203
+ function extractGraphicAsSymbol ( document , svgText ) {
185
204
var div = document . createElement ( "div" ) ;
186
205
div . innerHTML = svgText ;
187
206
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
- } ;
207
+ id = element . getAttribute ( "id" ) ,
208
+ viewBox = element . getAttribute ( "viewbox" ) || element . getAttribute ( "viewBox" ) ,
209
+ symbol = createSymbol ( document , id , element , viewBox ) ;
210
+ return symbol ;
195
211
}
196
212
197
213
// makes symbol from svg element
198
214
function createSymbol ( document , id , element , viewBox ) {
199
215
var symbol = document . createElementNS ( "http://www.w3.org/2000/svg" , "symbol" ) ;
200
- symbol . setAttribute ( "id" , id ) ;
201
216
while ( element . firstChild ) {
202
217
symbol . appendChild ( element . firstChild ) ;
203
218
}
204
- viewBox && symbol . setAttribute ( "viewBox" , viewBox ) ;
219
+ typeof id === "string" && symbol . setAttribute ( "id" , id ) ;
220
+ typeof viewBox === "string" && symbol . setAttribute ( "viewBox" , viewBox ) ;
205
221
return symbol ;
206
222
}
207
223
0 commit comments