grunt-svgstore
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -80,8 +80,8 @@ /* | ||
includedemo: { | ||
options:{ | ||
includedemo : true | ||
}, | ||
files: { | ||
'tmp/includedemo.svg': ['test/fixtures/*'] | ||
} | ||
options:{ | ||
includedemo : true | ||
}, | ||
files: { | ||
'tmp/includedemo.svg': ['test/fixtures/*'] | ||
} | ||
} | ||
@@ -88,0 +88,0 @@ }, |
{ | ||
"name": "grunt-svgstore", | ||
"description": "Merge SVGs from a folder.", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"homepage": "https://github.com/FWeinb/grunt-svgstore", | ||
@@ -6,0 +6,0 @@ "author": { |
@@ -122,6 +122,25 @@ # grunt-svgstore [![NPM version](https://badge.fury.io/js/grunt-svgstore.svg)](http://badge.fury.io/js/grunt-svgstore) [![Build Status](https://travis-ci.org/FWeinb/grunt-svgstore.svg?branch=master)](https://travis-ci.org/FWeinb/grunt-svgstore) | ||
## Release History | ||
* 0.1.0 Always add `xmlns` namspace. Added the `includedemo` option. Fixed Issues [#20](https://github.com/FWeinb/grunt-svgstore/issues/20), [#19](https://github.com/FWeinb/grunt-svgstore/issues/19), [#18](https://github.com/FWeinb/grunt-svgstore/issues/18) | ||
* 0.0.4 Fixed issue with referencing ids with `url()` (fix [#12](https://github.com/FWeinb/grunt-svgstore/issues/12)) | ||
* 0.0.3 Added `options.formatting` to format svg via [js-beautify](https://github.com/einars/js-beautify) | ||
* 0.0.2 Fixed npm dependencies | ||
* 0.0.1 Inital release | ||
#### 0.2.0 | ||
* Use a `<symbol>`-tag for representing icons (See [TxHawks Comment](https://github.com/FWeinb/grunt-svgstore/issues/16#issuecomment-43786059).) | ||
* Write the `viewBox` attribute to the `<symbol>`-tag, | ||
* Include `title` and `desc` elements in the generated svg for each `<symbol>` | ||
* use 'filename' as a fallback for `title` | ||
* Fix issue [#1](https://github.com/FWeinb/grunt-svgstore/issues/1) | ||
#### 0.1.0 | ||
* Always add `xmlns` namspace. | ||
* Added the `includedemo` option. | ||
* Fixed Issues [#20](https://github.com/FWeinb/grunt-svgstore/issues/20), [#19](https://github.com/FWeinb/grunt-svgstore/issues/19), [#18](https://github.com/FWeinb/grunt-svgstore/issues/18) | ||
#### 0.0.4 | ||
* Fixed issue with referencing ids with `url()` (fix [#12](https://github.com/FWeinb/grunt-svgstore/issues/12)) | ||
#### 0.0.3 | ||
* Added `options.formatting` to format svg via [js-beautify](https://github.com/einars/js-beautify) | ||
#### 0.0.2 | ||
* Fixed npm dependencies | ||
#### 0.0.1 | ||
* Inital release |
@@ -8,180 +8,205 @@ /* | ||
*/ | ||
'use strict'; | ||
module.exports = function(grunt) { | ||
var crypto = require('crypto'), | ||
multiline= require('multiline'), | ||
path = require('path'), | ||
var genAttrStr = function ( attrs, allowed ) { | ||
var result = ''; | ||
Object.keys(attrs).forEach(function (key) { | ||
if ( allowed === undefined || allowed.indexOf(key) >= 0 ) { | ||
result += ' ' + key + '="' + attrs[key] + '"'; | ||
} | ||
}); | ||
return result; | ||
}; | ||
beautify = require('js-beautify').html, | ||
cheerio = require('cheerio'), | ||
chalk = require('chalk'); | ||
module.exports = function (grunt) { | ||
var md5 = function(str){ | ||
return crypto.createHash('md5').update(str).digest('hex'); | ||
}; | ||
var crypto = require('crypto'); | ||
var multiline = require('multiline'); | ||
var path = require('path'); | ||
// Matching an url() reference. To correct references broken by making ids unquie to the source svg | ||
var urlPattern = /url\(\s*#([^ ]+?)\s*\)/g; | ||
var beautify = require('js-beautify').html; | ||
var cheerio = require('cheerio'); | ||
var chalk = require('chalk'); | ||
// Please see the Grunt documentation for more information regarding task | ||
// creation: http://gruntjs.com/creating-tasks | ||
var md5 = function (str) { | ||
return crypto.createHash('md5').update(str).digest('hex'); | ||
}; | ||
grunt.registerMultiTask('svgstore', 'Merge SVGs from a folder.', function() { | ||
// Merge task-specific and/or target-specific options with these defaults. | ||
var options = this.options({ | ||
prefix : '', | ||
svg : { | ||
'xmlns' : "http://www.w3.org/2000/svg" | ||
}, | ||
formatting : false, | ||
includedemo : false | ||
}); | ||
// Matching an url() reference. To correct references broken by making ids unquie to the source svg | ||
var urlPattern = /url\(\s*#([^ ]+?)\s*\)/g; | ||
this.files.forEach(function(file) { | ||
// Please see the Grunt documentation for more information regarding task | ||
// creation: http://gruntjs.com/creating-tasks | ||
var $resultDocument = cheerio.load('<svg><defs></defs></svg>'), | ||
$resultSvg = $resultDocument('svg'), | ||
$resultDefs = $resultDocument('defs').first(), | ||
iconNameViewBoxArray = []; // Used to store information of all icons that are added | ||
// { name : '', attribute : { 'data-viewBox' : ''}} | ||
grunt.registerMultiTask('svgstore', 'Merge SVGs from a folder.', function () { | ||
// Merge task-specific and/or target-specific options with these defaults. | ||
var options = this.options({ | ||
prefix: '', | ||
svg: { | ||
'xmlns': "http://www.w3.org/2000/svg" | ||
}, | ||
formatting: false, | ||
includedemo: false | ||
}); | ||
// Merge in SVG attributes | ||
for ( var attr in options.svg ){ | ||
$resultSvg.attr(attr, options.svg[attr]); | ||
} | ||
this.files.forEach(function (file) { | ||
file.src.filter(function(filepath) { | ||
if (!grunt.file.exists(filepath)) { | ||
grunt.log.warn('File "' + filepath + '" not found.'); | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
}).map(function(filepath){ | ||
var filename = path.basename(filepath, '.svg'), | ||
contentStr = grunt.file.read(filepath), | ||
uniqueId = md5(contentStr), | ||
$ = cheerio.load(contentStr, {normalizeWhitespace : true, xmlMode: true}); | ||
var $resultDocument = cheerio.load('<svg><defs></defs></svg>'), | ||
$resultSvg = $resultDocument('svg'), | ||
$resultDefs = $resultDocument('defs').first(), | ||
iconNameViewBoxArray = []; // Used to store information of all icons that are added | ||
// { name : '', attribute : { 'data-viewBox' : ''}} | ||
// Map to store references from id to uniqueId + id; | ||
var mappedIds = {}; | ||
// Merge in SVG attributes from option | ||
for (var attr in options.svg) { | ||
$resultSvg.attr(attr, options.svg[attr]); | ||
} | ||
// Make IDs unique | ||
$('[id]').each(function(){ | ||
var $elem = $(this); | ||
var id = $elem.attr('id'); | ||
var newId = uniqueId + id; | ||
mappedIds[id] = newId; | ||
$elem.attr('id', newId); | ||
}); | ||
file.src.filter(function (filepath) { | ||
if (!grunt.file.exists(filepath)) { | ||
grunt.log.warn('File "' + filepath + '" not found.'); | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
}).map(function (filepath) { | ||
var filename = path.basename(filepath, '.svg'); | ||
var contentStr = grunt.file.read(filepath); | ||
var uniqueId = md5(contentStr); | ||
var $ = cheerio.load(contentStr, { | ||
normalizeWhitespace: true, | ||
xmlMode: true | ||
}); | ||
// Search for an url() reference in every attribute of every tag | ||
// replace the id with the unique one. | ||
$('*').each(function(){ | ||
var $elem = $(this); | ||
var attrs = $elem.attr(); | ||
Object.keys(attrs).forEach(function(key){ | ||
var value = attrs[key]; | ||
var match; | ||
while ( ( match = urlPattern.exec(value)) !== null){ | ||
if ( mappedIds[match[1]] !== undefined) { | ||
value = value.replace(match[0], 'url(#' + mappedIds[match[1]] + ')'); | ||
} else { | ||
grunt.log.warn('Can\'t reference to id "' + match[1] + '" from attribute "' + attr + '" in "' + this[0].name + '" because it is not defined.'); | ||
} | ||
} | ||
$elem.attr(key, value); | ||
}); | ||
}); | ||
// Map to store references from id to uniqueId + id; | ||
var mappedIds = {}; | ||
var $svg = $('svg'), | ||
$children = $svg.children(); | ||
// Make IDs unique | ||
$('[id]').each(function () { | ||
var $elem = $(this); | ||
var id = $elem.attr('id'); | ||
var newId = uniqueId + id; | ||
mappedIds[id] = newId; | ||
$elem.attr('id', newId); | ||
}); | ||
// Search for an url() reference in every attribute of every tag | ||
// replace the id with the unique one. | ||
$('*').each(function () { | ||
var $elem = $(this); | ||
var attrs = $elem.attr(); | ||
Object.keys(attrs).forEach(function (key) { | ||
var value = attrs[key]; | ||
var match; | ||
while ((match = urlPattern.exec(value)) !== null) { | ||
if (mappedIds[match[1]] !== undefined) { | ||
value = value.replace(match[0], 'url(#' + mappedIds[match[1]] + ')'); | ||
} else { | ||
grunt.log.warn('Can\'t reference to id "' + match[1] + '" from attribute "' + attr + '" in "' + this[0].name + '" because it is not defined.'); | ||
} | ||
} | ||
$elem.attr(key, value); | ||
}); | ||
}); | ||
var resultStr; | ||
var $svg = $('svg'); | ||
var $title = $('title'); | ||
var $desc = $('desc'); | ||
var $def = $('defs').first(); | ||
var attr = $svg.attr(); | ||
// Use the first element | ||
if ( $children.length === 1){ | ||
resultStr = $svg.html(); | ||
} else { // Wrap the SVG in a <g>-Tag | ||
resultStr = '<g>' + $svg.html() + '</g>'; | ||
} | ||
var attrStr = genAttrStr(attr, ['viewBox']); | ||
// Create a object | ||
var $res = cheerio.load(resultStr); | ||
// merge in the defs from this svg in the result defs block. | ||
$resultDefs.append($def.html()); | ||
var graphicId = options.prefix + filename; | ||
// Add ID to the first Element | ||
$res('*').first().attr('id', graphicId); | ||
var title = $title.first().html(); | ||
var desc = $desc.first().html(); | ||
// Append to resulting SVG | ||
$resultDefs.append( $res.xml() ); | ||
// remove def, title, desc from this svg | ||
$def.remove(); | ||
$title.remove(); | ||
$desc.remove(); | ||
// Add icon to the demo.html array | ||
if ( options.includedemo ) { | ||
iconNameViewBoxArray.push({ | ||
name : graphicId, | ||
attributes : { | ||
'viewBox' : $svg.attr('viewBox') | ||
} | ||
}); | ||
} | ||
// If there is no title use the filename | ||
title = title || filename; | ||
}); | ||
var resultStr = '<symbol'+attrStr+'>' + '<title>' + title + '</title>'; | ||
var result = options.formatting ? beautify($resultDocument.xml(), options.formatting) : $resultDocument.xml(); | ||
var destName = path.basename(file.dest, '.svg'); | ||
// Only add desc if it was set | ||
if ( desc ) { resultStr +='<desc>'+ desc +'</desc>'; } | ||
grunt.file.write(file.dest, result); | ||
resultStr += $svg.html() + '</symbol>'; | ||
grunt.log.writeln('File ' + chalk.cyan(file.dest) + ' created.'); | ||
// Create a object | ||
var $res = cheerio.load(resultStr); | ||
if ( options.includedemo ) { | ||
var graphicId = options.prefix + filename; | ||
// Add ID to the first Element | ||
$res('*').first().attr('id', graphicId); | ||
$resultSvg.attr('style', 'display:none'); | ||
// Append to resulting SVG | ||
$resultDefs.append($res.xml()); | ||
var demoHTML = multiline.stripIndent(function(){/* | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<style> | ||
svg{ | ||
width:50px; | ||
height:50px; | ||
fill:black !important; | ||
} | ||
</style> | ||
<head> | ||
<body> | ||
{{svg}} | ||
{{useBlock}} | ||
</body> | ||
</html> | ||
*/}); | ||
var useBlock = ''; | ||
iconNameViewBoxArray.forEach(function(item){ | ||
var attrStr = ''; | ||
// Add icon to the demo.html array | ||
if (options.includedemo) { | ||
iconNameViewBoxArray.push({ | ||
name: graphicId, | ||
attributes: { | ||
'viewBox': $svg.attr('viewBox') | ||
} | ||
}); | ||
} | ||
Object.keys(item.attributes).forEach(function(key){ | ||
attrStr += ' ' +key+'="'+item.attributes[key]+'"'; | ||
}); | ||
}); | ||
useBlock += '\t\t<svg'+attrStr+'>\n\t\t\t<use xlink:href="#'+ item.name +'"></use>\n\t\t</svg>\n'; | ||
}); | ||
var result = options.formatting ? beautify($resultDocument.xml(), options.formatting) : $resultDocument.xml(); | ||
var destName = path.basename(file.dest, '.svg'); | ||
demoHTML = demoHTML.replace('{{svg}}', $resultDocument.xml()); | ||
demoHTML = demoHTML.replace('{{useBlock}}', useBlock); | ||
grunt.file.write(file.dest, result); | ||
var demoPath = path.resolve(path.dirname(file.dest), destName + '-demo.html' ); | ||
grunt.file.write(demoPath, demoHTML); | ||
grunt.log.writeln('Demo file ' + chalk.cyan(demoPath) + ' created.'); | ||
} | ||
grunt.log.writeln('File ' + chalk.cyan(file.dest) + ' created.'); | ||
if (options.includedemo) { | ||
$resultSvg.attr('style', 'width:0;height:0;visibility:hidden;'); | ||
var demoHTML = multiline.stripIndent(function () { /* | ||
<!doctype html> | ||
<html> | ||
<head> | ||
<style> | ||
svg{ | ||
width:50px; | ||
height:50px; | ||
fill:black !important; | ||
} | ||
</style> | ||
<head> | ||
<body> | ||
{{svg}} | ||
{{useBlock}} | ||
</body> | ||
</html> | ||
*/}); | ||
var useBlock = ''; | ||
iconNameViewBoxArray.forEach(function (item) { | ||
//var attrStr = genAttrStr(item.attributes); | ||
useBlock += '\t\t<svg>\n\t\t\t<use xlink:href="#' + item.name + '"></use>\n\t\t</svg>\n'; | ||
}); | ||
demoHTML = demoHTML.replace('{{svg}}', $resultDocument.xml()); | ||
demoHTML = demoHTML.replace('{{useBlock}}', useBlock); | ||
var demoPath = path.resolve(path.dirname(file.dest), destName + '-demo.html'); | ||
grunt.file.write(demoPath, demoHTML); | ||
grunt.log.writeln('Demo file ' + chalk.cyan(demoPath) + ' created.'); | ||
} | ||
}); | ||
}); | ||
}); | ||
}; | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
86769
30
330
146