1 | 'use strict';
|
2 |
|
3 | const jdfUtils = require('jdf-utils');
|
4 | const $ = jdfUtils.base;
|
5 | const f = jdfUtils.file;
|
6 | const jdf = require('./jdf');
|
7 | const path = require('path');
|
8 | const Images = require('jdf-css-sprite');
|
9 | const logger = require('jdf-log');
|
10 | const vfs = require('./VFS/VirtualFileSystem');
|
11 |
|
12 | const cssSprite = module.exports = {};
|
13 |
|
14 | cssSprite.init = function() {
|
15 | logger.profile('css sprite');
|
16 | setTragetPath();
|
17 | logger.verbose(`cssSpriteMode: ${jdf.config.output.cssSpriteMode}`);
|
18 | if(jdf.config.output.cssSpriteMode == 0){
|
19 | cssSprite.overall(jdf.config.outputDirName);
|
20 | }
|
21 |
|
22 | if(jdf.config.output.cssSpriteMode == 1){
|
23 |
|
24 | vfs.queryFileByTargetType('css').forEach((item) => {
|
25 | item.targetContent = cssSprite.scatter(item.buildPath, item.targetContent, jdf.config.outputDirName);
|
26 | delete item.buildPath;
|
27 | });
|
28 | }
|
29 | logger.profile('css sprite');
|
30 | }
|
31 |
|
32 | function setTragetPath() {
|
33 |
|
34 | const cwd = process.cwd();
|
35 | vfs.queryFileByTargetType('css').forEach((file) => {
|
36 | let rp = $.pathJoin(path.relative(cwd, file.targetPath));
|
37 | file.buildPath = rp;
|
38 | logger.verbose(`css sprite: ${rp}`);
|
39 | });
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | cssSprite.overall = function(source){
|
52 | var reg_background = /background(?:-image)?:([\s\S]*?)(?:;|$)/gi;
|
53 | var reg_img_url = /url\s*\(\s*("(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|[^)}]+)\s*\)/i;
|
54 | var reg_position = /(0|[+-]?(?:\d*\.|)\d+px|left|right)\s*(0|[+-]?(?:\d*\.|)\d+px|top)/i;
|
55 | var reg_repeat = /\brepeat-(x|y)/i;
|
56 | var reg_is_sprite = /[?&]__sprite/i;
|
57 |
|
58 |
|
59 | var result = [];
|
60 | var resultNew = [];
|
61 |
|
62 | var maxWidth = 0;
|
63 | var heightTotal = 0;
|
64 | var maxHeight = 0;
|
65 | var widthTotal = 0;
|
66 |
|
67 | var margin = jdf.config.output.cssSpriteMargin;
|
68 | var cssSpriteDirection = jdf.config.output.cssSpriteDirection;
|
69 |
|
70 | var background = [];
|
71 | const projectPath = jdf.getProjectPath();
|
72 | const cssFiles = vfs.queryFileByTargetType('css');
|
73 |
|
74 | cssFiles.forEach((file) => {
|
75 | const content = file.targetContent;
|
76 | const cssBg = content.match(reg_background);
|
77 | const dir = path.dirname(file.buildPath);
|
78 |
|
79 | if(cssBg){
|
80 | cssBg.forEach((bg) => {
|
81 | background.push({bg, dir});
|
82 | });
|
83 | }
|
84 | });
|
85 |
|
86 | if(background){
|
87 | var resultTemp = {};
|
88 | background.forEach(function(item){
|
89 | var img_url = item.bg.match(reg_img_url);
|
90 |
|
91 | if(img_url && reg_is_sprite.test(img_url[0]) && !$.is.httpLink(item)){
|
92 | var res = {
|
93 | content:null,
|
94 | url:null,
|
95 | position:null,
|
96 | repeat:null
|
97 | };
|
98 |
|
99 | var url = img_url[0].replace(/url\(|\)|\'|\"/gi,'');
|
100 |
|
101 | res.urlOrigin = url;
|
102 | url = url.replace(reg_is_sprite, '');
|
103 |
|
104 | var sprite_rem = img_url[0].match(new RegExp('__rem\\d+', 'g'));
|
105 | if(sprite_rem){
|
106 | res.rem = parseFloat(sprite_rem[0].replace('__rem', ''));
|
107 | url = url.replace(/__rem\d+/g, '');
|
108 | }
|
109 |
|
110 | res.url = path.join(item.dir, url);
|
111 | const realFilePath = path.relative(path.join(jdf.config.outputDirName, projectPath), res.url);
|
112 | logger.verbose(`sprite file path: ${realFilePath}`);
|
113 | if(f.exists(realFilePath)){
|
114 | res.content = Images(realFilePath);
|
115 |
|
116 |
|
117 | if(!resultTemp[res.url]){
|
118 | res.item = item.bg;
|
119 | res.width = res.content.size().width;
|
120 | res.height = res.content.size().height;
|
121 |
|
122 | if(cssSpriteDirection == 'vertical'){
|
123 | if(res.width>maxWidth){
|
124 | maxWidth = res.width;
|
125 | }
|
126 | heightTotal += res.height + margin;
|
127 | }else{
|
128 | if(res.height>maxHeight){
|
129 | maxHeight = res.height;
|
130 | }
|
131 | widthTotal += res.width + margin;
|
132 | }
|
133 |
|
134 | if(item.bg.match(reg_position)){
|
135 | res.position = item.bg.match(reg_position)[0];
|
136 | }
|
137 | if(item.bg.match(reg_repeat)){
|
138 | res.repeat = item.bg.match(reg_repeat)[0];
|
139 | }
|
140 | result.push(res);
|
141 | }
|
142 | resultTemp[res.url] = res.url;
|
143 |
|
144 | }else{
|
145 | logger.warn(res.url + ' may be not exist.');
|
146 | }
|
147 | }
|
148 | });
|
149 | }
|
150 |
|
151 | if(result.length>0){
|
152 |
|
153 | var outputName = jdf.getProjectPath().replace(/\//g, '_');
|
154 | var outputExtname = '.png';
|
155 |
|
156 | var imagesOutput = null;
|
157 | if(cssSpriteDirection == 'vertical'){
|
158 | imagesOutput = Images(maxWidth, heightTotal);
|
159 | }else{
|
160 | imagesOutput = Images(widthTotal, maxHeight);
|
161 | }
|
162 |
|
163 | var w = 0;
|
164 | var h = 0;
|
165 | result.forEach(function(item, i){
|
166 | if(!item.repeat){
|
167 | var x = 0, y = h, y2 = -h;
|
168 |
|
169 | if(cssSpriteDirection == 'vertical'){
|
170 | var x = 0, y = h, y2 = -h;
|
171 | if(item.position){
|
172 | var position = item.position.split(' ');
|
173 | var x1 = parseInt(position[0], 10)
|
174 | if(x1){
|
175 | x += x1;
|
176 | }
|
177 | var y1 = parseInt(position[1], 10)
|
178 | if(y1){
|
179 | y += y1;
|
180 | y2 -= y1;
|
181 | }
|
182 | }
|
183 |
|
184 |
|
185 | imagesOutput.draw(item.content, 0, y);
|
186 | }else{
|
187 | var y = 0, x = w, x2 = -w;
|
188 | if(item.position){
|
189 | var position = item.position.split(' ');
|
190 | var x1 = parseInt(position[0], 10)
|
191 | if(x1){
|
192 | x += x1;
|
193 | x2 -= x1;
|
194 | }
|
195 | var y1 = parseInt(position[1], 10)
|
196 | if(y1){
|
197 | y += y1;
|
198 | }
|
199 | }
|
200 |
|
201 |
|
202 | imagesOutput.draw(item.content, x, 0);
|
203 | }
|
204 |
|
205 | var urlOrigin = item.urlOrigin;
|
206 |
|
207 |
|
208 | var urlOriginNew = urlOrigin.replace(path.basename(item.url, path.extname(item.url)), outputName);
|
209 |
|
210 |
|
211 | urlOriginNew = urlOriginNew.replace(path.dirname(urlOriginNew), '/css/i');
|
212 |
|
213 | var backgroundNew = item.item.replace(urlOrigin, urlOriginNew).replace(reg_is_sprite,'').replace(/__rem\d+/, '');
|
214 | if(cssSpriteDirection == 'vertical'){
|
215 | if(item.rem){
|
216 | backgroundNew += 'background-position:'+(x/item.rem)+'rem '+(y2/item.rem)+'rem;';
|
217 | backgroundNew += 'background-size:' + (maxWidth/item.rem) + 'rem ' + (heightTotal/item.rem) + 'rem;';
|
218 | }else{
|
219 | backgroundNew += 'background-position:'+x+'px '+y2+'px;';
|
220 | }
|
221 | }else{
|
222 | if(item.rem){
|
223 | backgroundNew += 'background-position:'+(x2/item.rem)+'rem '+(y/item.rem)+'rem;';
|
224 | backgroundNew += 'background-size:' + (maxWidth/item.rem) + 'rem ' + (heightTotal/item.rem) + 'rem;';
|
225 | }else{
|
226 | backgroundNew += 'background-position:'+x2+'px '+y+'px;';
|
227 | }
|
228 | }
|
229 |
|
230 | item['backgroundNew'] = backgroundNew;
|
231 | resultNew.push(item);
|
232 |
|
233 | if(cssSpriteDirection == 'vertical'){
|
234 | h = h + item.height + margin;
|
235 | }else{
|
236 | w = w + item.width + margin;
|
237 | }
|
238 | }
|
239 | });
|
240 |
|
241 | cssFiles.forEach((file) => {
|
242 | let content = escape(file.targetContent);
|
243 | const dir = path.dirname(file.buildPath);
|
244 |
|
245 | resultNew.forEach((item) =>{
|
246 |
|
247 | let url = item.urlOrigin.replace('?__sprite', '').replace(/__rem\d+/gi, '');
|
248 | url = path.join(dir, url);
|
249 |
|
250 | if(url === item.url){
|
251 | content = content.replace(new RegExp(escape(item.item), 'gi'), escape(item.backgroundNew));
|
252 | }
|
253 | });
|
254 |
|
255 | file.targetContent = unescape(content);
|
256 | delete file.buildPath;
|
257 | });
|
258 |
|
259 |
|
260 | const originPath = path.join('css', 'i', outputName + outputExtname);
|
261 | const originContent = imagesOutput.encode(outputExtname);
|
262 | logger.verbose(`sprite new file: ${originPath}`);
|
263 | vfs.addFile(path.resolve(originPath), originContent);
|
264 | }
|
265 | }
|
266 |
|
267 | cssSprite.scatter = function(source, content, sourceOrigin){
|
268 | var reg_background = /background(?:-image)?:([\s\S]*?)(?:;|$)/gi;
|
269 | var reg_img_url = /url\s*\(\s*("(?:[^\\"\r\n\f]|\\[\s\S])*"|'(?:[^\\'\n\r\f]|\\[\s\S])*'|[^)}]+)\s*\)/i;
|
270 | var reg_position = /(0|[+-]?(?:\d*\.|)\d+px|left|right)\s*(0|[+-]?(?:\d*\.|)\d+px|top)/i;
|
271 | var reg_repeat = /\brepeat-(x|y)/i;
|
272 | var reg_is_sprite = /[?&]__sprite/i;
|
273 |
|
274 | var background = content.match(reg_background);
|
275 | var result = [];
|
276 |
|
277 | var maxWidth = 0;
|
278 | var heightTotal = 0;
|
279 | var maxHeight = 0;
|
280 | var widthTotal = 0;
|
281 |
|
282 | var margin = jdf.config.output.cssSpriteMargin;
|
283 | var cssSpriteDirection = jdf.config.output.cssSpriteDirection;
|
284 | const projectPath = jdf.getProjectPath();
|
285 |
|
286 | if (background) {
|
287 | var resultTemp = {};
|
288 | background.forEach(function(item){
|
289 | var img_url = item.match(reg_img_url);
|
290 | if(img_url && reg_is_sprite.test(img_url[0]) && !$.is.httpLink(item)){
|
291 | var res = {
|
292 | content:null,
|
293 | url:null,
|
294 | position:null,
|
295 | repeat:null
|
296 | };
|
297 |
|
298 | var url = img_url[0].replace(/url\(|\)|\'|\"/gi,'');
|
299 | res.urlOrigin = url;
|
300 | url = url.replace(reg_is_sprite, '');
|
301 |
|
302 | var sprite_rem = img_url[0].match(new RegExp('__rem\\d+', 'g'));
|
303 | if(sprite_rem){
|
304 | res.rem = parseFloat(sprite_rem[0].replace('__rem', ''));
|
305 | url = url.replace(/__rem\d+/g, '');
|
306 | }
|
307 |
|
308 | if(/^\/\w/.test(url)){
|
309 | res.url = path.join(jdf.config.outputDirName, jdf.getProjectPath(), url)
|
310 | }else{
|
311 | res.url = path.join(path.dirname(source),url);
|
312 | }
|
313 |
|
314 |
|
315 |
|
316 |
|
317 | const realFilePath = path.relative(path.join(jdf.config.outputDirName, projectPath), res.url);
|
318 | logger.verbose(`sprite file path: ${realFilePath}`);
|
319 |
|
320 | if(f.exists(realFilePath)){
|
321 | res.content = Images(realFilePath);
|
322 |
|
323 |
|
324 | if(!resultTemp[url]){
|
325 | res.item = item;
|
326 | res.width = res.content.size().width;
|
327 | res.height = res.content.size().height;
|
328 |
|
329 | if(cssSpriteDirection == 'vertical'){
|
330 | if(res.width>maxWidth){
|
331 | maxWidth = res.width;
|
332 | }
|
333 | heightTotal += res.height + margin;
|
334 | }else{
|
335 | if(res.height>maxHeight){
|
336 | maxHeight = res.height;
|
337 | }
|
338 | widthTotal += res.width + margin;
|
339 | }
|
340 |
|
341 | if(item.match(reg_position)){
|
342 | res.position = item.match(reg_position)[0];
|
343 | }
|
344 | if(item.match(reg_repeat)){
|
345 | res.repeat = item.match(reg_repeat)[0];
|
346 | }
|
347 | result.push(res);
|
348 | }
|
349 | resultTemp[url] = url;
|
350 | }else{
|
351 | logger.error(`${res.url} is not exist`);
|
352 | }
|
353 | }
|
354 | });
|
355 | }
|
356 |
|
357 | if(result.length>0){
|
358 |
|
359 | var outputName = path.basename(source, path.extname(source));
|
360 | var outputExtname = '.png';
|
361 |
|
362 | var imagesOutput = null;
|
363 | if(cssSpriteDirection == 'vertical'){
|
364 | imagesOutput = Images(maxWidth, heightTotal);
|
365 | }else{
|
366 | imagesOutput = Images(widthTotal, maxHeight);
|
367 | }
|
368 |
|
369 | var w = 0;
|
370 | var h = 0;
|
371 | result.forEach(function(item, i){
|
372 | if(!item.repeat){
|
373 | outputExtname = path.extname(item.url);
|
374 |
|
375 | if(cssSpriteDirection == 'vertical'){
|
376 | var x = 0, y = h, y2 = -h;
|
377 | if(item.position){
|
378 | var position = item.position.split(' ');
|
379 | var x1 = parseInt(position[0], 10)
|
380 | if(x1){
|
381 | x += x1;
|
382 | }
|
383 | var y1 = parseInt(position[1], 10)
|
384 | if(y1){
|
385 | y += y1;
|
386 | y2 -= y1;
|
387 | }
|
388 | }
|
389 |
|
390 |
|
391 | imagesOutput.draw(item.content, 0, y);
|
392 | }else{
|
393 | var y = 0, x = w, x2 = -w;
|
394 | if(item.position){
|
395 | var position = item.position.split(' ');
|
396 | var x1 = parseInt(position[0], 10)
|
397 | if(x1){
|
398 | x += x1;
|
399 | x2 -= x1;
|
400 | }
|
401 | var y1 = parseInt(position[1], 10)
|
402 | if(y1){
|
403 | y += y1;
|
404 | }
|
405 | }
|
406 |
|
407 |
|
408 | imagesOutput.draw(item.content, x, 0);
|
409 | }
|
410 |
|
411 |
|
412 | var urlOrigin = item.urlOrigin;
|
413 | var urlOriginNew = urlOrigin.replace(path.basename(item.url, path.extname(item.url)) , outputName);
|
414 | urlOriginNew = urlOriginNew.replace(/^\//, '');
|
415 |
|
416 | urlOriginNew = urlOriginNew.replace(/\.\/|\.\.\//gi, '');
|
417 |
|
418 | var backgroundNew = item.item.replace(urlOrigin, urlOriginNew).replace(reg_is_sprite, '').replace(/__rem\d+/, '');
|
419 |
|
420 | if(cssSpriteDirection == 'vertical'){
|
421 | if(item.rem){
|
422 | backgroundNew += 'background-position:'+(x/item.rem)+'rem '+(y2/item.rem)+'rem;';
|
423 | backgroundNew += 'background-size:' + (maxWidth/item.rem) + 'rem ' + (heightTotal/item.rem) + 'rem;';
|
424 | }else{
|
425 | backgroundNew += 'background-position:'+x+'px '+y2+'px;';
|
426 | }
|
427 | }else{
|
428 | if(item.rem){
|
429 | backgroundNew += 'background-position:'+(x2/item.rem)+'rem '+(y/item.rem)+'rem;';
|
430 | backgroundNew += 'background-size:' + (maxWidth/item.rem) + 'rem ' + (heightTotal/item.rem) + 'rem;';
|
431 | }else{
|
432 | backgroundNew += 'background-position:'+x2+'px '+y+'px;';
|
433 | }
|
434 | }
|
435 |
|
436 |
|
437 | content = escape(content);
|
438 | content = content.replace(new RegExp(escape(item.item), 'gi'), escape(backgroundNew));
|
439 | content = unescape(content);
|
440 |
|
441 | if(cssSpriteDirection == 'vertical'){
|
442 | h = h + item.height + margin;
|
443 | }else{
|
444 | w = w + item.width + margin;
|
445 | }
|
446 | }
|
447 | });
|
448 |
|
449 |
|
450 | let originPath = path.resolve(path.dirname(source), 'i', outputName + outputExtname);
|
451 | originPath = path.relative(path.join(jdf.config.outputDirName, projectPath), originPath);
|
452 | const originContent = imagesOutput.encode(outputExtname);
|
453 | logger.verbose(`sprite new file: ${originPath}`);
|
454 | vfs.addFile(path.resolve(originPath), originContent);
|
455 | }
|
456 | return content;
|
457 | }
|