mirror of
https://github.com/svg/svgo.git
synced 2025-07-29 20:21:14 +03:00
Format all plugins with prettier
This commit is contained in:
@ -43,47 +43,46 @@ plugins: [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
`
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add attributes to an outer <svg> element. Example config:
|
* Add attributes to an outer <svg> element. Example config:
|
||||||
*
|
*
|
||||||
* @author April Arcus
|
* @author April Arcus
|
||||||
*/
|
*/
|
||||||
exports.fn = function(data, params) {
|
exports.fn = function (data, params) {
|
||||||
if (!params || !(Array.isArray(params.attributes) || params.attribute)) {
|
if (!params || !(Array.isArray(params.attributes) || params.attribute)) {
|
||||||
console.error(ENOCLS);
|
console.error(ENOCLS);
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
var attributes = params.attributes || [ params.attribute ],
|
|
||||||
svg = data.content[0];
|
|
||||||
|
|
||||||
if (svg.isElem('svg')) {
|
|
||||||
attributes.forEach(function (attribute) {
|
|
||||||
if (typeof attribute === 'string') {
|
|
||||||
if (!svg.hasAttr(attribute)) {
|
|
||||||
svg.addAttr({
|
|
||||||
name: attribute,
|
|
||||||
prefix: '',
|
|
||||||
local: attribute
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (typeof attribute === 'object') {
|
|
||||||
Object.keys(attribute).forEach(function (key) {
|
|
||||||
if (!svg.hasAttr(key)) {
|
|
||||||
svg.addAttr({
|
|
||||||
name: key,
|
|
||||||
value: attribute[key],
|
|
||||||
prefix: '',
|
|
||||||
local: key
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attributes = params.attributes || [params.attribute],
|
||||||
|
svg = data.content[0];
|
||||||
|
|
||||||
|
if (svg.isElem('svg')) {
|
||||||
|
attributes.forEach(function (attribute) {
|
||||||
|
if (typeof attribute === 'string') {
|
||||||
|
if (!svg.hasAttr(attribute)) {
|
||||||
|
svg.addAttr({
|
||||||
|
name: attribute,
|
||||||
|
prefix: '',
|
||||||
|
local: attribute,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (typeof attribute === 'object') {
|
||||||
|
Object.keys(attribute).forEach(function (key) {
|
||||||
|
if (!svg.hasAttr(key)) {
|
||||||
|
svg.addAttr({
|
||||||
|
name: key,
|
||||||
|
value: attribute[key],
|
||||||
|
prefix: '',
|
||||||
|
local: key,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
@ -32,19 +32,24 @@ plugins:
|
|||||||
*
|
*
|
||||||
* @author April Arcus
|
* @author April Arcus
|
||||||
*/
|
*/
|
||||||
exports.fn = function(data, params) {
|
exports.fn = function (data, params) {
|
||||||
if (!params || !(Array.isArray(params.classNames) && params.classNames.some(String) || params.className)) {
|
if (
|
||||||
console.error(ENOCLS);
|
!params ||
|
||||||
return data;
|
!(
|
||||||
}
|
(Array.isArray(params.classNames) && params.classNames.some(String)) ||
|
||||||
|
params.className
|
||||||
var classNames = params.classNames || [ params.className ],
|
)
|
||||||
svg = data.content[0];
|
) {
|
||||||
|
console.error(ENOCLS);
|
||||||
if (svg.isElem('svg')) {
|
|
||||||
svg.class.add.apply(svg.class, classNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
var classNames = params.classNames || [params.className],
|
||||||
|
svg = data.content[0];
|
||||||
|
|
||||||
|
if (svg.isElem('svg')) {
|
||||||
|
svg.class.add.apply(svg.class, classNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
@ -4,17 +4,18 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'cleanups attributes from newlines, trailing and repeating spaces';
|
exports.description =
|
||||||
|
'cleanups attributes from newlines, trailing and repeating spaces';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
newlines: true,
|
newlines: true,
|
||||||
trim: true,
|
trim: true,
|
||||||
spaces: true
|
spaces: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
|
var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
|
||||||
regNewlines = /\r?\n/g,
|
regNewlines = /\r?\n/g,
|
||||||
regSpaces = /\s{2,}/g;
|
regSpaces = /\s{2,}/g;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup attributes values from newlines, trailing and repeating spaces.
|
* Cleanup attributes values from newlines, trailing and repeating spaces.
|
||||||
@ -25,32 +26,29 @@ var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.isElem()) {
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
if (params.newlines) {
|
||||||
|
// new line which requires a space instead of themselve
|
||||||
|
attr.value = attr.value.replace(
|
||||||
|
regNewlinesNeedSpace,
|
||||||
|
function (match, p1, p2) {
|
||||||
|
return p1 + ' ' + p2;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (item.isElem()) {
|
// simple new line
|
||||||
|
attr.value = attr.value.replace(regNewlines, '');
|
||||||
|
}
|
||||||
|
|
||||||
item.eachAttr(function(attr) {
|
if (params.trim) {
|
||||||
|
attr.value = attr.value.trim();
|
||||||
if (params.newlines) {
|
}
|
||||||
// new line which requires a space instead of themselve
|
|
||||||
attr.value = attr.value.replace(regNewlinesNeedSpace, function(match, p1, p2) {
|
|
||||||
return p1 + ' ' + p2;
|
|
||||||
});
|
|
||||||
|
|
||||||
// simple new line
|
|
||||||
attr.value = attr.value.replace(regNewlines, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.trim) {
|
|
||||||
attr.value = attr.value.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.spaces) {
|
|
||||||
attr.value = attr.value.replace(regSpaces, ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (params.spaces) {
|
||||||
|
attr.value = attr.value.replace(regSpaces, ' ');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,8 @@ exports.type = 'full';
|
|||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'remove or cleanup enable-background attribute when possible';
|
exports.description =
|
||||||
|
'remove or cleanup enable-background attribute when possible';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove or cleanup enable-background attr which coincides with a width/height box.
|
* Remove or cleanup enable-background attr which coincides with a width/height box.
|
||||||
@ -21,64 +22,65 @@ exports.description = 'remove or cleanup enable-background attribute when possib
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(data) {
|
exports.fn = function (data) {
|
||||||
|
var regEnableBackground = /^new\s0\s0\s([-+]?\d*\.?\d+([eE][-+]?\d+)?)\s([-+]?\d*\.?\d+([eE][-+]?\d+)?)$/,
|
||||||
|
hasFilter = false,
|
||||||
|
elems = ['svg', 'mask', 'pattern'];
|
||||||
|
|
||||||
var regEnableBackground = /^new\s0\s0\s([-+]?\d*\.?\d+([eE][-+]?\d+)?)\s([-+]?\d*\.?\d+([eE][-+]?\d+)?)$/,
|
function checkEnableBackground(item) {
|
||||||
hasFilter = false,
|
if (
|
||||||
elems = ['svg', 'mask', 'pattern'];
|
item.isElem(elems) &&
|
||||||
|
item.hasAttr('enable-background') &&
|
||||||
|
item.hasAttr('width') &&
|
||||||
|
item.hasAttr('height')
|
||||||
|
) {
|
||||||
|
var match = item
|
||||||
|
.attr('enable-background')
|
||||||
|
.value.match(regEnableBackground);
|
||||||
|
|
||||||
function checkEnableBackground(item) {
|
if (match) {
|
||||||
if (
|
if (
|
||||||
item.isElem(elems) &&
|
item.attr('width').value === match[1] &&
|
||||||
item.hasAttr('enable-background') &&
|
item.attr('height').value === match[3]
|
||||||
item.hasAttr('width') &&
|
|
||||||
item.hasAttr('height')
|
|
||||||
) {
|
) {
|
||||||
|
if (item.isElem('svg')) {
|
||||||
var match = item.attr('enable-background').value.match(regEnableBackground);
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
if (
|
|
||||||
item.attr('width').value === match[1] &&
|
|
||||||
item.attr('height').value === match[3]
|
|
||||||
) {
|
|
||||||
if (item.isElem('svg')) {
|
|
||||||
item.removeAttr('enable-background');
|
|
||||||
} else {
|
|
||||||
item.attr('enable-background').value = 'new';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkForFilter(item) {
|
|
||||||
if (item.isElem('filter')) {
|
|
||||||
hasFilter = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function monkeys(items, fn) {
|
|
||||||
items.content.forEach(function(item) {
|
|
||||||
fn(item);
|
|
||||||
|
|
||||||
if (item.content) {
|
|
||||||
monkeys(item, fn);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstStep = monkeys(data, function(item) {
|
|
||||||
checkEnableBackground(item);
|
|
||||||
if (!hasFilter) {
|
|
||||||
checkForFilter(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return hasFilter ? firstStep : monkeys(firstStep, function(item) {
|
|
||||||
//we don't need 'enable-background' if we have no filters
|
|
||||||
item.removeAttr('enable-background');
|
item.removeAttr('enable-background');
|
||||||
});
|
} else {
|
||||||
|
item.attr('enable-background').value = 'new';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkForFilter(item) {
|
||||||
|
if (item.isElem('filter')) {
|
||||||
|
hasFilter = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function monkeys(items, fn) {
|
||||||
|
items.content.forEach(function (item) {
|
||||||
|
fn(item);
|
||||||
|
|
||||||
|
if (item.content) {
|
||||||
|
monkeys(item, fn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstStep = monkeys(data, function (item) {
|
||||||
|
checkEnableBackground(item);
|
||||||
|
if (!hasFilter) {
|
||||||
|
checkForFilter(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasFilter
|
||||||
|
? firstStep
|
||||||
|
: monkeys(firstStep, function (item) {
|
||||||
|
//we don't need 'enable-background' if we have no filters
|
||||||
|
item.removeAttr('enable-background');
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -7,24 +7,74 @@ exports.active = true;
|
|||||||
exports.description = 'removes unused IDs and minifies used';
|
exports.description = 'removes unused IDs and minifies used';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
remove: true,
|
remove: true,
|
||||||
minify: true,
|
minify: true,
|
||||||
prefix: '',
|
prefix: '',
|
||||||
preserve: [],
|
preserve: [],
|
||||||
preservePrefixes: [],
|
preservePrefixes: [],
|
||||||
force: false
|
force: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var referencesProps = new Set(require('./_collections').referencesProps),
|
var referencesProps = new Set(require('./_collections').referencesProps),
|
||||||
regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/,
|
regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/,
|
||||||
regReferencesHref = /^#(.+?)$/,
|
regReferencesHref = /^#(.+?)$/,
|
||||||
regReferencesBegin = /(\w+)\./,
|
regReferencesBegin = /(\w+)\./,
|
||||||
styleOrScript = ['style', 'script'],
|
styleOrScript = ['style', 'script'],
|
||||||
generateIDchars = [
|
generateIDchars = [
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
'a',
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
'b',
|
||||||
],
|
'c',
|
||||||
maxIDindex = generateIDchars.length - 1;
|
'd',
|
||||||
|
'e',
|
||||||
|
'f',
|
||||||
|
'g',
|
||||||
|
'h',
|
||||||
|
'i',
|
||||||
|
'j',
|
||||||
|
'k',
|
||||||
|
'l',
|
||||||
|
'm',
|
||||||
|
'n',
|
||||||
|
'o',
|
||||||
|
'p',
|
||||||
|
'q',
|
||||||
|
'r',
|
||||||
|
's',
|
||||||
|
't',
|
||||||
|
'u',
|
||||||
|
'v',
|
||||||
|
'w',
|
||||||
|
'x',
|
||||||
|
'y',
|
||||||
|
'z',
|
||||||
|
'A',
|
||||||
|
'B',
|
||||||
|
'C',
|
||||||
|
'D',
|
||||||
|
'E',
|
||||||
|
'F',
|
||||||
|
'G',
|
||||||
|
'H',
|
||||||
|
'I',
|
||||||
|
'J',
|
||||||
|
'K',
|
||||||
|
'L',
|
||||||
|
'M',
|
||||||
|
'N',
|
||||||
|
'O',
|
||||||
|
'P',
|
||||||
|
'Q',
|
||||||
|
'R',
|
||||||
|
'S',
|
||||||
|
'T',
|
||||||
|
'U',
|
||||||
|
'V',
|
||||||
|
'W',
|
||||||
|
'X',
|
||||||
|
'Y',
|
||||||
|
'Z',
|
||||||
|
],
|
||||||
|
maxIDindex = generateIDchars.length - 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove unused and minify used IDs
|
* Remove unused and minify used IDs
|
||||||
@ -35,128 +85,155 @@ var referencesProps = new Set(require('./_collections').referencesProps),
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(data, params) {
|
exports.fn = function (data, params) {
|
||||||
var currentID,
|
var currentID,
|
||||||
currentIDstring,
|
currentIDstring,
|
||||||
IDs = new Map(),
|
IDs = new Map(),
|
||||||
referencesIDs = new Map(),
|
referencesIDs = new Map(),
|
||||||
hasStyleOrScript = false,
|
hasStyleOrScript = false,
|
||||||
preserveIDs = new Set(Array.isArray(params.preserve) ? params.preserve : params.preserve ? [params.preserve] : []),
|
preserveIDs = new Set(
|
||||||
preserveIDPrefixes = new Set(Array.isArray(params.preservePrefixes) ? params.preservePrefixes : (params.preservePrefixes ? [params.preservePrefixes] : [])),
|
Array.isArray(params.preserve)
|
||||||
idValuePrefix = '#',
|
? params.preserve
|
||||||
idValuePostfix = '.';
|
: params.preserve
|
||||||
|
? [params.preserve]
|
||||||
|
: []
|
||||||
|
),
|
||||||
|
preserveIDPrefixes = new Set(
|
||||||
|
Array.isArray(params.preservePrefixes)
|
||||||
|
? params.preservePrefixes
|
||||||
|
: params.preservePrefixes
|
||||||
|
? [params.preservePrefixes]
|
||||||
|
: []
|
||||||
|
),
|
||||||
|
idValuePrefix = '#',
|
||||||
|
idValuePostfix = '.';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bananas!
|
* Bananas!
|
||||||
*
|
*
|
||||||
* @param {Array} items input items
|
* @param {Array} items input items
|
||||||
* @return {Array} output items
|
* @return {Array} output items
|
||||||
*/
|
*/
|
||||||
function monkeys(items) {
|
function monkeys(items) {
|
||||||
for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
|
for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
|
||||||
var item = items.content[i];
|
var item = items.content[i];
|
||||||
|
|
||||||
// quit if <style> or <script> present ('force' param prevents quitting)
|
// quit if <style> or <script> present ('force' param prevents quitting)
|
||||||
if (!params.force) {
|
if (!params.force) {
|
||||||
var isNotEmpty = Boolean(item.content);
|
var isNotEmpty = Boolean(item.content);
|
||||||
if (item.isElem(styleOrScript) && isNotEmpty) {
|
if (item.isElem(styleOrScript) && isNotEmpty) {
|
||||||
hasStyleOrScript = true;
|
hasStyleOrScript = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Don't remove IDs if the whole SVG consists only of defs.
|
|
||||||
if (item.isElem('svg') && item.content) {
|
|
||||||
var hasDefsOnly = true;
|
|
||||||
|
|
||||||
for (var j = 0; j < item.content.length; j++) {
|
|
||||||
if (!item.content[j].isElem('defs')) {
|
|
||||||
hasDefsOnly = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasDefsOnly) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// …and don't remove any ID if yes
|
|
||||||
if (item.isElem()) {
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
var key, match;
|
|
||||||
|
|
||||||
// save IDs
|
|
||||||
if (attr.name === 'id') {
|
|
||||||
key = attr.value;
|
|
||||||
if (IDs.has(key)) {
|
|
||||||
item.removeAttr('id'); // remove repeated id
|
|
||||||
} else {
|
|
||||||
IDs.set(key, item);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// save references
|
|
||||||
if (referencesProps.has(attr.name) && (match = attr.value.match(regReferencesUrl))) {
|
|
||||||
key = match[2]; // url() reference
|
|
||||||
} else if (
|
|
||||||
attr.local === 'href' && (match = attr.value.match(regReferencesHref)) ||
|
|
||||||
attr.name === 'begin' && (match = attr.value.match(regReferencesBegin))
|
|
||||||
) {
|
|
||||||
key = match[1]; // href reference
|
|
||||||
}
|
|
||||||
if (key) {
|
|
||||||
var ref = referencesIDs.get(key) || [];
|
|
||||||
ref.push(attr);
|
|
||||||
referencesIDs.set(key, ref);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// go deeper
|
|
||||||
if (item.content) {
|
|
||||||
monkeys(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = monkeys(data);
|
// Don't remove IDs if the whole SVG consists only of defs.
|
||||||
|
if (item.isElem('svg') && item.content) {
|
||||||
|
var hasDefsOnly = true;
|
||||||
|
|
||||||
if (hasStyleOrScript) {
|
for (var j = 0; j < item.content.length; j++) {
|
||||||
return data;
|
if (!item.content[j].isElem('defs')) {
|
||||||
}
|
hasDefsOnly = false;
|
||||||
|
break;
|
||||||
const idPreserved = id => preserveIDs.has(id) || idMatchesPrefix(preserveIDPrefixes, id);
|
|
||||||
|
|
||||||
for (var ref of referencesIDs) {
|
|
||||||
var key = ref[0];
|
|
||||||
|
|
||||||
if (IDs.has(key)) {
|
|
||||||
// replace referenced IDs with the minified ones
|
|
||||||
if (params.minify && !idPreserved(key)) {
|
|
||||||
do {
|
|
||||||
currentIDstring = getIDstring(currentID = generateID(currentID), params);
|
|
||||||
} while (idPreserved(currentIDstring));
|
|
||||||
|
|
||||||
IDs.get(key).attr('id').value = currentIDstring;
|
|
||||||
|
|
||||||
for (var attr of ref[1]) {
|
|
||||||
attr.value = attr.value.includes(idValuePrefix) ?
|
|
||||||
attr.value.replace(idValuePrefix + key, idValuePrefix + currentIDstring) :
|
|
||||||
attr.value.replace(key + idValuePostfix, currentIDstring + idValuePostfix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// don't remove referenced IDs
|
}
|
||||||
IDs.delete(key);
|
if (hasDefsOnly) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove non-referenced IDs attributes from elements
|
// …and don't remove any ID if yes
|
||||||
if (params.remove) {
|
if (item.isElem()) {
|
||||||
for(var keyElem of IDs) {
|
item.eachAttr(function (attr) {
|
||||||
if (!idPreserved(keyElem[0])) {
|
var key, match;
|
||||||
keyElem[1].removeAttr('id');
|
|
||||||
|
// save IDs
|
||||||
|
if (attr.name === 'id') {
|
||||||
|
key = attr.value;
|
||||||
|
if (IDs.has(key)) {
|
||||||
|
item.removeAttr('id'); // remove repeated id
|
||||||
|
} else {
|
||||||
|
IDs.set(key, item);
|
||||||
}
|
}
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
// save references
|
||||||
|
if (
|
||||||
|
referencesProps.has(attr.name) &&
|
||||||
|
(match = attr.value.match(regReferencesUrl))
|
||||||
|
) {
|
||||||
|
key = match[2]; // url() reference
|
||||||
|
} else if (
|
||||||
|
(attr.local === 'href' &&
|
||||||
|
(match = attr.value.match(regReferencesHref))) ||
|
||||||
|
(attr.name === 'begin' &&
|
||||||
|
(match = attr.value.match(regReferencesBegin)))
|
||||||
|
) {
|
||||||
|
key = match[1]; // href reference
|
||||||
|
}
|
||||||
|
if (key) {
|
||||||
|
var ref = referencesIDs.get(key) || [];
|
||||||
|
ref.push(attr);
|
||||||
|
referencesIDs.set(key, ref);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// go deeper
|
||||||
|
if (item.content) {
|
||||||
|
monkeys(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = monkeys(data);
|
||||||
|
|
||||||
|
if (hasStyleOrScript) {
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const idPreserved = (id) =>
|
||||||
|
preserveIDs.has(id) || idMatchesPrefix(preserveIDPrefixes, id);
|
||||||
|
|
||||||
|
for (var ref of referencesIDs) {
|
||||||
|
var key = ref[0];
|
||||||
|
|
||||||
|
if (IDs.has(key)) {
|
||||||
|
// replace referenced IDs with the minified ones
|
||||||
|
if (params.minify && !idPreserved(key)) {
|
||||||
|
do {
|
||||||
|
currentIDstring = getIDstring(
|
||||||
|
(currentID = generateID(currentID)),
|
||||||
|
params
|
||||||
|
);
|
||||||
|
} while (idPreserved(currentIDstring));
|
||||||
|
|
||||||
|
IDs.get(key).attr('id').value = currentIDstring;
|
||||||
|
|
||||||
|
for (var attr of ref[1]) {
|
||||||
|
attr.value = attr.value.includes(idValuePrefix)
|
||||||
|
? attr.value.replace(
|
||||||
|
idValuePrefix + key,
|
||||||
|
idValuePrefix + currentIDstring
|
||||||
|
)
|
||||||
|
: attr.value.replace(
|
||||||
|
key + idValuePostfix,
|
||||||
|
currentIDstring + idValuePostfix
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// don't remove referenced IDs
|
||||||
|
IDs.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove non-referenced IDs attributes from elements
|
||||||
|
if (params.remove) {
|
||||||
|
for (var keyElem of IDs) {
|
||||||
|
if (!idPreserved(keyElem[0])) {
|
||||||
|
keyElem[1].removeAttr('id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,10 +244,10 @@ exports.fn = function(data, params) {
|
|||||||
* @return {Boolean} if currentID starts with one of the strings in prefixArray
|
* @return {Boolean} if currentID starts with one of the strings in prefixArray
|
||||||
*/
|
*/
|
||||||
function idMatchesPrefix(prefixArray, currentID) {
|
function idMatchesPrefix(prefixArray, currentID) {
|
||||||
if (!currentID) return false;
|
if (!currentID) return false;
|
||||||
|
|
||||||
for (var prefix of prefixArray) if (currentID.startsWith(prefix)) return true;
|
for (var prefix of prefixArray) if (currentID.startsWith(prefix)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -180,24 +257,24 @@ function idMatchesPrefix(prefixArray, currentID) {
|
|||||||
* @return {Array} generated ID array
|
* @return {Array} generated ID array
|
||||||
*/
|
*/
|
||||||
function generateID(currentID) {
|
function generateID(currentID) {
|
||||||
if (!currentID) return [0];
|
if (!currentID) return [0];
|
||||||
|
|
||||||
currentID[currentID.length - 1]++;
|
currentID[currentID.length - 1]++;
|
||||||
|
|
||||||
for(var i = currentID.length - 1; i > 0; i--) {
|
for (var i = currentID.length - 1; i > 0; i--) {
|
||||||
if (currentID[i] > maxIDindex) {
|
if (currentID[i] > maxIDindex) {
|
||||||
currentID[i] = 0;
|
currentID[i] = 0;
|
||||||
|
|
||||||
if (currentID[i - 1] !== undefined) {
|
if (currentID[i - 1] !== undefined) {
|
||||||
currentID[i - 1]++;
|
currentID[i - 1]++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (currentID[0] > maxIDindex) {
|
}
|
||||||
currentID[0] = 0;
|
if (currentID[0] > maxIDindex) {
|
||||||
currentID.unshift(0);
|
currentID[0] = 0;
|
||||||
}
|
currentID.unshift(0);
|
||||||
return currentID;
|
}
|
||||||
|
return currentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,6 +284,6 @@ function generateID(currentID) {
|
|||||||
* @return {String} output ID string
|
* @return {String} output ID string
|
||||||
*/
|
*/
|
||||||
function getIDstring(arr, params) {
|
function getIDstring(arr, params) {
|
||||||
var str = params.prefix;
|
var str = params.prefix;
|
||||||
return str + arr.map(i => generateIDchars[i]).join('');
|
return str + arr.map((i) => generateIDchars[i]).join('');
|
||||||
}
|
}
|
||||||
|
@ -7,22 +7,23 @@ exports.active = false;
|
|||||||
exports.description = 'rounds list of values to the fixed precision';
|
exports.description = 'rounds list of values to the fixed precision';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
floatPrecision: 3,
|
floatPrecision: 3,
|
||||||
leadingZero: true,
|
leadingZero: true,
|
||||||
defaultPx: true,
|
defaultPx: true,
|
||||||
convertToPx: true
|
convertToPx: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
|
var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
|
||||||
regSeparator = /\s+,?\s*|,\s*/,
|
regSeparator = /\s+,?\s*|,\s*/,
|
||||||
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
|
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
|
||||||
absoluteLengths = { // relative to px
|
absoluteLengths = {
|
||||||
cm: 96/2.54,
|
// relative to px
|
||||||
mm: 96/25.4,
|
cm: 96 / 2.54,
|
||||||
in: 96,
|
mm: 96 / 25.4,
|
||||||
pt: 4/3,
|
in: 96,
|
||||||
pc: 16
|
pt: 4 / 3,
|
||||||
};
|
pc: 16,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Round list of values to the fixed precision.
|
* Round list of values to the fixed precision.
|
||||||
@ -44,96 +45,90 @@ var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|
|
|||||||
*
|
*
|
||||||
* @author kiyopikko
|
* @author kiyopikko
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.hasAttr('points')) {
|
||||||
|
roundValues(item.attrs.points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.hasAttr('enable-background')) {
|
||||||
|
roundValues(item.attrs['enable-background']);
|
||||||
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('points') ) {
|
if (item.hasAttr('viewBox')) {
|
||||||
roundValues(item.attrs.points);
|
roundValues(item.attrs.viewBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('enable-background') ) {
|
if (item.hasAttr('stroke-dasharray')) {
|
||||||
roundValues(item.attrs['enable-background']);
|
roundValues(item.attrs['stroke-dasharray']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('viewBox') ) {
|
if (item.hasAttr('dx')) {
|
||||||
roundValues(item.attrs.viewBox);
|
roundValues(item.attrs.dx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('stroke-dasharray') ) {
|
if (item.hasAttr('dy')) {
|
||||||
roundValues(item.attrs['stroke-dasharray']);
|
roundValues(item.attrs.dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('dx') ) {
|
if (item.hasAttr('x')) {
|
||||||
roundValues(item.attrs.dx);
|
roundValues(item.attrs.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('dy') ) {
|
if (item.hasAttr('y')) {
|
||||||
roundValues(item.attrs.dy);
|
roundValues(item.attrs.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( item.hasAttr('x') ) {
|
function roundValues($prop) {
|
||||||
roundValues(item.attrs.x);
|
var num,
|
||||||
}
|
units,
|
||||||
|
match,
|
||||||
|
matchNew,
|
||||||
|
lists = $prop.value,
|
||||||
|
listsArr = lists.split(regSeparator),
|
||||||
|
roundedListArr = [],
|
||||||
|
roundedList;
|
||||||
|
|
||||||
if ( item.hasAttr('y') ) {
|
listsArr.forEach(function (elem) {
|
||||||
roundValues(item.attrs.y);
|
match = elem.match(regNumericValues);
|
||||||
}
|
matchNew = elem.match(/new/);
|
||||||
|
|
||||||
|
// if attribute value matches regNumericValues
|
||||||
|
if (match) {
|
||||||
|
// round it to the fixed precision
|
||||||
|
(num = +(+match[1]).toFixed(params.floatPrecision)),
|
||||||
|
(units = match[3] || '');
|
||||||
|
|
||||||
function roundValues($prop){
|
// convert absolute values to pixels
|
||||||
|
if (params.convertToPx && units && units in absoluteLengths) {
|
||||||
|
var pxNum = +(absoluteLengths[units] * match[1]).toFixed(
|
||||||
|
params.floatPrecision
|
||||||
|
);
|
||||||
|
|
||||||
var num, units,
|
if (String(pxNum).length < match[0].length)
|
||||||
match,
|
(num = pxNum), (units = 'px');
|
||||||
matchNew,
|
}
|
||||||
lists = $prop.value,
|
|
||||||
listsArr = lists.split(regSeparator),
|
|
||||||
roundedListArr = [],
|
|
||||||
roundedList;
|
|
||||||
|
|
||||||
listsArr.forEach(function(elem){
|
// and remove leading zero
|
||||||
|
if (params.leadingZero) {
|
||||||
|
num = removeLeadingZero(num);
|
||||||
|
}
|
||||||
|
|
||||||
match = elem.match(regNumericValues);
|
// remove default 'px' units
|
||||||
matchNew = elem.match(/new/);
|
if (params.defaultPx && units === 'px') {
|
||||||
|
units = '';
|
||||||
|
}
|
||||||
|
|
||||||
// if attribute value matches regNumericValues
|
roundedListArr.push(num + units);
|
||||||
if (match) {
|
}
|
||||||
// round it to the fixed precision
|
// if attribute value is "new"(only enable-background).
|
||||||
num = +(+match[1]).toFixed(params.floatPrecision),
|
else if (matchNew) {
|
||||||
units = match[3] || '';
|
roundedListArr.push('new');
|
||||||
|
} else if (elem) {
|
||||||
// convert absolute values to pixels
|
roundedListArr.push(elem);
|
||||||
if (params.convertToPx && units && (units in absoluteLengths)) {
|
}
|
||||||
var pxNum = +(absoluteLengths[units] * match[1]).toFixed(params.floatPrecision);
|
});
|
||||||
|
|
||||||
if (String(pxNum).length < match[0].length)
|
|
||||||
num = pxNum,
|
|
||||||
units = 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
// and remove leading zero
|
|
||||||
if (params.leadingZero) {
|
|
||||||
num = removeLeadingZero(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove default 'px' units
|
|
||||||
if (params.defaultPx && units === 'px') {
|
|
||||||
units = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
roundedListArr.push(num+units);
|
|
||||||
}
|
|
||||||
// if attribute value is "new"(only enable-background).
|
|
||||||
else if (matchNew) {
|
|
||||||
roundedListArr.push('new');
|
|
||||||
} else if (elem) {
|
|
||||||
roundedListArr.push(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
roundedList = roundedListArr.join(' ');
|
|
||||||
$prop.value = roundedList;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
roundedList = roundedListArr.join(' ');
|
||||||
|
$prop.value = roundedList;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,24 +4,26 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'rounds numeric values to the fixed precision, removes default ‘px’ units';
|
exports.description =
|
||||||
|
'rounds numeric values to the fixed precision, removes default ‘px’ units';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
floatPrecision: 3,
|
floatPrecision: 3,
|
||||||
leadingZero: true,
|
leadingZero: true,
|
||||||
defaultPx: true,
|
defaultPx: true,
|
||||||
convertToPx: true
|
convertToPx: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
|
var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
|
||||||
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
|
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
|
||||||
absoluteLengths = { // relative to px
|
absoluteLengths = {
|
||||||
cm: 96/2.54,
|
// relative to px
|
||||||
mm: 96/25.4,
|
cm: 96 / 2.54,
|
||||||
in: 96,
|
mm: 96 / 25.4,
|
||||||
pt: 4/3,
|
in: 96,
|
||||||
pc: 16
|
pt: 4 / 3,
|
||||||
};
|
pc: 16,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Round numeric values to the fixed precision,
|
* Round numeric values to the fixed precision,
|
||||||
@ -33,56 +35,58 @@ var regNumericValues = /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.isElem()) {
|
||||||
if (item.isElem()) {
|
var floatPrecision = params.floatPrecision;
|
||||||
|
|
||||||
var floatPrecision = params.floatPrecision;
|
|
||||||
|
|
||||||
if (item.hasAttr('viewBox')) {
|
|
||||||
var nums = item.attr('viewBox').value.split(/\s,?\s*|,\s*/g);
|
|
||||||
item.attr('viewBox').value = nums.map(function(value) {
|
|
||||||
var num = +value;
|
|
||||||
return isNaN(num) ? value : +num.toFixed(floatPrecision);
|
|
||||||
}).join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
// The `version` attribute is a text string and cannot be rounded
|
|
||||||
if (attr.name === 'version') { return }
|
|
||||||
|
|
||||||
var match = attr.value.match(regNumericValues);
|
|
||||||
|
|
||||||
// if attribute value matches regNumericValues
|
|
||||||
if (match) {
|
|
||||||
// round it to the fixed precision
|
|
||||||
var num = +(+match[1]).toFixed(floatPrecision),
|
|
||||||
units = match[3] || '';
|
|
||||||
|
|
||||||
// convert absolute values to pixels
|
|
||||||
if (params.convertToPx && units && (units in absoluteLengths)) {
|
|
||||||
var pxNum = +(absoluteLengths[units] * match[1]).toFixed(floatPrecision);
|
|
||||||
|
|
||||||
if (String(pxNum).length < match[0].length) {
|
|
||||||
num = pxNum;
|
|
||||||
units = 'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and remove leading zero
|
|
||||||
if (params.leadingZero) {
|
|
||||||
num = removeLeadingZero(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove default 'px' units
|
|
||||||
if (params.defaultPx && units === 'px') {
|
|
||||||
units = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.value = num + units;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
if (item.hasAttr('viewBox')) {
|
||||||
|
var nums = item.attr('viewBox').value.split(/\s,?\s*|,\s*/g);
|
||||||
|
item.attr('viewBox').value = nums
|
||||||
|
.map(function (value) {
|
||||||
|
var num = +value;
|
||||||
|
return isNaN(num) ? value : +num.toFixed(floatPrecision);
|
||||||
|
})
|
||||||
|
.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
// The `version` attribute is a text string and cannot be rounded
|
||||||
|
if (attr.name === 'version') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = attr.value.match(regNumericValues);
|
||||||
|
|
||||||
|
// if attribute value matches regNumericValues
|
||||||
|
if (match) {
|
||||||
|
// round it to the fixed precision
|
||||||
|
var num = +(+match[1]).toFixed(floatPrecision),
|
||||||
|
units = match[3] || '';
|
||||||
|
|
||||||
|
// convert absolute values to pixels
|
||||||
|
if (params.convertToPx && units && units in absoluteLengths) {
|
||||||
|
var pxNum = +(absoluteLengths[units] * match[1]).toFixed(
|
||||||
|
floatPrecision
|
||||||
|
);
|
||||||
|
|
||||||
|
if (String(pxNum).length < match[0].length) {
|
||||||
|
num = pxNum;
|
||||||
|
units = 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// and remove leading zero
|
||||||
|
if (params.leadingZero) {
|
||||||
|
num = removeLeadingZero(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove default 'px' units
|
||||||
|
if (params.defaultPx && units === 'px') {
|
||||||
|
units = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.value = num + units;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,12 +7,14 @@ exports.active = true;
|
|||||||
exports.description = 'collapses useless groups';
|
exports.description = 'collapses useless groups';
|
||||||
|
|
||||||
var collections = require('./_collections'),
|
var collections = require('./_collections'),
|
||||||
attrsInheritable = collections.inheritableAttrs,
|
attrsInheritable = collections.inheritableAttrs,
|
||||||
animationElems = collections.elemsGroups.animation;
|
animationElems = collections.elemsGroups.animation;
|
||||||
|
|
||||||
function hasAnimatedAttr(item) {
|
function hasAnimatedAttr(item) {
|
||||||
return item.isElem(animationElems) && item.hasAttr('attributeName', this) ||
|
return (
|
||||||
!item.isEmpty() && item.content.some(hasAnimatedAttr, this);
|
(item.isElem(animationElems) && item.hasAttr('attributeName', this)) ||
|
||||||
|
(!item.isEmpty() && item.content.some(hasAnimatedAttr, this))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -38,49 +40,58 @@ function hasAnimatedAttr(item) {
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
// non-empty elements
|
||||||
|
if (item.isElem() && !item.isElem('switch') && !item.isEmpty()) {
|
||||||
|
item.content.forEach(function (g, i) {
|
||||||
|
// non-empty groups
|
||||||
|
if (g.isElem('g') && !g.isEmpty()) {
|
||||||
|
// move group attibutes to the single content element
|
||||||
|
if (g.hasAttr() && g.content.length === 1) {
|
||||||
|
var inner = g.content[0];
|
||||||
|
|
||||||
// non-empty elements
|
if (
|
||||||
if (item.isElem() && !item.isElem('switch') && !item.isEmpty()) {
|
inner.isElem() &&
|
||||||
item.content.forEach(function(g, i) {
|
!inner.hasAttr('id') &&
|
||||||
// non-empty groups
|
!g.hasAttr('filter') &&
|
||||||
if (g.isElem('g') && !g.isEmpty()) {
|
!(g.hasAttr('class') && inner.hasAttr('class')) &&
|
||||||
// move group attibutes to the single content element
|
((!g.hasAttr('clip-path') && !g.hasAttr('mask')) ||
|
||||||
if (g.hasAttr() && g.content.length === 1) {
|
(inner.isElem('g') &&
|
||||||
var inner = g.content[0];
|
!g.hasAttr('transform') &&
|
||||||
|
!inner.hasAttr('transform')))
|
||||||
|
) {
|
||||||
|
g.eachAttr(function (attr) {
|
||||||
|
if (g.content.some(hasAnimatedAttr, attr.name)) return;
|
||||||
|
|
||||||
if (inner.isElem() && !inner.hasAttr('id') && !g.hasAttr('filter') &&
|
if (!inner.hasAttr(attr.name)) {
|
||||||
!(g.hasAttr('class') && inner.hasAttr('class')) && (
|
inner.addAttr(attr);
|
||||||
!g.hasAttr('clip-path') && !g.hasAttr('mask') ||
|
} else if (attr.name == 'transform') {
|
||||||
inner.isElem('g') && !g.hasAttr('transform') && !inner.hasAttr('transform')
|
inner.attr(attr.name).value =
|
||||||
)
|
attr.value + ' ' + inner.attr(attr.name).value;
|
||||||
) {
|
} else if (inner.hasAttr(attr.name, 'inherit')) {
|
||||||
g.eachAttr(function(attr) {
|
inner.attr(attr.name).value = attr.value;
|
||||||
if (g.content.some(hasAnimatedAttr, attr.name)) return;
|
} else if (
|
||||||
|
attrsInheritable.indexOf(attr.name) < 0 &&
|
||||||
|
!inner.hasAttr(attr.name, attr.value)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!inner.hasAttr(attr.name)) {
|
g.removeAttr(attr.name);
|
||||||
inner.addAttr(attr);
|
});
|
||||||
} else if (attr.name == 'transform') {
|
}
|
||||||
inner.attr(attr.name).value = attr.value + ' ' + inner.attr(attr.name).value;
|
}
|
||||||
} else if (inner.hasAttr(attr.name, 'inherit')) {
|
|
||||||
inner.attr(attr.name).value = attr.value;
|
|
||||||
} else if (
|
|
||||||
attrsInheritable.indexOf(attr.name) < 0 &&
|
|
||||||
!inner.hasAttr(attr.name, attr.value)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g.removeAttr(attr.name);
|
// collapse groups without attributes
|
||||||
});
|
if (
|
||||||
}
|
!g.hasAttr() &&
|
||||||
}
|
!g.content.some(function (item) {
|
||||||
|
return item.isElem(animationElems);
|
||||||
// collapse groups without attributes
|
})
|
||||||
if (!g.hasAttr() && !g.content.some(function(item) { return item.isElem(animationElems) })) {
|
) {
|
||||||
item.spliceContent(i, 1, g.content);
|
item.spliceContent(i, 1, g.content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,19 +7,21 @@ exports.active = true;
|
|||||||
exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
|
exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
currentColor: false,
|
currentColor: false,
|
||||||
names2hex: true,
|
names2hex: true,
|
||||||
rgb2hex: true,
|
rgb2hex: true,
|
||||||
shorthex: true,
|
shorthex: true,
|
||||||
shortname: true
|
shortname: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var collections = require('./_collections'),
|
var collections = require('./_collections'),
|
||||||
rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)',
|
rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)',
|
||||||
rComma = '\\s*,\\s*',
|
rComma = '\\s*,\\s*',
|
||||||
regRGB = new RegExp('^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'),
|
regRGB = new RegExp(
|
||||||
regHEX = /^#(([a-fA-F0-9])\2){3}$/,
|
'^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'
|
||||||
none = /\bnone\b/i;
|
),
|
||||||
|
regHEX = /^#(([a-fA-F0-9])\2){3}$/,
|
||||||
|
none = /\bnone\b/i;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert different colors formats in element attributes to hex.
|
* Convert different colors formats in element attributes to hex.
|
||||||
@ -47,69 +49,60 @@ var collections = require('./_collections'),
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.elem) {
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
if (collections.colorsProps.indexOf(attr.name) > -1) {
|
||||||
|
var val = attr.value,
|
||||||
|
match;
|
||||||
|
|
||||||
if (item.elem) {
|
// Convert colors to currentColor
|
||||||
|
if (params.currentColor) {
|
||||||
|
if (typeof params.currentColor === 'string') {
|
||||||
|
match = val === params.currentColor;
|
||||||
|
} else if (params.currentColor.exec) {
|
||||||
|
match = params.currentColor.exec(val);
|
||||||
|
} else {
|
||||||
|
match = !val.match(none);
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
val = 'currentColor';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item.eachAttr(function(attr) {
|
// Convert color name keyword to long hex
|
||||||
|
if (params.names2hex && val.toLowerCase() in collections.colorsNames) {
|
||||||
|
val = collections.colorsNames[val.toLowerCase()];
|
||||||
|
}
|
||||||
|
|
||||||
if (collections.colorsProps.indexOf(attr.name) > -1) {
|
// Convert rgb() to long hex
|
||||||
|
if (params.rgb2hex && (match = val.match(regRGB))) {
|
||||||
|
match = match.slice(1, 4).map(function (m) {
|
||||||
|
if (m.indexOf('%') > -1) m = Math.round(parseFloat(m) * 2.55);
|
||||||
|
|
||||||
var val = attr.value,
|
return Math.max(0, Math.min(m, 255));
|
||||||
match;
|
});
|
||||||
|
|
||||||
// Convert colors to currentColor
|
val = rgb2hex(match);
|
||||||
if (params.currentColor) {
|
}
|
||||||
if (typeof params.currentColor === 'string') {
|
|
||||||
match = val === params.currentColor;
|
|
||||||
} else if (params.currentColor.exec) {
|
|
||||||
match = params.currentColor.exec(val);
|
|
||||||
} else {
|
|
||||||
match = !val.match(none);
|
|
||||||
}
|
|
||||||
if (match) {
|
|
||||||
val = 'currentColor';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert color name keyword to long hex
|
// Convert long hex to short hex
|
||||||
if (params.names2hex && val.toLowerCase() in collections.colorsNames) {
|
if (params.shorthex && (match = val.match(regHEX))) {
|
||||||
val = collections.colorsNames[val.toLowerCase()];
|
val = '#' + match[0][1] + match[0][3] + match[0][5];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert rgb() to long hex
|
// Convert hex to short name
|
||||||
if (params.rgb2hex && (match = val.match(regRGB))) {
|
if (params.shortname) {
|
||||||
match = match.slice(1, 4).map(function(m) {
|
var lowerVal = val.toLowerCase();
|
||||||
if (m.indexOf('%') > -1)
|
if (lowerVal in collections.colorsShortNames) {
|
||||||
m = Math.round(parseFloat(m) * 2.55);
|
val = collections.colorsShortNames[lowerVal];
|
||||||
|
}
|
||||||
return Math.max(0, Math.min(m, 255));
|
}
|
||||||
});
|
|
||||||
|
|
||||||
val = rgb2hex(match);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert long hex to short hex
|
|
||||||
if (params.shorthex && (match = val.match(regHEX))) {
|
|
||||||
val = '#' + match[0][1] + match[0][3] + match[0][5];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert hex to short name
|
|
||||||
if (params.shortname) {
|
|
||||||
var lowerVal = val.toLowerCase();
|
|
||||||
if (lowerVal in collections.colorsShortNames) {
|
|
||||||
val = collections.colorsShortNames[lowerVal];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.value = val;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
attr.value = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,5 +119,10 @@ exports.fn = function(item, params) {
|
|||||||
* @author Jed Schmidt
|
* @author Jed Schmidt
|
||||||
*/
|
*/
|
||||||
function rgb2hex(rgb) {
|
function rgb2hex(rgb) {
|
||||||
return '#' + ('00000' + (rgb[0] << 16 | rgb[1] << 8 | rgb[2]).toString(16)).slice(-6).toUpperCase();
|
return (
|
||||||
|
'#' +
|
||||||
|
('00000' + ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]).toString(16))
|
||||||
|
.slice(-6)
|
||||||
|
.toUpperCase()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -16,24 +16,26 @@ exports.description = 'converts non-eccentric <ellipse>s to <circle>s';
|
|||||||
*
|
*
|
||||||
* @author Taylor Hunt
|
* @author Taylor Hunt
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
if (item.isElem('ellipse')) {
|
if (item.isElem('ellipse')) {
|
||||||
var rx = item.hasAttr('rx') && item.attr('rx').value || 0;
|
var rx = (item.hasAttr('rx') && item.attr('rx').value) || 0;
|
||||||
var ry = item.hasAttr('ry') && item.attr('ry').value || 0;
|
var ry = (item.hasAttr('ry') && item.attr('ry').value) || 0;
|
||||||
|
|
||||||
if (rx === ry ||
|
if (
|
||||||
rx === 'auto' || ry === 'auto' // SVG2
|
rx === ry ||
|
||||||
) {
|
rx === 'auto' ||
|
||||||
var radius = rx !== 'auto' ? rx : ry;
|
ry === 'auto' // SVG2
|
||||||
item.renameElem('circle');
|
) {
|
||||||
item.removeAttr(['rx', 'ry']);
|
var radius = rx !== 'auto' ? rx : ry;
|
||||||
item.addAttr({
|
item.renameElem('circle');
|
||||||
name: 'r',
|
item.removeAttr(['rx', 'ry']);
|
||||||
value: radius,
|
item.addAttr({
|
||||||
prefix: '',
|
name: 'r',
|
||||||
local: 'r',
|
value: radius,
|
||||||
});
|
prefix: '',
|
||||||
}
|
local: 'r',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -7,34 +7,46 @@ exports.active = false;
|
|||||||
exports.description = 'converts style to attributes';
|
exports.description = 'converts style to attributes';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
keepImportant: false
|
keepImportant: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var stylingProps = require('./_collections').attrsGroups.presentation,
|
var stylingProps = require('./_collections').attrsGroups.presentation,
|
||||||
rEscape = '\\\\(?:[0-9a-f]{1,6}\\s?|\\r\\n|.)', // Like \" or \2051. Code points consume one space.
|
rEscape = '\\\\(?:[0-9a-f]{1,6}\\s?|\\r\\n|.)', // Like \" or \2051. Code points consume one space.
|
||||||
rAttr = '\\s*(' + g('[^:;\\\\]', rEscape) + '*?)\\s*', // attribute name like ‘fill’
|
rAttr = '\\s*(' + g('[^:;\\\\]', rEscape) + '*?)\\s*', // attribute name like ‘fill’
|
||||||
rSingleQuotes = "'(?:[^'\\n\\r\\\\]|" + rEscape + ")*?(?:'|$)", // string in single quotes: 'smth'
|
rSingleQuotes = "'(?:[^'\\n\\r\\\\]|" + rEscape + ")*?(?:'|$)", // string in single quotes: 'smth'
|
||||||
rQuotes = '"(?:[^"\\n\\r\\\\]|' + rEscape + ')*?(?:"|$)', // string in double quotes: "smth"
|
rQuotes = '"(?:[^"\\n\\r\\\\]|' + rEscape + ')*?(?:"|$)', // string in double quotes: "smth"
|
||||||
rQuotedString = new RegExp('^' + g(rSingleQuotes, rQuotes) + '$'),
|
rQuotedString = new RegExp('^' + g(rSingleQuotes, rQuotes) + '$'),
|
||||||
|
// Parentheses, E.g.: url(data:image/png;base64,iVBO...).
|
||||||
// Parentheses, E.g.: url(data:image/png;base64,iVBO...).
|
// ':' and ';' inside of it should be threated as is. (Just like in strings.)
|
||||||
// ':' and ';' inside of it should be threated as is. (Just like in strings.)
|
rParenthesis =
|
||||||
rParenthesis = '\\(' + g('[^\'"()\\\\]+', rEscape, rSingleQuotes, rQuotes) + '*?' + '\\)',
|
'\\(' + g('[^\'"()\\\\]+', rEscape, rSingleQuotes, rQuotes) + '*?' + '\\)',
|
||||||
|
// The value. It can have strings and parentheses (see above). Fallbacks to anything in case of unexpected input.
|
||||||
// The value. It can have strings and parentheses (see above). Fallbacks to anything in case of unexpected input.
|
rValue =
|
||||||
rValue = '\\s*(' + g('[^!\'"();\\\\]+?', rEscape, rSingleQuotes, rQuotes, rParenthesis, '[^;]*?') + '*?' + ')',
|
'\\s*(' +
|
||||||
|
g(
|
||||||
// End of declaration. Spaces outside of capturing groups help to do natural trimming.
|
'[^!\'"();\\\\]+?',
|
||||||
rDeclEnd = '\\s*(?:;\\s*|$)',
|
rEscape,
|
||||||
|
rSingleQuotes,
|
||||||
// Important rule
|
rQuotes,
|
||||||
rImportant = '(\\s*!important(?![-(\\w]))?',
|
rParenthesis,
|
||||||
|
'[^;]*?'
|
||||||
// Final RegExp to parse CSS declarations.
|
) +
|
||||||
regDeclarationBlock = new RegExp(rAttr + ':' + rValue + rImportant + rDeclEnd, 'ig'),
|
'*?' +
|
||||||
|
')',
|
||||||
// Comments expression. Honors escape sequences and strings.
|
// End of declaration. Spaces outside of capturing groups help to do natural trimming.
|
||||||
regStripComments = new RegExp(g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'), 'ig');
|
rDeclEnd = '\\s*(?:;\\s*|$)',
|
||||||
|
// Important rule
|
||||||
|
rImportant = '(\\s*!important(?![-(\\w]))?',
|
||||||
|
// Final RegExp to parse CSS declarations.
|
||||||
|
regDeclarationBlock = new RegExp(
|
||||||
|
rAttr + ':' + rValue + rImportant + rDeclEnd,
|
||||||
|
'ig'
|
||||||
|
),
|
||||||
|
// Comments expression. Honors escape sequences and strings.
|
||||||
|
regStripComments = new RegExp(
|
||||||
|
g(rEscape, rSingleQuotes, rQuotes, '/\\*[^]*?\\*/'),
|
||||||
|
'ig'
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert style in attributes. Cleanups comments and illegal declarations (without colon) as a side effect.
|
* Convert style in attributes. Cleanups comments and illegal declarations (without colon) as a side effect.
|
||||||
@ -54,71 +66,70 @@ var stylingProps = require('./_collections').attrsGroups.presentation,
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.elem && item.hasAttr('style')) {
|
||||||
|
// ['opacity: 1', 'color: #000']
|
||||||
|
var styleValue = item.attr('style').value,
|
||||||
|
styles = [],
|
||||||
|
attrs = {};
|
||||||
|
|
||||||
if (item.elem && item.hasAttr('style')) {
|
// Strip CSS comments preserving escape sequences and strings.
|
||||||
// ['opacity: 1', 'color: #000']
|
styleValue = styleValue.replace(regStripComments, function (match) {
|
||||||
var styleValue = item.attr('style').value,
|
return match[0] == '/'
|
||||||
styles = [],
|
? ''
|
||||||
attrs = {};
|
: match[0] == '\\' && /[-g-z]/i.test(match[1])
|
||||||
|
? match[1]
|
||||||
// Strip CSS comments preserving escape sequences and strings.
|
: match;
|
||||||
styleValue = styleValue.replace(regStripComments, function(match) {
|
});
|
||||||
return match[0] == '/' ? '' :
|
|
||||||
match[0] == '\\' && /[-g-z]/i.test(match[1]) ? match[1] : match;
|
|
||||||
});
|
|
||||||
|
|
||||||
regDeclarationBlock.lastIndex = 0;
|
|
||||||
// eslint-disable-next-line no-cond-assign
|
|
||||||
for (var rule; rule = regDeclarationBlock.exec(styleValue);) {
|
|
||||||
if (!params.keepImportant || !rule[3]) {
|
|
||||||
styles.push([rule[1], rule[2]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (styles.length) {
|
|
||||||
|
|
||||||
styles = styles.filter(function(style) {
|
|
||||||
if (style[0]) {
|
|
||||||
var prop = style[0].toLowerCase(),
|
|
||||||
val = style[1];
|
|
||||||
|
|
||||||
if (rQuotedString.test(val)) {
|
|
||||||
val = val.slice(1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stylingProps.indexOf(prop) > -1) {
|
|
||||||
|
|
||||||
attrs[prop] = {
|
|
||||||
name: prop,
|
|
||||||
value: val,
|
|
||||||
local: prop,
|
|
||||||
prefix: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.assign(item.attrs, attrs);
|
|
||||||
|
|
||||||
if (styles.length) {
|
|
||||||
item.attr('style').value = styles
|
|
||||||
.map(function(declaration) { return declaration.join(':') })
|
|
||||||
.join(';');
|
|
||||||
} else {
|
|
||||||
item.removeAttr('style');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
regDeclarationBlock.lastIndex = 0;
|
||||||
|
// eslint-disable-next-line no-cond-assign
|
||||||
|
for (var rule; (rule = regDeclarationBlock.exec(styleValue)); ) {
|
||||||
|
if (!params.keepImportant || !rule[3]) {
|
||||||
|
styles.push([rule[1], rule[2]]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (styles.length) {
|
||||||
|
styles = styles.filter(function (style) {
|
||||||
|
if (style[0]) {
|
||||||
|
var prop = style[0].toLowerCase(),
|
||||||
|
val = style[1];
|
||||||
|
|
||||||
|
if (rQuotedString.test(val)) {
|
||||||
|
val = val.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stylingProps.indexOf(prop) > -1) {
|
||||||
|
attrs[prop] = {
|
||||||
|
name: prop,
|
||||||
|
value: val,
|
||||||
|
local: prop,
|
||||||
|
prefix: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.assign(item.attrs, attrs);
|
||||||
|
|
||||||
|
if (styles.length) {
|
||||||
|
item.attr('style').value = styles
|
||||||
|
.map(function (declaration) {
|
||||||
|
return declaration.join(':');
|
||||||
|
})
|
||||||
|
.join(';');
|
||||||
|
} else {
|
||||||
|
item.removeAttr('style');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function g() {
|
function g() {
|
||||||
return '(?:' + Array.prototype.join.call(arguments, '|') + ')';
|
return '(?:' + Array.prototype.join.call(arguments, '|') + ')';
|
||||||
}
|
}
|
||||||
|
@ -7,27 +7,27 @@ exports.active = true;
|
|||||||
exports.description = 'collapses multiple transformations and optimizes it';
|
exports.description = 'collapses multiple transformations and optimizes it';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
convertToShorts: true,
|
convertToShorts: true,
|
||||||
// degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default
|
// degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default
|
||||||
floatPrecision: 3,
|
floatPrecision: 3,
|
||||||
transformPrecision: 5,
|
transformPrecision: 5,
|
||||||
matrixToTransform: true,
|
matrixToTransform: true,
|
||||||
shortTranslate: true,
|
shortTranslate: true,
|
||||||
shortScale: true,
|
shortScale: true,
|
||||||
shortRotate: true,
|
shortRotate: true,
|
||||||
removeUseless: true,
|
removeUseless: true,
|
||||||
collapseIntoOne: true,
|
collapseIntoOne: true,
|
||||||
leadingZero: true,
|
leadingZero: true,
|
||||||
negativeExtraSpace: false
|
negativeExtraSpace: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
|
var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
|
||||||
transform2js = require('./_transforms.js').transform2js,
|
transform2js = require('./_transforms.js').transform2js,
|
||||||
transformsMultiply = require('./_transforms.js').transformsMultiply,
|
transformsMultiply = require('./_transforms.js').transformsMultiply,
|
||||||
matrixToTransform = require('./_transforms.js').matrixToTransform,
|
matrixToTransform = require('./_transforms.js').matrixToTransform,
|
||||||
degRound,
|
degRound,
|
||||||
floatRound,
|
floatRound,
|
||||||
transformRound;
|
transformRound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert matrices to the short aliases,
|
* Convert matrices to the short aliases,
|
||||||
@ -43,27 +43,23 @@ var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.elem) {
|
||||||
if (item.elem) {
|
// transform
|
||||||
|
if (item.hasAttr('transform')) {
|
||||||
// transform
|
convertTransform(item, 'transform', params);
|
||||||
if (item.hasAttr('transform')) {
|
|
||||||
convertTransform(item, 'transform', params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// gradientTransform
|
|
||||||
if (item.hasAttr('gradientTransform')) {
|
|
||||||
convertTransform(item, 'gradientTransform', params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// patternTransform
|
|
||||||
if (item.hasAttr('patternTransform')) {
|
|
||||||
convertTransform(item, 'patternTransform', params);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gradientTransform
|
||||||
|
if (item.hasAttr('gradientTransform')) {
|
||||||
|
convertTransform(item, 'gradientTransform', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// patternTransform
|
||||||
|
if (item.hasAttr('patternTransform')) {
|
||||||
|
convertTransform(item, 'patternTransform', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,28 +70,28 @@ exports.fn = function(item, params) {
|
|||||||
* @param {Object} params plugin params
|
* @param {Object} params plugin params
|
||||||
*/
|
*/
|
||||||
function convertTransform(item, attrName, params) {
|
function convertTransform(item, attrName, params) {
|
||||||
var data = transform2js(item.attr(attrName).value);
|
var data = transform2js(item.attr(attrName).value);
|
||||||
params = definePrecision(data, params);
|
params = definePrecision(data, params);
|
||||||
|
|
||||||
if (params.collapseIntoOne && data.length > 1) {
|
if (params.collapseIntoOne && data.length > 1) {
|
||||||
data = [transformsMultiply(data)];
|
data = [transformsMultiply(data)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.convertToShorts) {
|
if (params.convertToShorts) {
|
||||||
data = convertToShorts(data, params);
|
data = convertToShorts(data, params);
|
||||||
} else {
|
} else {
|
||||||
data.forEach(roundTransform);
|
data.forEach(roundTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.removeUseless) {
|
if (params.removeUseless) {
|
||||||
data = removeUseless(data);
|
data = removeUseless(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.length) {
|
if (data.length) {
|
||||||
item.attr(attrName).value = js2transform(data, params);
|
item.attr(attrName).value = js2transform(data, params);
|
||||||
} else {
|
} else {
|
||||||
item.removeAttr(attrName);
|
item.removeAttr(attrName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,37 +106,49 @@ function convertTransform(item, attrName, params) {
|
|||||||
* @return {Array} output array
|
* @return {Array} output array
|
||||||
*/
|
*/
|
||||||
function definePrecision(data, params) {
|
function definePrecision(data, params) {
|
||||||
var matrixData = data.reduce(getMatrixData, []),
|
var matrixData = data.reduce(getMatrixData, []),
|
||||||
significantDigits = params.transformPrecision;
|
significantDigits = params.transformPrecision;
|
||||||
|
|
||||||
// Clone params so it don't affect other elements transformations.
|
// Clone params so it don't affect other elements transformations.
|
||||||
params = Object.assign({}, params);
|
params = Object.assign({}, params);
|
||||||
|
|
||||||
// Limit transform precision with matrix one. Calculating with larger precision doesn't add any value.
|
// Limit transform precision with matrix one. Calculating with larger precision doesn't add any value.
|
||||||
if (matrixData.length) {
|
if (matrixData.length) {
|
||||||
params.transformPrecision = Math.min(params.transformPrecision,
|
params.transformPrecision = Math.min(
|
||||||
Math.max.apply(Math, matrixData.map(floatDigits)) || params.transformPrecision);
|
params.transformPrecision,
|
||||||
|
Math.max.apply(Math, matrixData.map(floatDigits)) ||
|
||||||
|
params.transformPrecision
|
||||||
|
);
|
||||||
|
|
||||||
significantDigits = Math.max.apply(Math, matrixData.map(function(n) {
|
significantDigits = Math.max.apply(
|
||||||
return String(n).replace(/\D+/g, '').length; // Number of digits in a number. 123.45 → 5
|
Math,
|
||||||
}));
|
matrixData.map(function (n) {
|
||||||
}
|
return String(n).replace(/\D+/g, '').length; // Number of digits in a number. 123.45 → 5
|
||||||
// No sense in angle precision more then number of significant digits in matrix.
|
})
|
||||||
if (!('degPrecision' in params)) {
|
);
|
||||||
params.degPrecision = Math.max(0, Math.min(params.floatPrecision, significantDigits - 2));
|
}
|
||||||
}
|
// No sense in angle precision more then number of significant digits in matrix.
|
||||||
|
if (!('degPrecision' in params)) {
|
||||||
|
params.degPrecision = Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(params.floatPrecision, significantDigits - 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
floatRound = params.floatPrecision >= 1 && params.floatPrecision < 20 ?
|
floatRound =
|
||||||
smartRound.bind(this, params.floatPrecision) :
|
params.floatPrecision >= 1 && params.floatPrecision < 20
|
||||||
round;
|
? smartRound.bind(this, params.floatPrecision)
|
||||||
degRound = params.degPrecision >= 1 && params.floatPrecision < 20 ?
|
: round;
|
||||||
smartRound.bind(this, params.degPrecision) :
|
degRound =
|
||||||
round;
|
params.degPrecision >= 1 && params.floatPrecision < 20
|
||||||
transformRound = params.transformPrecision >= 1 && params.floatPrecision < 20 ?
|
? smartRound.bind(this, params.degPrecision)
|
||||||
smartRound.bind(this, params.transformPrecision) :
|
: round;
|
||||||
round;
|
transformRound =
|
||||||
|
params.transformPrecision >= 1 && params.floatPrecision < 20
|
||||||
|
? smartRound.bind(this, params.transformPrecision)
|
||||||
|
: round;
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,14 +159,14 @@ function definePrecision(data, params) {
|
|||||||
* @return {Array} output array
|
* @return {Array} output array
|
||||||
*/
|
*/
|
||||||
function getMatrixData(a, b) {
|
function getMatrixData(a, b) {
|
||||||
return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a;
|
return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns number of digits after the point. 0.125 → 3
|
* Returns number of digits after the point. 0.125 → 3
|
||||||
*/
|
*/
|
||||||
function floatDigits(n) {
|
function floatDigits(n) {
|
||||||
return (n = String(n)).slice(n.indexOf('.')).length - 1;
|
return (n = String(n)).slice(n.indexOf('.')).length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,79 +177,74 @@ function floatDigits(n) {
|
|||||||
* @return {Array} output array
|
* @return {Array} output array
|
||||||
*/
|
*/
|
||||||
function convertToShorts(transforms, params) {
|
function convertToShorts(transforms, params) {
|
||||||
|
for (var i = 0; i < transforms.length; i++) {
|
||||||
|
var transform = transforms[i];
|
||||||
|
|
||||||
for(var i = 0; i < transforms.length; i++) {
|
// convert matrix to the short aliases
|
||||||
|
if (params.matrixToTransform && transform.name === 'matrix') {
|
||||||
var transform = transforms[i];
|
var decomposed = matrixToTransform(transform, params);
|
||||||
|
if (
|
||||||
// convert matrix to the short aliases
|
decomposed != transform &&
|
||||||
if (
|
js2transform(decomposed, params).length <=
|
||||||
params.matrixToTransform &&
|
js2transform([transform], params).length
|
||||||
transform.name === 'matrix'
|
) {
|
||||||
) {
|
transforms.splice.apply(transforms, [i, 1].concat(decomposed));
|
||||||
var decomposed = matrixToTransform(transform, params);
|
}
|
||||||
if (decomposed != transform &&
|
transform = transforms[i];
|
||||||
js2transform(decomposed, params).length <= js2transform([transform], params).length) {
|
|
||||||
|
|
||||||
transforms.splice.apply(transforms, [i, 1].concat(decomposed));
|
|
||||||
}
|
|
||||||
transform = transforms[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixed-point numbers
|
|
||||||
// 12.754997 → 12.755
|
|
||||||
roundTransform(transform);
|
|
||||||
|
|
||||||
// convert long translate transform notation to the shorts one
|
|
||||||
// translate(10 0) → translate(10)
|
|
||||||
if (
|
|
||||||
params.shortTranslate &&
|
|
||||||
transform.name === 'translate' &&
|
|
||||||
transform.data.length === 2 &&
|
|
||||||
!transform.data[1]
|
|
||||||
) {
|
|
||||||
transform.data.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert long scale transform notation to the shorts one
|
|
||||||
// scale(2 2) → scale(2)
|
|
||||||
if (
|
|
||||||
params.shortScale &&
|
|
||||||
transform.name === 'scale' &&
|
|
||||||
transform.data.length === 2 &&
|
|
||||||
transform.data[0] === transform.data[1]
|
|
||||||
) {
|
|
||||||
transform.data.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert long rotate transform notation to the short one
|
|
||||||
// translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy)
|
|
||||||
if (
|
|
||||||
params.shortRotate &&
|
|
||||||
transforms[i - 2] &&
|
|
||||||
transforms[i - 2].name === 'translate' &&
|
|
||||||
transforms[i - 1].name === 'rotate' &&
|
|
||||||
transforms[i].name === 'translate' &&
|
|
||||||
transforms[i - 2].data[0] === -transforms[i].data[0] &&
|
|
||||||
transforms[i - 2].data[1] === -transforms[i].data[1]
|
|
||||||
) {
|
|
||||||
transforms.splice(i - 2, 3, {
|
|
||||||
name: 'rotate',
|
|
||||||
data: [
|
|
||||||
transforms[i - 1].data[0],
|
|
||||||
transforms[i - 2].data[0],
|
|
||||||
transforms[i - 2].data[1]
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// splice compensation
|
|
||||||
i -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return transforms;
|
// fixed-point numbers
|
||||||
|
// 12.754997 → 12.755
|
||||||
|
roundTransform(transform);
|
||||||
|
|
||||||
|
// convert long translate transform notation to the shorts one
|
||||||
|
// translate(10 0) → translate(10)
|
||||||
|
if (
|
||||||
|
params.shortTranslate &&
|
||||||
|
transform.name === 'translate' &&
|
||||||
|
transform.data.length === 2 &&
|
||||||
|
!transform.data[1]
|
||||||
|
) {
|
||||||
|
transform.data.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert long scale transform notation to the shorts one
|
||||||
|
// scale(2 2) → scale(2)
|
||||||
|
if (
|
||||||
|
params.shortScale &&
|
||||||
|
transform.name === 'scale' &&
|
||||||
|
transform.data.length === 2 &&
|
||||||
|
transform.data[0] === transform.data[1]
|
||||||
|
) {
|
||||||
|
transform.data.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert long rotate transform notation to the short one
|
||||||
|
// translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy)
|
||||||
|
if (
|
||||||
|
params.shortRotate &&
|
||||||
|
transforms[i - 2] &&
|
||||||
|
transforms[i - 2].name === 'translate' &&
|
||||||
|
transforms[i - 1].name === 'rotate' &&
|
||||||
|
transforms[i].name === 'translate' &&
|
||||||
|
transforms[i - 2].data[0] === -transforms[i].data[0] &&
|
||||||
|
transforms[i - 2].data[1] === -transforms[i].data[1]
|
||||||
|
) {
|
||||||
|
transforms.splice(i - 2, 3, {
|
||||||
|
name: 'rotate',
|
||||||
|
data: [
|
||||||
|
transforms[i - 1].data[0],
|
||||||
|
transforms[i - 2].data[0],
|
||||||
|
transforms[i - 2].data[1],
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// splice compensation
|
||||||
|
i -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return transforms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -251,38 +254,36 @@ function convertToShorts(transforms, params) {
|
|||||||
* @return {Array} output array
|
* @return {Array} output array
|
||||||
*/
|
*/
|
||||||
function removeUseless(transforms) {
|
function removeUseless(transforms) {
|
||||||
|
return transforms.filter(function (transform) {
|
||||||
|
// translate(0), rotate(0[, cx, cy]), skewX(0), skewY(0)
|
||||||
|
if (
|
||||||
|
(['translate', 'rotate', 'skewX', 'skewY'].indexOf(transform.name) > -1 &&
|
||||||
|
(transform.data.length == 1 || transform.name == 'rotate') &&
|
||||||
|
!transform.data[0]) ||
|
||||||
|
// translate(0, 0)
|
||||||
|
(transform.name == 'translate' &&
|
||||||
|
!transform.data[0] &&
|
||||||
|
!transform.data[1]) ||
|
||||||
|
// scale(1)
|
||||||
|
(transform.name == 'scale' &&
|
||||||
|
transform.data[0] == 1 &&
|
||||||
|
(transform.data.length < 2 || transform.data[1] == 1)) ||
|
||||||
|
// matrix(1 0 0 1 0 0)
|
||||||
|
(transform.name == 'matrix' &&
|
||||||
|
transform.data[0] == 1 &&
|
||||||
|
transform.data[3] == 1 &&
|
||||||
|
!(
|
||||||
|
transform.data[1] ||
|
||||||
|
transform.data[2] ||
|
||||||
|
transform.data[4] ||
|
||||||
|
transform.data[5]
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return transforms.filter(function(transform) {
|
return true;
|
||||||
|
});
|
||||||
// translate(0), rotate(0[, cx, cy]), skewX(0), skewY(0)
|
|
||||||
if (
|
|
||||||
['translate', 'rotate', 'skewX', 'skewY'].indexOf(transform.name) > -1 &&
|
|
||||||
(transform.data.length == 1 || transform.name == 'rotate') &&
|
|
||||||
!transform.data[0] ||
|
|
||||||
|
|
||||||
// translate(0, 0)
|
|
||||||
transform.name == 'translate' &&
|
|
||||||
!transform.data[0] &&
|
|
||||||
!transform.data[1] ||
|
|
||||||
|
|
||||||
// scale(1)
|
|
||||||
transform.name == 'scale' &&
|
|
||||||
transform.data[0] == 1 &&
|
|
||||||
(transform.data.length < 2 || transform.data[1] == 1) ||
|
|
||||||
|
|
||||||
// matrix(1 0 0 1 0 0)
|
|
||||||
transform.name == 'matrix' &&
|
|
||||||
transform.data[0] == 1 &&
|
|
||||||
transform.data[3] == 1 &&
|
|
||||||
!(transform.data[1] || transform.data[2] || transform.data[4] || transform.data[5])
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -293,39 +294,46 @@ function removeUseless(transforms) {
|
|||||||
* @return {String} output string
|
* @return {String} output string
|
||||||
*/
|
*/
|
||||||
function js2transform(transformJS, params) {
|
function js2transform(transformJS, params) {
|
||||||
|
var transformString = '';
|
||||||
|
|
||||||
var transformString = '';
|
// collect output value string
|
||||||
|
transformJS.forEach(function (transform) {
|
||||||
// collect output value string
|
roundTransform(transform);
|
||||||
transformJS.forEach(function(transform) {
|
transformString +=
|
||||||
roundTransform(transform);
|
(transformString && ' ') +
|
||||||
transformString += (transformString && ' ') + transform.name + '(' + cleanupOutData(transform.data, params) + ')';
|
transform.name +
|
||||||
});
|
'(' +
|
||||||
|
cleanupOutData(transform.data, params) +
|
||||||
return transformString;
|
')';
|
||||||
|
});
|
||||||
|
|
||||||
|
return transformString;
|
||||||
}
|
}
|
||||||
|
|
||||||
function roundTransform(transform) {
|
function roundTransform(transform) {
|
||||||
switch (transform.name) {
|
switch (transform.name) {
|
||||||
case 'translate':
|
case 'translate':
|
||||||
transform.data = floatRound(transform.data);
|
transform.data = floatRound(transform.data);
|
||||||
break;
|
break;
|
||||||
case 'rotate':
|
case 'rotate':
|
||||||
transform.data = degRound(transform.data.slice(0, 1)).concat(floatRound(transform.data.slice(1)));
|
transform.data = degRound(transform.data.slice(0, 1)).concat(
|
||||||
break;
|
floatRound(transform.data.slice(1))
|
||||||
case 'skewX':
|
);
|
||||||
case 'skewY':
|
break;
|
||||||
transform.data = degRound(transform.data);
|
case 'skewX':
|
||||||
break;
|
case 'skewY':
|
||||||
case 'scale':
|
transform.data = degRound(transform.data);
|
||||||
transform.data = transformRound(transform.data);
|
break;
|
||||||
break;
|
case 'scale':
|
||||||
case 'matrix':
|
transform.data = transformRound(transform.data);
|
||||||
transform.data = transformRound(transform.data.slice(0, 4)).concat(floatRound(transform.data.slice(4)));
|
break;
|
||||||
break;
|
case 'matrix':
|
||||||
}
|
transform.data = transformRound(transform.data.slice(0, 4)).concat(
|
||||||
return transform;
|
floatRound(transform.data.slice(4))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -335,7 +343,7 @@ function roundTransform(transform) {
|
|||||||
* @return {Array} output data array
|
* @return {Array} output data array
|
||||||
*/
|
*/
|
||||||
function round(data) {
|
function round(data) {
|
||||||
return data.map(Math.round);
|
return data.map(Math.round);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -348,13 +356,19 @@ function round(data) {
|
|||||||
* @return {Array} output data array
|
* @return {Array} output data array
|
||||||
*/
|
*/
|
||||||
function smartRound(precision, data) {
|
function smartRound(precision, data) {
|
||||||
for (var i = data.length, tolerance = +Math.pow(.1, precision).toFixed(precision); i--;) {
|
for (
|
||||||
if (data[i].toFixed(precision) != data[i]) {
|
var i = data.length,
|
||||||
var rounded = +data[i].toFixed(precision - 1);
|
tolerance = +Math.pow(0.1, precision).toFixed(precision);
|
||||||
data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance ?
|
i--;
|
||||||
+data[i].toFixed(precision) :
|
|
||||||
rounded;
|
) {
|
||||||
}
|
if (data[i].toFixed(precision) != data[i]) {
|
||||||
|
var rounded = +data[i].toFixed(precision - 1);
|
||||||
|
data[i] =
|
||||||
|
+Math.abs(rounded - data[i]).toFixed(precision + 1) >= tolerance
|
||||||
|
? +data[i].toFixed(precision)
|
||||||
|
: rounded;
|
||||||
}
|
}
|
||||||
return data;
|
}
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,19 @@ exports.type = 'full';
|
|||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'minifies styles and removes unused styles based on usage data';
|
exports.description =
|
||||||
|
'minifies styles and removes unused styles based on usage data';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
// ... CSSO options goes here
|
// ... CSSO options goes here
|
||||||
|
|
||||||
// additional
|
// additional
|
||||||
usage: {
|
usage: {
|
||||||
force: false, // force to use usage data even if it unsafe (document contains <script> or on* attributes)
|
force: false, // force to use usage data even if it unsafe (document contains <script> or on* attributes)
|
||||||
ids: true,
|
ids: true,
|
||||||
classes: true,
|
classes: true,
|
||||||
tags: true
|
tags: true,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var csso = require('csso');
|
var csso = require('csso');
|
||||||
@ -25,130 +26,146 @@ var csso = require('csso');
|
|||||||
*
|
*
|
||||||
* @author strarsis <strarsis@gmail.com>
|
* @author strarsis <strarsis@gmail.com>
|
||||||
*/
|
*/
|
||||||
exports.fn = function(ast, options) {
|
exports.fn = function (ast, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var minifyOptionsForStylesheet = cloneObject(options);
|
var minifyOptionsForStylesheet = cloneObject(options);
|
||||||
var minifyOptionsForAttribute = cloneObject(options);
|
var minifyOptionsForAttribute = cloneObject(options);
|
||||||
var elems = findStyleElems(ast);
|
var elems = findStyleElems(ast);
|
||||||
|
|
||||||
minifyOptionsForStylesheet.usage = collectUsageData(ast, options);
|
minifyOptionsForStylesheet.usage = collectUsageData(ast, options);
|
||||||
minifyOptionsForAttribute.usage = null;
|
minifyOptionsForAttribute.usage = null;
|
||||||
|
|
||||||
elems.forEach(function(elem) {
|
elems.forEach(function (elem) {
|
||||||
if (elem.isElem('style')) {
|
if (elem.isElem('style')) {
|
||||||
// <style> element
|
// <style> element
|
||||||
var styleCss = elem.content[0].text || elem.content[0].cdata || [];
|
var styleCss = elem.content[0].text || elem.content[0].cdata || [];
|
||||||
var DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text';
|
var DATA =
|
||||||
|
styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0
|
||||||
|
? 'cdata'
|
||||||
|
: 'text';
|
||||||
|
|
||||||
elem.content[0][DATA] = csso.minify(styleCss, minifyOptionsForStylesheet).css;
|
elem.content[0][DATA] = csso.minify(
|
||||||
} else {
|
styleCss,
|
||||||
// style attribute
|
minifyOptionsForStylesheet
|
||||||
var elemStyle = elem.attr('style').value;
|
).css;
|
||||||
|
} else {
|
||||||
|
// style attribute
|
||||||
|
var elemStyle = elem.attr('style').value;
|
||||||
|
|
||||||
elem.attr('style').value = csso.minifyBlock(elemStyle, minifyOptionsForAttribute).css;
|
elem.attr('style').value = csso.minifyBlock(
|
||||||
}
|
elemStyle,
|
||||||
});
|
minifyOptionsForAttribute
|
||||||
|
).css;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return ast;
|
return ast;
|
||||||
};
|
};
|
||||||
|
|
||||||
function cloneObject(obj) {
|
function cloneObject(obj) {
|
||||||
return {...obj};
|
return { ...obj };
|
||||||
}
|
}
|
||||||
|
|
||||||
function findStyleElems(ast) {
|
function findStyleElems(ast) {
|
||||||
|
function walk(items, styles) {
|
||||||
|
for (var i = 0; i < items.content.length; i++) {
|
||||||
|
var item = items.content[i];
|
||||||
|
|
||||||
function walk(items, styles) {
|
// go deeper
|
||||||
for (var i = 0; i < items.content.length; i++) {
|
if (item.content) {
|
||||||
var item = items.content[i];
|
walk(item, styles);
|
||||||
|
}
|
||||||
|
|
||||||
// go deeper
|
if (item.isElem('style') && !item.isEmpty()) {
|
||||||
if (item.content) {
|
styles.push(item);
|
||||||
walk(item, styles);
|
} else if (item.isElem() && item.hasAttr('style')) {
|
||||||
}
|
styles.push(item);
|
||||||
|
}
|
||||||
if (item.isElem('style') && !item.isEmpty()) {
|
|
||||||
styles.push(item);
|
|
||||||
} else if (item.isElem() && item.hasAttr('style')) {
|
|
||||||
styles.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return styles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return walk(ast, []);
|
return styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
return walk(ast, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldFilter(options, name) {
|
function shouldFilter(options, name) {
|
||||||
if ('usage' in options === false) {
|
if ('usage' in options === false) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.usage && name in options.usage === false) {
|
if (options.usage && name in options.usage === false) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boolean(options.usage && options.usage[name]);
|
return Boolean(options.usage && options.usage[name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function collectUsageData(ast, options) {
|
function collectUsageData(ast, options) {
|
||||||
|
function walk(items, usageData) {
|
||||||
|
for (var i = 0; i < items.content.length; i++) {
|
||||||
|
var item = items.content[i];
|
||||||
|
|
||||||
function walk(items, usageData) {
|
// go deeper
|
||||||
for (var i = 0; i < items.content.length; i++) {
|
if (item.content) {
|
||||||
var item = items.content[i];
|
walk(item, usageData);
|
||||||
|
}
|
||||||
|
|
||||||
// go deeper
|
if (item.isElem('script')) {
|
||||||
if (item.content) {
|
safe = false;
|
||||||
walk(item, usageData);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isElem('script')) {
|
if (item.isElem()) {
|
||||||
safe = false;
|
usageData.tags[item.elem] = true;
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isElem()) {
|
if (item.hasAttr('id')) {
|
||||||
usageData.tags[item.elem] = true;
|
usageData.ids[item.attr('id').value] = true;
|
||||||
|
|
||||||
if (item.hasAttr('id')) {
|
|
||||||
usageData.ids[item.attr('id').value] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.hasAttr('class')) {
|
|
||||||
item.attr('class').value.replace(/^\s+|\s+$/g, '').split(/\s+/).forEach(function(className) {
|
|
||||||
usageData.classes[className] = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.attrs && Object.keys(item.attrs).some(function(name) { return /^on/i.test(name); })) {
|
|
||||||
safe = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return usageData;
|
if (item.hasAttr('class')) {
|
||||||
}
|
item
|
||||||
|
.attr('class')
|
||||||
var safe = true;
|
.value.replace(/^\s+|\s+$/g, '')
|
||||||
var usageData = {};
|
.split(/\s+/)
|
||||||
var hasData = false;
|
.forEach(function (className) {
|
||||||
var rawData = walk(ast, {
|
usageData.classes[className] = true;
|
||||||
ids: Object.create(null),
|
});
|
||||||
classes: Object.create(null),
|
|
||||||
tags: Object.create(null)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!safe && options.usage && options.usage.force) {
|
|
||||||
safe = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [key, data] of Object.entries(rawData)) {
|
|
||||||
if (shouldFilter(options, key)) {
|
|
||||||
usageData[key] = Object.keys(data);
|
|
||||||
hasData = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
item.attrs &&
|
||||||
|
Object.keys(item.attrs).some(function (name) {
|
||||||
|
return /^on/i.test(name);
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
safe = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return safe && hasData ? usageData : null;
|
return usageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
var safe = true;
|
||||||
|
var usageData = {};
|
||||||
|
var hasData = false;
|
||||||
|
var rawData = walk(ast, {
|
||||||
|
ids: Object.create(null),
|
||||||
|
classes: Object.create(null),
|
||||||
|
tags: Object.create(null),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!safe && options.usage && options.usage.force) {
|
||||||
|
safe = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, data] of Object.entries(rawData)) {
|
||||||
|
if (shouldFilter(options, key)) {
|
||||||
|
usageData[key] = Object.keys(data);
|
||||||
|
hasData = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return safe && hasData ? usageData : null;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ exports.active = true;
|
|||||||
exports.description = 'moves elements attributes to the existing group wrapper';
|
exports.description = 'moves elements attributes to the existing group wrapper';
|
||||||
|
|
||||||
var inheritableAttrs = require('./_collections').inheritableAttrs,
|
var inheritableAttrs = require('./_collections').inheritableAttrs,
|
||||||
pathElems = require('./_collections.js').pathElems;
|
pathElems = require('./_collections.js').pathElems;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collapse content's intersected and inheritable
|
* Collapse content's intersected and inheritable
|
||||||
@ -33,65 +33,54 @@ var inheritableAttrs = require('./_collections').inheritableAttrs,
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.isElem('g') && !item.isEmpty() && item.content.length > 1) {
|
||||||
|
var intersection = {},
|
||||||
|
hasTransform = false,
|
||||||
|
hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'),
|
||||||
|
intersected = item.content.every(function (inner) {
|
||||||
|
if (inner.isElem() && inner.hasAttr()) {
|
||||||
|
// don't mess with possible styles (hack until CSS parsing is implemented)
|
||||||
|
if (inner.hasAttr('class')) return false;
|
||||||
|
if (!Object.keys(intersection).length) {
|
||||||
|
intersection = inner.attrs;
|
||||||
|
} else {
|
||||||
|
intersection = intersectInheritableAttrs(intersection, inner.attrs);
|
||||||
|
|
||||||
if (item.isElem('g') && !item.isEmpty() && item.content.length > 1) {
|
if (!intersection) return false;
|
||||||
|
}
|
||||||
var intersection = {},
|
|
||||||
hasTransform = false,
|
|
||||||
hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'),
|
|
||||||
intersected = item.content.every(function(inner) {
|
|
||||||
if (inner.isElem() && inner.hasAttr()) {
|
|
||||||
// don't mess with possible styles (hack until CSS parsing is implemented)
|
|
||||||
if (inner.hasAttr('class')) return false;
|
|
||||||
if (!Object.keys(intersection).length) {
|
|
||||||
intersection = inner.attrs;
|
|
||||||
} else {
|
|
||||||
intersection = intersectInheritableAttrs(intersection, inner.attrs);
|
|
||||||
|
|
||||||
if (!intersection) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
allPath = item.content.every(function(inner) {
|
|
||||||
return inner.isElem(pathElems);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (intersected) {
|
|
||||||
|
|
||||||
item.content.forEach(function(g) {
|
|
||||||
|
|
||||||
for (const [name, attr] of Object.entries(intersection)) {
|
|
||||||
|
|
||||||
if (!allPath && !hasClip || name !== 'transform') {
|
|
||||||
|
|
||||||
g.removeAttr(name);
|
|
||||||
|
|
||||||
if (name === 'transform') {
|
|
||||||
if (!hasTransform) {
|
|
||||||
if (item.hasAttr('transform')) {
|
|
||||||
item.attr('transform').value += ' ' + attr.value;
|
|
||||||
} else {
|
|
||||||
item.addAttr(attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasTransform = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item.addAttr(attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
allPath = item.content.every(function (inner) {
|
||||||
|
return inner.isElem(pathElems);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (intersected) {
|
||||||
|
item.content.forEach(function (g) {
|
||||||
|
for (const [name, attr] of Object.entries(intersection)) {
|
||||||
|
if ((!allPath && !hasClip) || name !== 'transform') {
|
||||||
|
g.removeAttr(name);
|
||||||
|
|
||||||
|
if (name === 'transform') {
|
||||||
|
if (!hasTransform) {
|
||||||
|
if (item.hasAttr('transform')) {
|
||||||
|
item.attr('transform').value += ' ' + attr.value;
|
||||||
|
} else {
|
||||||
|
item.addAttr(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasTransform = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.addAttr(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,25 +92,23 @@ exports.fn = function(item) {
|
|||||||
* @return {Object} intersected attrs object
|
* @return {Object} intersected attrs object
|
||||||
*/
|
*/
|
||||||
function intersectInheritableAttrs(a, b) {
|
function intersectInheritableAttrs(a, b) {
|
||||||
|
var c = {};
|
||||||
|
|
||||||
var c = {};
|
for (const [n, attr] of Object.entries(a)) {
|
||||||
|
if (
|
||||||
for (const [n, attr] of Object.entries(a)) {
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
if (
|
b.hasOwnProperty(n) &&
|
||||||
// eslint-disable-next-line no-prototype-builtins
|
inheritableAttrs.indexOf(n) > -1 &&
|
||||||
b.hasOwnProperty(n) &&
|
attr.name === b[n].name &&
|
||||||
inheritableAttrs.indexOf(n) > -1 &&
|
attr.value === b[n].value &&
|
||||||
attr.name === b[n].name &&
|
attr.prefix === b[n].prefix &&
|
||||||
attr.value === b[n].value &&
|
attr.local === b[n].local
|
||||||
attr.prefix === b[n].prefix &&
|
) {
|
||||||
attr.local === b[n].local
|
c[n] = attr;
|
||||||
) {
|
|
||||||
c[n] = attr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!Object.keys(c).length) return false;
|
if (!Object.keys(c).length) return false;
|
||||||
|
|
||||||
return c;
|
|
||||||
|
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ exports.active = true;
|
|||||||
exports.description = 'moves some group attributes to the content elements';
|
exports.description = 'moves some group attributes to the content elements';
|
||||||
|
|
||||||
var collections = require('./_collections.js'),
|
var collections = require('./_collections.js'),
|
||||||
pathElems = collections.pathElems.concat(['g', 'text']),
|
pathElems = collections.pathElems.concat(['g', 'text']),
|
||||||
referencesProps = collections.referencesProps;
|
referencesProps = collections.referencesProps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move group attrs to the content elements.
|
* Move group attrs to the content elements.
|
||||||
@ -29,35 +29,34 @@ var collections = require('./_collections.js'),
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
// move group transform attr to content's pathElems
|
||||||
// move group transform attr to content's pathElems
|
if (
|
||||||
if (
|
item.isElem('g') &&
|
||||||
item.isElem('g') &&
|
item.hasAttr('transform') &&
|
||||||
item.hasAttr('transform') &&
|
!item.isEmpty() &&
|
||||||
!item.isEmpty() &&
|
!item.someAttr(function (attr) {
|
||||||
!item.someAttr(function(attr) {
|
return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
|
||||||
return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
|
}) &&
|
||||||
}) &&
|
item.content.every(function (inner) {
|
||||||
item.content.every(function(inner) {
|
return inner.isElem(pathElems) && !inner.hasAttr('id');
|
||||||
return inner.isElem(pathElems) && !inner.hasAttr('id');
|
})
|
||||||
})
|
) {
|
||||||
) {
|
item.content.forEach(function (inner) {
|
||||||
item.content.forEach(function(inner) {
|
var attr = item.attr('transform');
|
||||||
var attr = item.attr('transform');
|
if (inner.hasAttr('transform')) {
|
||||||
if (inner.hasAttr('transform')) {
|
inner.attr('transform').value =
|
||||||
inner.attr('transform').value = attr.value + ' ' + inner.attr('transform').value;
|
attr.value + ' ' + inner.attr('transform').value;
|
||||||
} else {
|
} else {
|
||||||
inner.addAttr({
|
inner.addAttr({
|
||||||
'name': attr.name,
|
name: attr.name,
|
||||||
'local': attr.local,
|
local: attr.local,
|
||||||
'prefix': attr.prefix,
|
prefix: attr.prefix,
|
||||||
'value': attr.value
|
value: attr.value,
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
item.removeAttr('transform');
|
item.removeAttr('transform');
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -5,148 +5,147 @@ exports.type = 'perItem';
|
|||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
delim: '__',
|
delim: '__',
|
||||||
prefixIds: true,
|
prefixIds: true,
|
||||||
prefixClassNames: true,
|
prefixClassNames: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.description = 'prefix IDs';
|
exports.description = 'prefix IDs';
|
||||||
|
|
||||||
var csstree = require('css-tree'),
|
var csstree = require('css-tree'),
|
||||||
collections = require('./_collections.js'),
|
collections = require('./_collections.js'),
|
||||||
referencesProps = collections.referencesProps,
|
referencesProps = collections.referencesProps,
|
||||||
rxId = /^#(.*)$/, // regular expression for matching an ID + extracing its name
|
rxId = /^#(.*)$/, // regular expression for matching an ID + extracing its name
|
||||||
addPrefix = null;
|
addPrefix = null;
|
||||||
|
|
||||||
const unquote = (string) => {
|
const unquote = (string) => {
|
||||||
const first = string.charAt(0)
|
const first = string.charAt(0);
|
||||||
if (first === "'" || first === '"') {
|
if (first === "'" || first === '"') {
|
||||||
if (first === string.charAt(string.length - 1)) {
|
if (first === string.charAt(string.length - 1)) {
|
||||||
return string.slice(1, -1);
|
return string.slice(1, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string;
|
return string;
|
||||||
}
|
};
|
||||||
|
|
||||||
// Escapes a string for being used as ID
|
// Escapes a string for being used as ID
|
||||||
var escapeIdentifierName = function(str) {
|
var escapeIdentifierName = function (str) {
|
||||||
return str.replace(/[. ]/g, '_');
|
return str.replace(/[. ]/g, '_');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Matches an #ID value, captures the ID name
|
// Matches an #ID value, captures the ID name
|
||||||
var matchId = function(urlVal) {
|
var matchId = function (urlVal) {
|
||||||
var idUrlMatches = urlVal.match(rxId);
|
var idUrlMatches = urlVal.match(rxId);
|
||||||
if (idUrlMatches === null) {
|
if (idUrlMatches === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return idUrlMatches[1];
|
return idUrlMatches[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Matches an url(...) value, captures the URL
|
// Matches an url(...) value, captures the URL
|
||||||
var matchUrl = function(val) {
|
var matchUrl = function (val) {
|
||||||
var urlMatches = /url\((.*?)\)/gi.exec(val);
|
var urlMatches = /url\((.*?)\)/gi.exec(val);
|
||||||
if (urlMatches === null) {
|
if (urlMatches === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return urlMatches[1];
|
return urlMatches[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks if attribute is empty
|
// Checks if attribute is empty
|
||||||
var attrNotEmpty = function(attr) {
|
var attrNotEmpty = function (attr) {
|
||||||
return (attr && attr.value && attr.value.length > 0);
|
return attr && attr.value && attr.value.length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// prefixes an #ID
|
// prefixes an #ID
|
||||||
var prefixId = function(val) {
|
var prefixId = function (val) {
|
||||||
var idName = matchId(val);
|
var idName = matchId(val);
|
||||||
if (!idName) {
|
if (!idName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return '#' + addPrefix(idName);
|
return '#' + addPrefix(idName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// attr.value helper methods
|
// attr.value helper methods
|
||||||
|
|
||||||
// prefixes a class attribute value
|
// prefixes a class attribute value
|
||||||
var addPrefixToClassAttr = function(attr) {
|
var addPrefixToClassAttr = function (attr) {
|
||||||
if (!attrNotEmpty(attr)) {
|
if (!attrNotEmpty(attr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.value = attr.value.split(/\s+/).map(addPrefix).join(' ');
|
attr.value = attr.value.split(/\s+/).map(addPrefix).join(' ');
|
||||||
};
|
};
|
||||||
|
|
||||||
// prefixes an ID attribute value
|
// prefixes an ID attribute value
|
||||||
var addPrefixToIdAttr = function(attr) {
|
var addPrefixToIdAttr = function (attr) {
|
||||||
if (!attrNotEmpty(attr)) {
|
if (!attrNotEmpty(attr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.value = addPrefix(attr.value);
|
attr.value = addPrefix(attr.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
// prefixes a href attribute value
|
// prefixes a href attribute value
|
||||||
var addPrefixToHrefAttr = function(attr) {
|
var addPrefixToHrefAttr = function (attr) {
|
||||||
if (!attrNotEmpty(attr)) {
|
if (!attrNotEmpty(attr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var idPrefixed = prefixId(attr.value);
|
var idPrefixed = prefixId(attr.value);
|
||||||
if (!idPrefixed) {
|
if (!idPrefixed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
attr.value = idPrefixed;
|
attr.value = idPrefixed;
|
||||||
};
|
};
|
||||||
|
|
||||||
// prefixes an URL attribute value
|
// prefixes an URL attribute value
|
||||||
var addPrefixToUrlAttr = function(attr) {
|
var addPrefixToUrlAttr = function (attr) {
|
||||||
if (!attrNotEmpty(attr)) {
|
if (!attrNotEmpty(attr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// url(...) in value
|
// url(...) in value
|
||||||
var urlVal = matchUrl(attr.value);
|
var urlVal = matchUrl(attr.value);
|
||||||
if (!urlVal) {
|
if (!urlVal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var idPrefixed = prefixId(urlVal);
|
var idPrefixed = prefixId(urlVal);
|
||||||
if (!idPrefixed) {
|
if (!idPrefixed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.value = 'url(' + idPrefixed + ')';
|
attr.value = 'url(' + idPrefixed + ')';
|
||||||
};
|
};
|
||||||
|
|
||||||
// prefixes begin/end attribute value
|
// prefixes begin/end attribute value
|
||||||
var addPrefixToBeginEndAttr = function(attr) {
|
var addPrefixToBeginEndAttr = function (attr) {
|
||||||
if (!attrNotEmpty(attr)) {
|
if (!attrNotEmpty(attr)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts = attr.value.split('; ').map(function (val) {
|
||||||
|
val = val.trim();
|
||||||
|
|
||||||
|
if (val.endsWith('.end') || val.endsWith('.start')) {
|
||||||
|
var idPostfix = val.split('.'),
|
||||||
|
id = idPostfix[0],
|
||||||
|
postfix = idPostfix[1];
|
||||||
|
|
||||||
|
var idPrefixed = prefixId(`#${id}`);
|
||||||
|
|
||||||
|
if (!idPrefixed) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
idPrefixed = idPrefixed.slice(1);
|
||||||
|
return `${idPrefixed}.${postfix}`;
|
||||||
|
} else {
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var parts = attr.value.split('; ').map(function(val) {
|
attr.value = parts.join('; ');
|
||||||
val = val.trim();
|
|
||||||
|
|
||||||
if (val.endsWith('.end') || val.endsWith('.start')) {
|
|
||||||
var idPostfix = val.split('.'),
|
|
||||||
id = idPostfix[0],
|
|
||||||
postfix = idPostfix[1];
|
|
||||||
|
|
||||||
var idPrefixed = prefixId(`#${id}`);
|
|
||||||
|
|
||||||
if (!idPrefixed) {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
idPrefixed = idPrefixed.slice(1);
|
|
||||||
return `${idPrefixed}.${postfix}`;
|
|
||||||
} else {
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
attr.value = parts.join('; ');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBasename = (path) => {
|
const getBasename = (path) => {
|
||||||
@ -167,123 +166,123 @@ const getBasename = (path) => {
|
|||||||
*
|
*
|
||||||
* @author strarsis <strarsis@gmail.com>
|
* @author strarsis <strarsis@gmail.com>
|
||||||
*/
|
*/
|
||||||
exports.fn = function(node, opts, extra) {
|
exports.fn = function (node, opts, extra) {
|
||||||
|
// skip subsequent passes when multipass is used
|
||||||
// skip subsequent passes when multipass is used
|
if (extra.multipassCount && extra.multipassCount > 0) {
|
||||||
if(extra.multipassCount && extra.multipassCount > 0) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefix, from file name or option
|
|
||||||
var prefix = 'prefix';
|
|
||||||
if (opts.prefix) {
|
|
||||||
if (typeof opts.prefix === 'function') {
|
|
||||||
prefix = opts.prefix(node, extra);
|
|
||||||
} else {
|
|
||||||
prefix = opts.prefix;
|
|
||||||
}
|
|
||||||
} else if (opts.prefix === false) {
|
|
||||||
prefix = false;
|
|
||||||
} else if (extra && extra.path && extra.path.length > 0) {
|
|
||||||
var filename = getBasename(extra.path);
|
|
||||||
prefix = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// prefixes a normal value
|
|
||||||
addPrefix = function(name) {
|
|
||||||
if(prefix === false){
|
|
||||||
return escapeIdentifierName(name);
|
|
||||||
}
|
|
||||||
return escapeIdentifierName(prefix + opts.delim + name);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// <style/> property values
|
|
||||||
|
|
||||||
if (node.elem === 'style') {
|
|
||||||
if (node.isEmpty()) {
|
|
||||||
// skip empty <style/>s
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cssStr = node.content[0].text || node.content[0].cdata || [];
|
|
||||||
|
|
||||||
var cssAst = {};
|
|
||||||
try {
|
|
||||||
cssAst = csstree.parse(cssStr, {
|
|
||||||
parseValue: true,
|
|
||||||
parseCustomProperty: false
|
|
||||||
});
|
|
||||||
} catch (parseError) {
|
|
||||||
console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
var idPrefixed = '';
|
|
||||||
csstree.walk(cssAst, function(node) {
|
|
||||||
|
|
||||||
// #ID, .class
|
|
||||||
if (((opts.prefixIds && node.type === 'IdSelector') ||
|
|
||||||
(opts.prefixClassNames && node.type === 'ClassSelector')) &&
|
|
||||||
node.name) {
|
|
||||||
node.name = addPrefix(node.name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// url(...) in value
|
|
||||||
if (node.type === 'Url' &&
|
|
||||||
node.value.value && node.value.value.length > 0) {
|
|
||||||
idPrefixed = prefixId(unquote(node.value.value));
|
|
||||||
if (!idPrefixed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
node.value.value = idPrefixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// update <style>s
|
|
||||||
node.content[0].text = csstree.generate(cssAst);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// element attributes
|
|
||||||
|
|
||||||
if (!node.attrs) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Nodes
|
|
||||||
|
|
||||||
if(opts.prefixIds) {
|
|
||||||
// ID
|
|
||||||
addPrefixToIdAttr(node.attrs.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(opts.prefixClassNames) {
|
|
||||||
// Class
|
|
||||||
addPrefixToClassAttr(node.attrs.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// References
|
|
||||||
|
|
||||||
// href
|
|
||||||
addPrefixToHrefAttr(node.attrs.href);
|
|
||||||
|
|
||||||
// (xlink:)href (deprecated, must be still supported)
|
|
||||||
addPrefixToHrefAttr(node.attrs['xlink:href']);
|
|
||||||
|
|
||||||
// (referenceable) properties
|
|
||||||
for (var referencesProp of referencesProps) {
|
|
||||||
addPrefixToUrlAttr(node.attrs[referencesProp]);
|
|
||||||
}
|
|
||||||
|
|
||||||
addPrefixToBeginEndAttr(node.attrs.begin);
|
|
||||||
addPrefixToBeginEndAttr(node.attrs.end);
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefix, from file name or option
|
||||||
|
var prefix = 'prefix';
|
||||||
|
if (opts.prefix) {
|
||||||
|
if (typeof opts.prefix === 'function') {
|
||||||
|
prefix = opts.prefix(node, extra);
|
||||||
|
} else {
|
||||||
|
prefix = opts.prefix;
|
||||||
|
}
|
||||||
|
} else if (opts.prefix === false) {
|
||||||
|
prefix = false;
|
||||||
|
} else if (extra && extra.path && extra.path.length > 0) {
|
||||||
|
var filename = getBasename(extra.path);
|
||||||
|
prefix = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefixes a normal value
|
||||||
|
addPrefix = function (name) {
|
||||||
|
if (prefix === false) {
|
||||||
|
return escapeIdentifierName(name);
|
||||||
|
}
|
||||||
|
return escapeIdentifierName(prefix + opts.delim + name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// <style/> property values
|
||||||
|
|
||||||
|
if (node.elem === 'style') {
|
||||||
|
if (node.isEmpty()) {
|
||||||
|
// skip empty <style/>s
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cssStr = node.content[0].text || node.content[0].cdata || [];
|
||||||
|
|
||||||
|
var cssAst = {};
|
||||||
|
try {
|
||||||
|
cssAst = csstree.parse(cssStr, {
|
||||||
|
parseValue: true,
|
||||||
|
parseCustomProperty: false,
|
||||||
|
});
|
||||||
|
} catch (parseError) {
|
||||||
|
console.warn(
|
||||||
|
'Warning: Parse error of styles of <style/> element, skipped. Error details: ' +
|
||||||
|
parseError
|
||||||
|
);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
var idPrefixed = '';
|
||||||
|
csstree.walk(cssAst, function (node) {
|
||||||
|
// #ID, .class
|
||||||
|
if (
|
||||||
|
((opts.prefixIds && node.type === 'IdSelector') ||
|
||||||
|
(opts.prefixClassNames && node.type === 'ClassSelector')) &&
|
||||||
|
node.name
|
||||||
|
) {
|
||||||
|
node.name = addPrefix(node.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// url(...) in value
|
||||||
|
if (
|
||||||
|
node.type === 'Url' &&
|
||||||
|
node.value.value &&
|
||||||
|
node.value.value.length > 0
|
||||||
|
) {
|
||||||
|
idPrefixed = prefixId(unquote(node.value.value));
|
||||||
|
if (!idPrefixed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node.value.value = idPrefixed;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// update <style>s
|
||||||
|
node.content[0].text = csstree.generate(cssAst);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// element attributes
|
||||||
|
|
||||||
|
if (!node.attrs) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
|
||||||
|
if (opts.prefixIds) {
|
||||||
|
// ID
|
||||||
|
addPrefixToIdAttr(node.attrs.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.prefixClassNames) {
|
||||||
|
// Class
|
||||||
|
addPrefixToClassAttr(node.attrs.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// References
|
||||||
|
|
||||||
|
// href
|
||||||
|
addPrefixToHrefAttr(node.attrs.href);
|
||||||
|
|
||||||
|
// (xlink:)href (deprecated, must be still supported)
|
||||||
|
addPrefixToHrefAttr(node.attrs['xlink:href']);
|
||||||
|
|
||||||
|
// (referenceable) properties
|
||||||
|
for (var referencesProp of referencesProps) {
|
||||||
|
addPrefixToUrlAttr(node.attrs[referencesProp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPrefixToBeginEndAttr(node.attrs.begin);
|
||||||
|
addPrefixToBeginEndAttr(node.attrs.end);
|
||||||
|
|
||||||
|
return node;
|
||||||
};
|
};
|
||||||
|
@ -4,8 +4,8 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.description = 'removes attributes of elements that match a css selector';
|
exports.description =
|
||||||
|
'removes attributes of elements that match a css selector';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes attributes of elements that match a css selector.
|
* Removes attributes of elements that match a css selector.
|
||||||
@ -23,7 +23,7 @@ exports.description = 'removes attributes of elements that match a css selector'
|
|||||||
*
|
*
|
||||||
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
||||||
* ↓
|
* ↓
|
||||||
* <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/>
|
* <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/>
|
||||||
*
|
*
|
||||||
* <caption>A selector removing multiple attributes</caption>
|
* <caption>A selector removing multiple attributes</caption>
|
||||||
* plugins:
|
* plugins:
|
||||||
@ -35,7 +35,7 @@ exports.description = 'removes attributes of elements that match a css selector'
|
|||||||
*
|
*
|
||||||
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
|
||||||
* ↓
|
* ↓
|
||||||
* <rect x="0" y="0" width="100" height="100"/>
|
* <rect x="0" y="0" width="100" height="100"/>
|
||||||
*
|
*
|
||||||
* <caption>Multiple selectors removing attributes</caption>
|
* <caption>Multiple selectors removing attributes</caption>
|
||||||
* plugins:
|
* plugins:
|
||||||
@ -57,14 +57,12 @@ exports.description = 'removes attributes of elements that match a css selector'
|
|||||||
*
|
*
|
||||||
* @author Bradley Mease
|
* @author Bradley Mease
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
var selectors = Array.isArray(params.selectors) ? params.selectors : [params];
|
||||||
var selectors = Array.isArray(params.selectors) ? params.selectors : [params];
|
|
||||||
|
|
||||||
selectors.map(function(i) {
|
|
||||||
if (item.matches(i.selector)) {
|
|
||||||
item.removeAttr(i.attributes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
selectors.map(function (i) {
|
||||||
|
if (item.matches(i.selector)) {
|
||||||
|
item.removeAttr(i.attributes);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -9,9 +9,9 @@ exports.active = false;
|
|||||||
exports.description = 'removes specified attributes';
|
exports.description = 'removes specified attributes';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
elemSeparator: DEFAULT_SEPARATOR,
|
elemSeparator: DEFAULT_SEPARATOR,
|
||||||
preserveCurrentColor: false,
|
preserveCurrentColor: false,
|
||||||
attrs: []
|
attrs: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,70 +81,68 @@ exports.params = {
|
|||||||
*
|
*
|
||||||
* @author Benny Schudel
|
* @author Benny Schudel
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
// wrap into an array if params is not
|
// wrap into an array if params is not
|
||||||
if (!Array.isArray(params.attrs)) {
|
if (!Array.isArray(params.attrs)) {
|
||||||
params.attrs = [params.attrs];
|
params.attrs = [params.attrs];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isElem()) {
|
if (item.isElem()) {
|
||||||
var elemSeparator = typeof params.elemSeparator == 'string' ? params.elemSeparator : DEFAULT_SEPARATOR;
|
var elemSeparator =
|
||||||
var preserveCurrentColor = typeof params.preserveCurrentColor == 'boolean' ? params.preserveCurrentColor : false;
|
typeof params.elemSeparator == 'string'
|
||||||
|
? params.elemSeparator
|
||||||
|
: DEFAULT_SEPARATOR;
|
||||||
|
var preserveCurrentColor =
|
||||||
|
typeof params.preserveCurrentColor == 'boolean'
|
||||||
|
? params.preserveCurrentColor
|
||||||
|
: false;
|
||||||
|
|
||||||
// prepare patterns
|
// prepare patterns
|
||||||
var patterns = params.attrs.map(function(pattern) {
|
var patterns = params.attrs.map(function (pattern) {
|
||||||
|
// if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value*
|
||||||
|
if (pattern.indexOf(elemSeparator) === -1) {
|
||||||
|
pattern = ['.*', elemSeparator, pattern, elemSeparator, '.*'].join('');
|
||||||
|
|
||||||
// if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value*
|
// if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
|
||||||
if (pattern.indexOf(elemSeparator) === -1) {
|
} else if (pattern.split(elemSeparator).length < 3) {
|
||||||
pattern = ['.*', elemSeparator, pattern, elemSeparator, '.*'].join('');
|
pattern = [pattern, elemSeparator, '.*'].join('');
|
||||||
|
}
|
||||||
|
|
||||||
// if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
|
// create regexps for element, attribute name, and attribute value
|
||||||
} else if (pattern.split(elemSeparator).length < 3) {
|
return pattern.split(elemSeparator).map(function (value) {
|
||||||
pattern = [pattern, elemSeparator, '.*'].join('');
|
// adjust single * to match anything
|
||||||
|
if (value === '*') {
|
||||||
|
value = '.*';
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegExp(['^', value, '$'].join(''), 'i');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// loop patterns
|
||||||
|
patterns.forEach(function (pattern) {
|
||||||
|
// matches element
|
||||||
|
if (pattern[0].test(item.elem)) {
|
||||||
|
// loop attributes
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
var name = attr.name;
|
||||||
|
var value = attr.value;
|
||||||
|
var isFillCurrentColor =
|
||||||
|
preserveCurrentColor && name == 'fill' && value == 'currentColor';
|
||||||
|
var isStrokeCurrentColor =
|
||||||
|
preserveCurrentColor && name == 'stroke' && value == 'currentColor';
|
||||||
|
|
||||||
|
if (!(isFillCurrentColor || isStrokeCurrentColor)) {
|
||||||
|
// matches attribute name
|
||||||
|
if (pattern[1].test(name)) {
|
||||||
|
// matches attribute value
|
||||||
|
if (pattern[2].test(attr.value)) {
|
||||||
|
item.removeAttr(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// create regexps for element, attribute name, and attribute value
|
|
||||||
return pattern.split(elemSeparator)
|
|
||||||
.map(function(value) {
|
|
||||||
|
|
||||||
// adjust single * to match anything
|
|
||||||
if (value === '*') { value = '.*'; }
|
|
||||||
|
|
||||||
return new RegExp(['^', value, '$'].join(''), 'i');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// loop patterns
|
});
|
||||||
patterns.forEach(function(pattern) {
|
}
|
||||||
|
|
||||||
// matches element
|
|
||||||
if (pattern[0].test(item.elem)) {
|
|
||||||
|
|
||||||
// loop attributes
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
var name = attr.name;
|
|
||||||
var value = attr.value;
|
|
||||||
var isFillCurrentColor = preserveCurrentColor && name == 'fill' && value == 'currentColor';
|
|
||||||
var isStrokeCurrentColor = preserveCurrentColor && name == 'stroke' && value == 'currentColor';
|
|
||||||
|
|
||||||
if (!(isFillCurrentColor || isStrokeCurrentColor)) {
|
|
||||||
// matches attribute name
|
|
||||||
if (pattern[1].test(name)) {
|
|
||||||
|
|
||||||
// matches attribute value
|
|
||||||
if (pattern[2].test(attr.value)) {
|
|
||||||
item.removeAttr(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -18,10 +18,8 @@ exports.description = 'removes comments';
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.comment && item.comment.charAt(0) !== '!') {
|
||||||
if (item.comment && item.comment.charAt(0) !== '!') {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@ exports.type = 'perItem';
|
|||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
removeAny: true
|
removeAny: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.description = 'removes <desc>';
|
exports.description = 'removes <desc>';
|
||||||
@ -24,9 +24,13 @@ var standardDescs = /^(Created with|Created using)/;
|
|||||||
*
|
*
|
||||||
* @author Daniel Wabyick
|
* @author Daniel Wabyick
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
return (
|
||||||
return !item.isElem('desc') || !(params.removeAny || item.isEmpty() ||
|
!item.isElem('desc') ||
|
||||||
standardDescs.test(item.content[0].text));
|
!(
|
||||||
|
params.removeAny ||
|
||||||
|
item.isEmpty() ||
|
||||||
|
standardDescs.test(item.content[0].text)
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,8 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.description = 'removes width and height in presence of viewBox (opposite to removeViewBox, disable it first)';
|
exports.description =
|
||||||
|
'removes width and height in presence of viewBox (opposite to removeViewBox, disable it first)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove width/height attributes and add the viewBox attribute if it's missing
|
* Remove width/height attributes and add the viewBox attribute if it's missing
|
||||||
@ -19,31 +20,29 @@ exports.description = 'removes width and height in presence of viewBox (opposite
|
|||||||
*
|
*
|
||||||
* @author Benny Schudel
|
* @author Benny Schudel
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.isElem('svg')) {
|
||||||
if (item.isElem('svg')) {
|
if (item.hasAttr('viewBox')) {
|
||||||
if (item.hasAttr('viewBox')) {
|
item.removeAttr('width');
|
||||||
item.removeAttr('width');
|
item.removeAttr('height');
|
||||||
item.removeAttr('height');
|
} else if (
|
||||||
} else if (
|
item.hasAttr('width') &&
|
||||||
item.hasAttr('width') &&
|
item.hasAttr('height') &&
|
||||||
item.hasAttr('height') &&
|
!isNaN(Number(item.attr('width').value)) &&
|
||||||
!isNaN(Number(item.attr('width').value)) &&
|
!isNaN(Number(item.attr('height').value))
|
||||||
!isNaN(Number(item.attr('height').value))
|
) {
|
||||||
) {
|
item.addAttr({
|
||||||
item.addAttr({
|
name: 'viewBox',
|
||||||
name: 'viewBox',
|
value:
|
||||||
value:
|
'0 0 ' +
|
||||||
'0 0 ' +
|
Number(item.attr('width').value) +
|
||||||
Number(item.attr('width').value) +
|
' ' +
|
||||||
' ' +
|
Number(item.attr('height').value),
|
||||||
Number(item.attr('height').value),
|
prefix: '',
|
||||||
prefix: '',
|
local: 'viewBox',
|
||||||
local: 'viewBox'
|
});
|
||||||
});
|
item.removeAttr('width');
|
||||||
item.removeAttr('width');
|
item.removeAttr('height');
|
||||||
item.removeAttr('height');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -31,10 +31,8 @@ exports.description = 'removes doctype declaration';
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.doctype) {
|
||||||
if (item.doctype) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -7,10 +7,10 @@ exports.active = true;
|
|||||||
exports.description = 'removes editors namespaces, elements and attributes';
|
exports.description = 'removes editors namespaces, elements and attributes';
|
||||||
|
|
||||||
var editorNamespaces = require('./_collections').editorNamespaces,
|
var editorNamespaces = require('./_collections').editorNamespaces,
|
||||||
prefixes = [];
|
prefixes = [];
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
additionalNamespaces: []
|
additionalNamespaces: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,39 +27,36 @@ exports.params = {
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (Array.isArray(params.additionalNamespaces)) {
|
||||||
|
editorNamespaces = editorNamespaces.concat(params.additionalNamespaces);
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(params.additionalNamespaces)) {
|
if (item.elem) {
|
||||||
editorNamespaces = editorNamespaces.concat(params.additionalNamespaces);
|
if (item.isElem('svg')) {
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
if (
|
||||||
|
attr.prefix === 'xmlns' &&
|
||||||
|
editorNamespaces.indexOf(attr.value) > -1
|
||||||
|
) {
|
||||||
|
prefixes.push(attr.local);
|
||||||
|
|
||||||
|
// <svg xmlns:sodipodi="">
|
||||||
|
item.removeAttr(attr.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.elem) {
|
// <* sodipodi:*="">
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
if (item.isElem('svg')) {
|
if (prefixes.indexOf(attr.prefix) > -1) {
|
||||||
|
item.removeAttr(attr.name);
|
||||||
item.eachAttr(function(attr) {
|
}
|
||||||
if (attr.prefix === 'xmlns' && editorNamespaces.indexOf(attr.value) > -1) {
|
});
|
||||||
prefixes.push(attr.local);
|
|
||||||
|
|
||||||
// <svg xmlns:sodipodi="">
|
|
||||||
item.removeAttr(attr.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// <* sodipodi:*="">
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
if (prefixes.indexOf(attr.prefix) > -1) {
|
|
||||||
item.removeAttr(attr.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// <sodipodi:*>
|
|
||||||
if (prefixes.indexOf(item.prefix) > -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// <sodipodi:*>
|
||||||
|
if (prefixes.indexOf(item.prefix) > -1) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,11 +4,12 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.description = 'removes arbitrary elements by ID or className (disabled by default)';
|
exports.description =
|
||||||
|
'removes arbitrary elements by ID or className (disabled by default)';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
id: [],
|
id: [],
|
||||||
class: []
|
class: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,11 +51,11 @@ exports.params = {
|
|||||||
*
|
*
|
||||||
* @author Eli Dupuis (@elidupuis)
|
* @author Eli Dupuis (@elidupuis)
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
// wrap params in an array if not already
|
// wrap params in an array if not already
|
||||||
['id', 'class'].forEach(function(key) {
|
['id', 'class'].forEach(function (key) {
|
||||||
if (!Array.isArray(params[key])) {
|
if (!Array.isArray(params[key])) {
|
||||||
params[key] = [ params[key] ];
|
params[key] = [params[key]];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,6 +74,6 @@ exports.fn = function(item, params) {
|
|||||||
const elemClass = item.attr('class');
|
const elemClass = item.attr('class');
|
||||||
if (elemClass && params.class.length !== 0) {
|
if (elemClass && params.class.length !== 0) {
|
||||||
const classList = elemClass.value.split(' ');
|
const classList = elemClass.value.split(' ');
|
||||||
return params.class.some(item => classList.includes(item)) === false;
|
return params.class.some((item) => classList.includes(item)) === false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,9 +7,9 @@ exports.active = true;
|
|||||||
exports.description = 'removes empty <text> elements';
|
exports.description = 'removes empty <text> elements';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
text: true,
|
text: true,
|
||||||
tspan: true,
|
tspan: true,
|
||||||
tref: true
|
tref: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,27 +33,14 @@ exports.params = {
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
// Remove empty text element
|
||||||
|
if (params.text && item.isElem('text') && item.isEmpty()) return false;
|
||||||
|
|
||||||
// Remove empty text element
|
// Remove empty tspan element
|
||||||
if (
|
if (params.tspan && item.isElem('tspan') && item.isEmpty()) return false;
|
||||||
params.text &&
|
|
||||||
item.isElem('text') &&
|
|
||||||
item.isEmpty()
|
|
||||||
) return false;
|
|
||||||
|
|
||||||
// Remove empty tspan element
|
|
||||||
if (
|
|
||||||
params.tspan &&
|
|
||||||
item.isElem('tspan') &&
|
|
||||||
item.isEmpty()
|
|
||||||
) return false;
|
|
||||||
|
|
||||||
// Remove tref with empty xlink:href attribute
|
|
||||||
if (
|
|
||||||
params.tref &&
|
|
||||||
item.isElem('tref') &&
|
|
||||||
!item.hasAttrLocal('href')
|
|
||||||
) return false;
|
|
||||||
|
|
||||||
|
// Remove tref with empty xlink:href attribute
|
||||||
|
if (params.tref && item.isElem('tref') && !item.hasAttrLocal('href'))
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -16,8 +16,6 @@ exports.description = 'removes <metadata>';
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
return !item.isElem('metadata');
|
||||||
return !item.isElem('metadata');
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -4,11 +4,12 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'removes non-inheritable group’s presentational attributes';
|
exports.description =
|
||||||
|
'removes non-inheritable group’s presentational attributes';
|
||||||
|
|
||||||
var inheritableAttrs = require('./_collections').inheritableAttrs,
|
var inheritableAttrs = require('./_collections').inheritableAttrs,
|
||||||
attrsGroups = require('./_collections').attrsGroups,
|
attrsGroups = require('./_collections').attrsGroups,
|
||||||
applyGroups = require('./_collections').presentationNonInheritableGroupAttrs;
|
applyGroups = require('./_collections').presentationNonInheritableGroupAttrs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove non-inheritable group's "presentation" attributes.
|
* Remove non-inheritable group's "presentation" attributes.
|
||||||
@ -18,20 +19,16 @@ var inheritableAttrs = require('./_collections').inheritableAttrs,
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.isElem('g')) {
|
||||||
if (item.isElem('g')) {
|
item.eachAttr(function (attr) {
|
||||||
|
if (
|
||||||
item.eachAttr(function(attr) {
|
~attrsGroups.presentation.indexOf(attr.name) &&
|
||||||
if (
|
!~inheritableAttrs.indexOf(attr.name) &&
|
||||||
~attrsGroups.presentation.indexOf(attr.name) &&
|
!~applyGroups.indexOf(attr.name)
|
||||||
!~inheritableAttrs.indexOf(attr.name) &&
|
) {
|
||||||
!~applyGroups.indexOf(attr.name)
|
item.removeAttr(attr.name);
|
||||||
) {
|
}
|
||||||
item.removeAttr(attr.name);
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -4,15 +4,16 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.description = 'removes elements that are drawn outside of the viewbox (disabled by default)';
|
exports.description =
|
||||||
|
'removes elements that are drawn outside of the viewbox (disabled by default)';
|
||||||
|
|
||||||
const JSAPI = require('../lib/svgo/jsAPI.js');
|
const JSAPI = require('../lib/svgo/jsAPI.js');
|
||||||
|
|
||||||
var _path = require('./_path.js'),
|
var _path = require('./_path.js'),
|
||||||
intersects = _path.intersects,
|
intersects = _path.intersects,
|
||||||
path2js = _path.path2js,
|
path2js = _path.path2js,
|
||||||
viewBox,
|
viewBox,
|
||||||
viewBoxJS;
|
viewBoxJS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove elements that are drawn outside of the viewbox.
|
* Remove elements that are drawn outside of the viewbox.
|
||||||
@ -22,33 +23,32 @@ var _path = require('./_path.js'),
|
|||||||
*
|
*
|
||||||
* @author JoshyPHP
|
* @author JoshyPHP
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (
|
||||||
|
item.isElem('path') &&
|
||||||
|
item.hasAttr('d') &&
|
||||||
|
typeof viewBox !== 'undefined'
|
||||||
|
) {
|
||||||
|
// Consider that any item with a transform attribute or a M instruction
|
||||||
|
// within the viewBox is visible
|
||||||
|
if (hasTransform(item) || pathMovesWithinViewBox(item.attr('d').value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.isElem('path') && item.hasAttr('d') && typeof viewBox !== 'undefined')
|
var pathJS = path2js(item);
|
||||||
{
|
if (pathJS.length === 2) {
|
||||||
// Consider that any item with a transform attribute or a M instruction
|
// Use a closed clone of the path if it's too short for intersects()
|
||||||
// within the viewBox is visible
|
pathJS = JSON.parse(JSON.stringify(pathJS));
|
||||||
if (hasTransform(item) || pathMovesWithinViewBox(item.attr('d').value))
|
pathJS.push({ instruction: 'z' });
|
||||||
{
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pathJS = path2js(item);
|
return intersects(viewBoxJS, pathJS);
|
||||||
if (pathJS.length === 2)
|
}
|
||||||
{
|
if (item.isElem('svg')) {
|
||||||
// Use a closed clone of the path if it's too short for intersects()
|
parseViewBox(item);
|
||||||
pathJS = JSON.parse(JSON.stringify(pathJS));
|
}
|
||||||
pathJS.push({ instruction: 'z' });
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersects(viewBoxJS, pathJS);
|
return true;
|
||||||
}
|
|
||||||
if (item.isElem('svg'))
|
|
||||||
{
|
|
||||||
parseViewBox(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,9 +57,11 @@ exports.fn = function(item) {
|
|||||||
* @param {String} path
|
* @param {String} path
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
function hasTransform(item)
|
function hasTransform(item) {
|
||||||
{
|
return (
|
||||||
return item.hasAttr('transform') || (item.parentNode && hasTransform(item.parentNode));
|
item.hasAttr('transform') ||
|
||||||
|
(item.parentNode && hasTransform(item.parentNode))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,50 +69,51 @@ function hasTransform(item)
|
|||||||
*
|
*
|
||||||
* @param {Object} svg svg element item
|
* @param {Object} svg svg element item
|
||||||
*/
|
*/
|
||||||
function parseViewBox(svg)
|
function parseViewBox(svg) {
|
||||||
{
|
var viewBoxData = '';
|
||||||
var viewBoxData = '';
|
if (svg.hasAttr('viewBox')) {
|
||||||
if (svg.hasAttr('viewBox'))
|
// Remove commas and plus signs, normalize and trim whitespace
|
||||||
{
|
viewBoxData = svg.attr('viewBox').value;
|
||||||
// Remove commas and plus signs, normalize and trim whitespace
|
} else if (svg.hasAttr('height') && svg.hasAttr('width')) {
|
||||||
viewBoxData = svg.attr('viewBox').value;
|
viewBoxData =
|
||||||
}
|
'0 0 ' + svg.attr('width').value + ' ' + svg.attr('height').value;
|
||||||
else if (svg.hasAttr('height') && svg.hasAttr('width'))
|
}
|
||||||
{
|
|
||||||
viewBoxData = '0 0 ' + svg.attr('width').value + ' ' + svg.attr('height').value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove commas and plus signs, normalize and trim whitespace
|
// Remove commas and plus signs, normalize and trim whitespace
|
||||||
viewBoxData = viewBoxData.replace(/[,+]|px/g, ' ').replace(/\s+/g, ' ').replace(/^\s*|\s*$/g, '');
|
viewBoxData = viewBoxData
|
||||||
|
.replace(/[,+]|px/g, ' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.replace(/^\s*|\s*$/g, '');
|
||||||
|
|
||||||
// Ensure that the dimensions are 4 values separated by space
|
// Ensure that the dimensions are 4 values separated by space
|
||||||
var m = /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(viewBoxData);
|
var m = /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(
|
||||||
if (!m)
|
viewBoxData
|
||||||
{
|
);
|
||||||
return;
|
if (!m) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Store the viewBox boundaries
|
// Store the viewBox boundaries
|
||||||
viewBox = {
|
viewBox = {
|
||||||
left: parseFloat(m[1]),
|
left: parseFloat(m[1]),
|
||||||
top: parseFloat(m[2]),
|
top: parseFloat(m[2]),
|
||||||
right: parseFloat(m[1]) + parseFloat(m[3]),
|
right: parseFloat(m[1]) + parseFloat(m[3]),
|
||||||
bottom: parseFloat(m[2]) + parseFloat(m[4])
|
bottom: parseFloat(m[2]) + parseFloat(m[4]),
|
||||||
};
|
};
|
||||||
|
|
||||||
var path = new JSAPI({
|
var path = new JSAPI({
|
||||||
elem: 'path',
|
elem: 'path',
|
||||||
prefix: '',
|
prefix: '',
|
||||||
local: 'path'
|
local: 'path',
|
||||||
});
|
});
|
||||||
path.addAttr({
|
path.addAttr({
|
||||||
name: 'd',
|
name: 'd',
|
||||||
prefix: '',
|
prefix: '',
|
||||||
local: 'd',
|
local: 'd',
|
||||||
value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z'
|
value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z',
|
||||||
});
|
});
|
||||||
|
|
||||||
viewBoxJS = path2js(path);
|
viewBoxJS = path2js(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,16 +122,19 @@ function parseViewBox(svg)
|
|||||||
* @param {String} path
|
* @param {String} path
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
function pathMovesWithinViewBox(path)
|
function pathMovesWithinViewBox(path) {
|
||||||
{
|
var regexp = /M\s*(-?\d*\.?\d+)(?!\d)\s*(-?\d*\.?\d+)/g,
|
||||||
var regexp = /M\s*(-?\d*\.?\d+)(?!\d)\s*(-?\d*\.?\d+)/g, m;
|
m;
|
||||||
while (null !== (m = regexp.exec(path)))
|
while (null !== (m = regexp.exec(path))) {
|
||||||
{
|
if (
|
||||||
if (m[1] >= viewBox.left && m[1] <= viewBox.right && m[2] >= viewBox.top && m[2] <= viewBox.bottom)
|
m[1] >= viewBox.left &&
|
||||||
{
|
m[1] <= viewBox.right &&
|
||||||
return true;
|
m[2] >= viewBox.top &&
|
||||||
}
|
m[2] <= viewBox.bottom
|
||||||
}
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,11 @@ exports.description = 'removes raster images (disabled by default)';
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (
|
||||||
if (
|
item.isElem('image') &&
|
||||||
item.isElem('image') &&
|
item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/)
|
||||||
item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/)
|
) {
|
||||||
) {
|
return false;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -16,8 +16,6 @@ exports.description = 'removes <script> elements (disabled by default)';
|
|||||||
*
|
*
|
||||||
* @author Patrick Klingemann
|
* @author Patrick Klingemann
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
return !item.isElem('script');
|
||||||
return !item.isElem('script');
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -16,8 +16,6 @@ exports.description = 'removes <style> element (disabled by default)';
|
|||||||
*
|
*
|
||||||
* @author Betsy Dupuis
|
* @author Betsy Dupuis
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
return !item.isElem('style');
|
||||||
return !item.isElem('style');
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -16,8 +16,6 @@ exports.description = 'removes <title>';
|
|||||||
*
|
*
|
||||||
* @author Igor Kalashnikov
|
* @author Igor Kalashnikov
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
return !item.isElem('title');
|
||||||
return !item.isElem('title');
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -4,54 +4,54 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = true;
|
exports.active = true;
|
||||||
|
|
||||||
exports.description = 'removes unknown elements content and attributes, removes attrs with default values';
|
exports.description =
|
||||||
|
'removes unknown elements content and attributes, removes attrs with default values';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
unknownContent: true,
|
unknownContent: true,
|
||||||
unknownAttrs: true,
|
unknownAttrs: true,
|
||||||
defaultAttrs: true,
|
defaultAttrs: true,
|
||||||
uselessOverrides: true,
|
uselessOverrides: true,
|
||||||
keepDataAttrs: true,
|
keepDataAttrs: true,
|
||||||
keepAriaAttrs: true,
|
keepAriaAttrs: true,
|
||||||
keepRoleAttr: false
|
keepRoleAttr: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var collections = require('./_collections'),
|
var collections = require('./_collections'),
|
||||||
elems = collections.elems,
|
elems = collections.elems,
|
||||||
attrsGroups = collections.attrsGroups,
|
attrsGroups = collections.attrsGroups,
|
||||||
elemsGroups = collections.elemsGroups,
|
elemsGroups = collections.elemsGroups,
|
||||||
attrsGroupsDefaults = collections.attrsGroupsDefaults,
|
attrsGroupsDefaults = collections.attrsGroupsDefaults,
|
||||||
attrsInheritable = collections.inheritableAttrs,
|
attrsInheritable = collections.inheritableAttrs,
|
||||||
applyGroups = collections.presentationNonInheritableGroupAttrs;
|
applyGroups = collections.presentationNonInheritableGroupAttrs;
|
||||||
|
|
||||||
// collect and extend all references
|
// collect and extend all references
|
||||||
for (const elem of Object.values(elems)) {
|
for (const elem of Object.values(elems)) {
|
||||||
if (elem.attrsGroups) {
|
if (elem.attrsGroups) {
|
||||||
elem.attrs = elem.attrs || [];
|
elem.attrs = elem.attrs || [];
|
||||||
|
|
||||||
elem.attrsGroups.forEach(function(attrsGroupName) {
|
elem.attrsGroups.forEach(function (attrsGroupName) {
|
||||||
elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]);
|
elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]);
|
||||||
|
|
||||||
var groupDefaults = attrsGroupsDefaults[attrsGroupName];
|
var groupDefaults = attrsGroupsDefaults[attrsGroupName];
|
||||||
|
|
||||||
if (groupDefaults) {
|
if (groupDefaults) {
|
||||||
elem.defaults = elem.defaults || {};
|
elem.defaults = elem.defaults || {};
|
||||||
|
|
||||||
for (const [attrName, attr] of Object.entries(groupDefaults)) {
|
for (const [attrName, attr] of Object.entries(groupDefaults)) {
|
||||||
elem.defaults[attrName] = attr;
|
elem.defaults[attrName] = attr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
if (elem.contentGroups) {
|
||||||
|
elem.content = elem.content || [];
|
||||||
|
|
||||||
if (elem.contentGroups) {
|
elem.contentGroups.forEach(function (contentGroupName) {
|
||||||
elem.content = elem.content || [];
|
elem.content = elem.content.concat(elemsGroups[contentGroupName]);
|
||||||
|
});
|
||||||
elem.contentGroups.forEach(function(contentGroupName) {
|
}
|
||||||
elem.content = elem.content.concat(elemsGroups[contentGroupName]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,85 +64,64 @@ for (const elem of Object.values(elems)) {
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
// elems w/o namespace prefix
|
||||||
|
if (item.isElem() && !item.prefix) {
|
||||||
|
var elem = item.elem;
|
||||||
|
|
||||||
// elems w/o namespace prefix
|
// remove unknown element's content
|
||||||
if (item.isElem() && !item.prefix) {
|
if (
|
||||||
|
params.unknownContent &&
|
||||||
var elem = item.elem;
|
!item.isEmpty() &&
|
||||||
|
elems[elem] && // make sure we know of this element before checking its children
|
||||||
// remove unknown element's content
|
elem !== 'foreignObject' // Don't check foreignObject
|
||||||
|
) {
|
||||||
|
item.content.forEach(function (content, i) {
|
||||||
if (
|
if (
|
||||||
params.unknownContent &&
|
content.isElem() &&
|
||||||
!item.isEmpty() &&
|
!content.prefix &&
|
||||||
elems[elem] && // make sure we know of this element before checking its children
|
((elems[elem].content && // Do we have a record of its permitted content?
|
||||||
elem !== 'foreignObject' // Don't check foreignObject
|
elems[elem].content.indexOf(content.elem) === -1) ||
|
||||||
|
(!elems[elem].content && // we dont know about its permitted content
|
||||||
|
!elems[content.elem])) // check that we know about the element at all
|
||||||
) {
|
) {
|
||||||
item.content.forEach(function(content, i) {
|
item.content.splice(i, 1);
|
||||||
if (
|
|
||||||
content.isElem() &&
|
|
||||||
!content.prefix &&
|
|
||||||
(
|
|
||||||
(
|
|
||||||
elems[elem].content && // Do we have a record of its permitted content?
|
|
||||||
elems[elem].content.indexOf(content.elem) === -1
|
|
||||||
) ||
|
|
||||||
(
|
|
||||||
!elems[elem].content && // we dont know about its permitted content
|
|
||||||
!elems[content.elem] // check that we know about the element at all
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
item.content.splice(i, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// remove element's unknown attrs and attrs with default values
|
|
||||||
if (elems[elem] && elems[elem].attrs) {
|
|
||||||
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
|
|
||||||
if (
|
|
||||||
attr.name !== 'xmlns' &&
|
|
||||||
(attr.prefix === 'xml' || !attr.prefix) &&
|
|
||||||
(!params.keepDataAttrs || attr.name.indexOf('data-') != 0) &&
|
|
||||||
(!params.keepAriaAttrs || attr.name.indexOf('aria-') != 0) &&
|
|
||||||
(!params.keepRoleAttr || attr.name != 'role')
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
// unknown attrs
|
|
||||||
(
|
|
||||||
params.unknownAttrs &&
|
|
||||||
elems[elem].attrs.indexOf(attr.name) === -1
|
|
||||||
) ||
|
|
||||||
// attrs with default values
|
|
||||||
(
|
|
||||||
params.defaultAttrs &&
|
|
||||||
!item.hasAttr('id') &&
|
|
||||||
elems[elem].defaults &&
|
|
||||||
elems[elem].defaults[attr.name] === attr.value && (
|
|
||||||
attrsInheritable.indexOf(attr.name) < 0 ||
|
|
||||||
!item.parentNode.computedAttr(attr.name)
|
|
||||||
)
|
|
||||||
) ||
|
|
||||||
// useless overrides
|
|
||||||
(
|
|
||||||
params.uselessOverrides &&
|
|
||||||
!item.hasAttr('id') &&
|
|
||||||
applyGroups.indexOf(attr.name) < 0 &&
|
|
||||||
attrsInheritable.indexOf(attr.name) > -1 &&
|
|
||||||
item.parentNode.computedAttr(attr.name, attr.value)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
item.removeAttr(attr.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove element's unknown attrs and attrs with default values
|
||||||
|
if (elems[elem] && elems[elem].attrs) {
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
if (
|
||||||
|
attr.name !== 'xmlns' &&
|
||||||
|
(attr.prefix === 'xml' || !attr.prefix) &&
|
||||||
|
(!params.keepDataAttrs || attr.name.indexOf('data-') != 0) &&
|
||||||
|
(!params.keepAriaAttrs || attr.name.indexOf('aria-') != 0) &&
|
||||||
|
(!params.keepRoleAttr || attr.name != 'role')
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
// unknown attrs
|
||||||
|
(params.unknownAttrs &&
|
||||||
|
elems[elem].attrs.indexOf(attr.name) === -1) ||
|
||||||
|
// attrs with default values
|
||||||
|
(params.defaultAttrs &&
|
||||||
|
!item.hasAttr('id') &&
|
||||||
|
elems[elem].defaults &&
|
||||||
|
elems[elem].defaults[attr.name] === attr.value &&
|
||||||
|
(attrsInheritable.indexOf(attr.name) < 0 ||
|
||||||
|
!item.parentNode.computedAttr(attr.name))) ||
|
||||||
|
// useless overrides
|
||||||
|
(params.uselessOverrides &&
|
||||||
|
!item.hasAttr('id') &&
|
||||||
|
applyGroups.indexOf(attr.name) < 0 &&
|
||||||
|
attrsInheritable.indexOf(attr.name) > -1 &&
|
||||||
|
item.parentNode.computedAttr(attr.name, attr.value))
|
||||||
|
) {
|
||||||
|
item.removeAttr(attr.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -14,96 +14,84 @@ exports.description = 'removes unused namespaces declaration';
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(data) {
|
exports.fn = function (data) {
|
||||||
|
var svgElem,
|
||||||
|
xmlnsCollection = [];
|
||||||
|
|
||||||
var svgElem,
|
/**
|
||||||
xmlnsCollection = [];
|
* Remove namespace from collection.
|
||||||
|
*
|
||||||
/**
|
* @param {String} ns namescape name
|
||||||
* Remove namespace from collection.
|
*/
|
||||||
*
|
function removeNSfromCollection(ns) {
|
||||||
* @param {String} ns namescape name
|
var pos = xmlnsCollection.indexOf(ns);
|
||||||
*/
|
|
||||||
function removeNSfromCollection(ns) {
|
|
||||||
|
|
||||||
var pos = xmlnsCollection.indexOf(ns);
|
|
||||||
|
|
||||||
// if found - remove ns from the namespaces collection
|
|
||||||
if (pos > -1) {
|
|
||||||
xmlnsCollection.splice(pos, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// if found - remove ns from the namespaces collection
|
||||||
|
if (pos > -1) {
|
||||||
|
xmlnsCollection.splice(pos, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bananas!
|
* Bananas!
|
||||||
*
|
*
|
||||||
* @param {Array} items input items
|
* @param {Array} items input items
|
||||||
*
|
*
|
||||||
* @return {Array} output items
|
* @return {Array} output items
|
||||||
*/
|
*/
|
||||||
function monkeys(items) {
|
function monkeys(items) {
|
||||||
|
var i = 0,
|
||||||
|
length = items.content.length;
|
||||||
|
|
||||||
var i = 0,
|
while (i < length) {
|
||||||
length = items.content.length;
|
var item = items.content[i];
|
||||||
|
|
||||||
while(i < length) {
|
if (item.isElem('svg')) {
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
var item = items.content[i];
|
// collect namespaces
|
||||||
|
if (attr.prefix === 'xmlns' && attr.local) {
|
||||||
if (item.isElem('svg')) {
|
xmlnsCollection.push(attr.local);
|
||||||
|
}
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
// collect namespaces
|
|
||||||
if (attr.prefix === 'xmlns' && attr.local) {
|
|
||||||
xmlnsCollection.push(attr.local);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// if svg element has ns-attr
|
|
||||||
if (xmlnsCollection.length) {
|
|
||||||
// save svg element
|
|
||||||
svgElem = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xmlnsCollection.length) {
|
|
||||||
|
|
||||||
// check item for the ns-attrs
|
|
||||||
if (item.prefix) {
|
|
||||||
removeNSfromCollection(item.prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check each attr for the ns-attrs
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
removeNSfromCollection(attr.prefix);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// if nothing is found - go deeper
|
|
||||||
if (xmlnsCollection.length && item.content) {
|
|
||||||
monkeys(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
data = monkeys(data);
|
|
||||||
|
|
||||||
// remove svg element ns-attributes if they are not used even once
|
|
||||||
if (xmlnsCollection.length) {
|
|
||||||
xmlnsCollection.forEach(function(name) {
|
|
||||||
svgElem.removeAttr('xmlns:' + name);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// if svg element has ns-attr
|
||||||
|
if (xmlnsCollection.length) {
|
||||||
|
// save svg element
|
||||||
|
svgElem = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmlnsCollection.length) {
|
||||||
|
// check item for the ns-attrs
|
||||||
|
if (item.prefix) {
|
||||||
|
removeNSfromCollection(item.prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check each attr for the ns-attrs
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
removeNSfromCollection(attr.prefix);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// if nothing is found - go deeper
|
||||||
|
if (xmlnsCollection.length && item.content) {
|
||||||
|
monkeys(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = monkeys(data);
|
||||||
|
|
||||||
|
// remove svg element ns-attributes if they are not used even once
|
||||||
|
if (xmlnsCollection.length) {
|
||||||
|
xmlnsCollection.forEach(function (name) {
|
||||||
|
svgElem.removeAttr('xmlns:' + name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
};
|
};
|
||||||
|
@ -16,38 +16,27 @@ var nonRendering = require('./_collections').elemsGroups.nonRendering;
|
|||||||
*
|
*
|
||||||
* @author Lev Solntsev
|
* @author Lev Solntsev
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.isElem('defs')) {
|
||||||
if (item.isElem('defs')) {
|
if (item.content) {
|
||||||
|
item.content = getUsefulItems(item, []);
|
||||||
if (item.content) {
|
|
||||||
item.content = getUsefulItems(item, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isEmpty()) return false;
|
|
||||||
|
|
||||||
} else if (item.isElem(nonRendering) && !item.hasAttr('id')) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.isEmpty()) return false;
|
||||||
|
} else if (item.isElem(nonRendering) && !item.hasAttr('id')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getUsefulItems(item, usefulItems) {
|
function getUsefulItems(item, usefulItems) {
|
||||||
|
item.content.forEach(function (child) {
|
||||||
|
if (child.hasAttr('id') || child.isElem('style')) {
|
||||||
|
usefulItems.push(child);
|
||||||
|
child.parentNode = item;
|
||||||
|
} else if (!child.isEmpty()) {
|
||||||
|
child.content = getUsefulItems(child, usefulItems);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
item.content.forEach(function(child) {
|
return usefulItems;
|
||||||
if (child.hasAttr('id') || child.isElem('style')) {
|
|
||||||
|
|
||||||
usefulItems.push(child);
|
|
||||||
child.parentNode = item;
|
|
||||||
|
|
||||||
} else if (!child.isEmpty()) {
|
|
||||||
|
|
||||||
child.content = getUsefulItems(child, usefulItems);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return usefulItems;
|
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,16 @@ exports.active = true;
|
|||||||
exports.description = 'removes useless stroke and fill attributes';
|
exports.description = 'removes useless stroke and fill attributes';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
stroke: true,
|
stroke: true,
|
||||||
fill: true,
|
fill: true,
|
||||||
removeNone: false,
|
removeNone: false,
|
||||||
hasStyleOrScript: false
|
hasStyleOrScript: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
var shape = require('./_collections').elemsGroups.shape,
|
var shape = require('./_collections').elemsGroups.shape,
|
||||||
regStrokeProps = /^stroke/,
|
regStrokeProps = /^stroke/,
|
||||||
regFillProps = /^fill-/,
|
regFillProps = /^fill-/,
|
||||||
styleOrScript = ['style', 'script'];
|
styleOrScript = ['style', 'script'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove useless stroke and fill attrs.
|
* Remove useless stroke and fill attrs.
|
||||||
@ -27,81 +27,78 @@ var shape = require('./_collections').elemsGroups.shape,
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
if (item.isElem(styleOrScript)) {
|
||||||
if (item.isElem(styleOrScript)) {
|
params.hasStyleOrScript = true;
|
||||||
params.hasStyleOrScript = true;
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!params.hasStyleOrScript &&
|
||||||
|
item.isElem(shape) &&
|
||||||
|
!item.computedAttr('id')
|
||||||
|
) {
|
||||||
|
var stroke = params.stroke && item.computedAttr('stroke'),
|
||||||
|
fill = params.fill && !item.computedAttr('fill', 'none');
|
||||||
|
|
||||||
|
// remove stroke*
|
||||||
|
if (
|
||||||
|
params.stroke &&
|
||||||
|
(!stroke ||
|
||||||
|
stroke == 'none' ||
|
||||||
|
item.computedAttr('stroke-opacity', '0') ||
|
||||||
|
item.computedAttr('stroke-width', '0'))
|
||||||
|
) {
|
||||||
|
// stroke-width may affect the size of marker-end
|
||||||
|
if (
|
||||||
|
item.computedAttr('stroke-width', '0') === true ||
|
||||||
|
item.computedAttr('marker-end') == null
|
||||||
|
) {
|
||||||
|
var parentStroke = item.parentNode.computedAttr('stroke'),
|
||||||
|
declineStroke = parentStroke && parentStroke != 'none';
|
||||||
|
|
||||||
|
item.eachAttr(function (attr) {
|
||||||
|
if (regStrokeProps.test(attr.name)) {
|
||||||
|
item.removeAttr(attr.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (declineStroke)
|
||||||
|
item.addAttr({
|
||||||
|
name: 'stroke',
|
||||||
|
value: 'none',
|
||||||
|
prefix: '',
|
||||||
|
local: 'stroke',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!params.hasStyleOrScript && item.isElem(shape) && !item.computedAttr('id')) {
|
// remove fill*
|
||||||
|
if (params.fill && (!fill || item.computedAttr('fill-opacity', '0'))) {
|
||||||
var stroke = params.stroke && item.computedAttr('stroke'),
|
item.eachAttr(function (attr) {
|
||||||
fill = params.fill && !item.computedAttr('fill', 'none');
|
if (regFillProps.test(attr.name)) {
|
||||||
|
item.removeAttr(attr.name);
|
||||||
// remove stroke*
|
|
||||||
if (
|
|
||||||
params.stroke &&
|
|
||||||
(
|
|
||||||
!stroke ||
|
|
||||||
stroke == 'none' ||
|
|
||||||
item.computedAttr('stroke-opacity', '0') ||
|
|
||||||
item.computedAttr('stroke-width', '0')
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// stroke-width may affect the size of marker-end
|
|
||||||
if (
|
|
||||||
item.computedAttr('stroke-width', '0') === true ||
|
|
||||||
item.computedAttr('marker-end') == null
|
|
||||||
) {
|
|
||||||
var parentStroke = item.parentNode.computedAttr('stroke'),
|
|
||||||
declineStroke = parentStroke && parentStroke != 'none';
|
|
||||||
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
if (regStrokeProps.test(attr.name)) {
|
|
||||||
item.removeAttr(attr.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (declineStroke) item.addAttr({
|
|
||||||
name: 'stroke',
|
|
||||||
value: 'none',
|
|
||||||
prefix: '',
|
|
||||||
local: 'stroke'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove fill*
|
|
||||||
if (
|
|
||||||
params.fill &&
|
|
||||||
(!fill || item.computedAttr('fill-opacity', '0'))
|
|
||||||
) {
|
|
||||||
item.eachAttr(function(attr) {
|
|
||||||
if (regFillProps.test(attr.name)) {
|
|
||||||
item.removeAttr(attr.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (fill) {
|
|
||||||
if (item.hasAttr('fill'))
|
|
||||||
item.attr('fill').value = 'none';
|
|
||||||
else
|
|
||||||
item.addAttr({
|
|
||||||
name: 'fill',
|
|
||||||
value: 'none',
|
|
||||||
prefix: '',
|
|
||||||
local: 'fill'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.removeNone &&
|
|
||||||
(!stroke || item.hasAttr('stroke') && item.attr('stroke').value=='none') &&
|
|
||||||
(!fill || item.hasAttr('fill') && item.attr('fill').value=='none')) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fill) {
|
||||||
|
if (item.hasAttr('fill')) item.attr('fill').value = 'none';
|
||||||
|
else
|
||||||
|
item.addAttr({
|
||||||
|
name: 'fill',
|
||||||
|
value: 'none',
|
||||||
|
prefix: '',
|
||||||
|
local: 'fill',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
params.removeNone &&
|
||||||
|
(!stroke ||
|
||||||
|
(item.hasAttr('stroke') && item.attr('stroke').value == 'none')) &&
|
||||||
|
(!fill || (item.hasAttr('fill') && item.attr('fill').value == 'none'))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,8 @@ exports.type = 'perItem';
|
|||||||
|
|
||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.description = 'removes xmlns attribute (for inline svg, disabled by default)';
|
exports.description =
|
||||||
|
'removes xmlns attribute (for inline svg, disabled by default)';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the xmlns attribute when present.
|
* Remove the xmlns attribute when present.
|
||||||
@ -19,10 +20,8 @@ exports.description = 'removes xmlns attribute (for inline svg, disabled by defa
|
|||||||
*
|
*
|
||||||
* @author Ricardo Tomasi
|
* @author Ricardo Tomasi
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.isElem('svg') && item.hasAttr('xmlns')) {
|
||||||
if (item.isElem('svg') && item.hasAttr('xmlns')) {
|
item.removeAttr('xmlns');
|
||||||
item.removeAttr('xmlns');
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
};
|
|
||||||
|
@ -17,8 +17,8 @@ exports.description = 'removes XML processing instructions';
|
|||||||
*
|
*
|
||||||
* @author Kir Belevich
|
* @author Kir Belevich
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
return !(
|
||||||
return !(item.processinginstruction && item.processinginstruction.name === 'xml');
|
item.processinginstruction && item.processinginstruction.name === 'xml'
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -84,9 +84,10 @@ exports.type = 'full';
|
|||||||
|
|
||||||
exports.active = false;
|
exports.active = false;
|
||||||
|
|
||||||
exports.description = 'Finds <path> elements with the same d, fill, and ' +
|
exports.description =
|
||||||
'stroke, and converts them to <use> elements ' +
|
'Finds <path> elements with the same d, fill, and ' +
|
||||||
'referencing a single <path> def.';
|
'stroke, and converts them to <use> elements ' +
|
||||||
|
'referencing a single <path> def.';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds <path> elements with the same d, fill, and stroke, and converts them to
|
* Finds <path> elements with the same d, fill, and stroke, and converts them to
|
||||||
@ -94,11 +95,11 @@ exports.description = 'Finds <path> elements with the same d, fill, and ' +
|
|||||||
*
|
*
|
||||||
* @author Jacob Howcroft
|
* @author Jacob Howcroft
|
||||||
*/
|
*/
|
||||||
exports.fn = function(data) {
|
exports.fn = function (data) {
|
||||||
const seen = new Map();
|
const seen = new Map();
|
||||||
let count = 0;
|
let count = 0;
|
||||||
const defs = [];
|
const defs = [];
|
||||||
traverse(data, item => {
|
traverse(data, (item) => {
|
||||||
if (!item.isElem('path') || !item.hasAttr('d')) {
|
if (!item.isElem('path') || !item.hasAttr('d')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -108,22 +109,34 @@ exports.fn = function(data) {
|
|||||||
const key = d + ';s:' + stroke + ';f:' + fill;
|
const key = d + ';s:' + stroke + ';f:' + fill;
|
||||||
const hasSeen = seen.get(key);
|
const hasSeen = seen.get(key);
|
||||||
if (!hasSeen) {
|
if (!hasSeen) {
|
||||||
seen.set(key, {elem: item, reused: false});
|
seen.set(key, { elem: item, reused: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!hasSeen.reused) {
|
if (!hasSeen.reused) {
|
||||||
hasSeen.reused = true;
|
hasSeen.reused = true;
|
||||||
if (!hasSeen.elem.hasAttr('id')) {
|
if (!hasSeen.elem.hasAttr('id')) {
|
||||||
hasSeen.elem.addAttr({name: 'id', local: 'id',
|
hasSeen.elem.addAttr({
|
||||||
prefix: '', value: 'reuse-' + (count++)});
|
name: 'id',
|
||||||
|
local: 'id',
|
||||||
|
prefix: '',
|
||||||
|
value: 'reuse-' + count++,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
defs.push(hasSeen.elem);
|
defs.push(hasSeen.elem);
|
||||||
}
|
}
|
||||||
convertToUse(item, hasSeen.elem.attr('id').value);
|
convertToUse(item, hasSeen.elem.attr('id').value);
|
||||||
});
|
});
|
||||||
if (defs.length > 0) {
|
if (defs.length > 0) {
|
||||||
const defsTag = new JSAPI({
|
const defsTag = new JSAPI(
|
||||||
elem: 'defs', prefix: '', local: 'defs', content: [], attrs: []}, data);
|
{
|
||||||
|
elem: 'defs',
|
||||||
|
prefix: '',
|
||||||
|
local: 'defs',
|
||||||
|
content: [],
|
||||||
|
attrs: [],
|
||||||
|
},
|
||||||
|
data
|
||||||
|
);
|
||||||
data.content[0].spliceContent(0, 0, defsTag);
|
data.content[0].spliceContent(0, 0, defsTag);
|
||||||
for (let def of defs) {
|
for (let def of defs) {
|
||||||
// Remove class and style before copying to avoid circular refs in
|
// Remove class and style before copying to avoid circular refs in
|
||||||
@ -152,8 +165,12 @@ function convertToUse(item, href) {
|
|||||||
item.removeAttr('d');
|
item.removeAttr('d');
|
||||||
item.removeAttr('stroke');
|
item.removeAttr('stroke');
|
||||||
item.removeAttr('fill');
|
item.removeAttr('fill');
|
||||||
item.addAttr({name: 'xlink:href', local: 'xlink:href',
|
item.addAttr({
|
||||||
prefix: 'none', value: '#' + href});
|
name: 'xlink:href',
|
||||||
|
local: 'xlink:href',
|
||||||
|
prefix: 'none',
|
||||||
|
value: '#' + href,
|
||||||
|
});
|
||||||
delete item.pathJS;
|
delete item.pathJS;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,25 @@ exports.active = false;
|
|||||||
exports.description = 'sorts element attributes (disabled by default)';
|
exports.description = 'sorts element attributes (disabled by default)';
|
||||||
|
|
||||||
exports.params = {
|
exports.params = {
|
||||||
order: [
|
order: [
|
||||||
'id',
|
'id',
|
||||||
'width', 'height',
|
'width',
|
||||||
'x', 'x1', 'x2',
|
'height',
|
||||||
'y', 'y1', 'y2',
|
'x',
|
||||||
'cx', 'cy', 'r',
|
'x1',
|
||||||
'fill', 'stroke', 'marker',
|
'x2',
|
||||||
'd', 'points'
|
'y',
|
||||||
]
|
'y1',
|
||||||
|
'y2',
|
||||||
|
'cx',
|
||||||
|
'cy',
|
||||||
|
'r',
|
||||||
|
'fill',
|
||||||
|
'stroke',
|
||||||
|
'marker',
|
||||||
|
'd',
|
||||||
|
'points',
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,59 +36,53 @@ exports.params = {
|
|||||||
*
|
*
|
||||||
* @author Nikolay Frantsev
|
* @author Nikolay Frantsev
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item, params) {
|
exports.fn = function (item, params) {
|
||||||
|
var attrs = [],
|
||||||
|
sorted = {},
|
||||||
|
orderlen = params.order.length + 1,
|
||||||
|
xmlnsOrder = params.xmlnsOrder || 'front';
|
||||||
|
|
||||||
var attrs = [],
|
if (item.elem) {
|
||||||
sorted = {},
|
item.eachAttr(function (attr) {
|
||||||
orderlen = params.order.length + 1,
|
attrs.push(attr);
|
||||||
xmlnsOrder = params.xmlnsOrder || 'front';
|
});
|
||||||
|
|
||||||
if (item.elem) {
|
attrs.sort(function (a, b) {
|
||||||
|
if (a.prefix != b.prefix) {
|
||||||
|
// xmlns attributes implicitly have the prefix xmlns
|
||||||
|
if (xmlnsOrder == 'front') {
|
||||||
|
if (a.prefix == 'xmlns') return -1;
|
||||||
|
if (b.prefix == 'xmlns') return 1;
|
||||||
|
}
|
||||||
|
return a.prefix < b.prefix ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
item.eachAttr(function(attr) {
|
var aindex = orderlen;
|
||||||
attrs.push(attr);
|
var bindex = orderlen;
|
||||||
});
|
|
||||||
|
|
||||||
attrs.sort(function(a, b) {
|
for (var i = 0; i < params.order.length; i++) {
|
||||||
if (a.prefix != b.prefix) {
|
if (a.name == params.order[i]) {
|
||||||
// xmlns attributes implicitly have the prefix xmlns
|
aindex = i;
|
||||||
if (xmlnsOrder == 'front') {
|
} else if (a.name.indexOf(params.order[i] + '-') === 0) {
|
||||||
if (a.prefix == 'xmlns')
|
aindex = i + 0.5;
|
||||||
return -1;
|
}
|
||||||
if (b.prefix == 'xmlns')
|
if (b.name == params.order[i]) {
|
||||||
return 1;
|
bindex = i;
|
||||||
}
|
} else if (b.name.indexOf(params.order[i] + '-') === 0) {
|
||||||
return a.prefix < b.prefix ? -1 : 1;
|
bindex = i + 0.5;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var aindex = orderlen;
|
if (aindex != bindex) {
|
||||||
var bindex = orderlen;
|
return aindex - bindex;
|
||||||
|
}
|
||||||
|
return a.name < b.name ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
for (var i = 0; i < params.order.length; i++) {
|
attrs.forEach(function (attr) {
|
||||||
if (a.name == params.order[i]) {
|
sorted[attr.name] = attr;
|
||||||
aindex = i;
|
});
|
||||||
} else if (a.name.indexOf(params.order[i] + '-') === 0) {
|
|
||||||
aindex = i + .5;
|
|
||||||
}
|
|
||||||
if (b.name == params.order[i]) {
|
|
||||||
bindex = i;
|
|
||||||
} else if (b.name.indexOf(params.order[i] + '-') === 0) {
|
|
||||||
bindex = i + .5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aindex != bindex) {
|
|
||||||
return aindex - bindex;
|
|
||||||
}
|
|
||||||
return a.name < b.name ? -1 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
attrs.forEach(function (attr) {
|
|
||||||
sorted[attr.name] = attr;
|
|
||||||
});
|
|
||||||
|
|
||||||
item.attrs = sorted;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
item.attrs = sorted;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -15,33 +15,30 @@ exports.description = 'Sorts children of <defs> to improve compression';
|
|||||||
*
|
*
|
||||||
* @author David Leston
|
* @author David Leston
|
||||||
*/
|
*/
|
||||||
exports.fn = function(item) {
|
exports.fn = function (item) {
|
||||||
|
if (item.isElem('defs')) {
|
||||||
if (item.isElem('defs')) {
|
if (item.content) {
|
||||||
|
var frequency = item.content.reduce(function (frequency, child) {
|
||||||
if (item.content) {
|
if (child.elem in frequency) {
|
||||||
var frequency = item.content.reduce(function (frequency, child) {
|
frequency[child.elem]++;
|
||||||
if (child.elem in frequency) {
|
} else {
|
||||||
frequency[child.elem]++;
|
frequency[child.elem] = 1;
|
||||||
} else {
|
|
||||||
frequency[child.elem] = 1;
|
|
||||||
}
|
|
||||||
return frequency;
|
|
||||||
}, {});
|
|
||||||
item.content.sort(function (a, b) {
|
|
||||||
var frequencyComparison = frequency[b.elem] - frequency[a.elem];
|
|
||||||
if (frequencyComparison !== 0 ) {
|
|
||||||
return frequencyComparison;
|
|
||||||
}
|
|
||||||
var lengthComparison = b.elem.length - a.elem.length;
|
|
||||||
if (lengthComparison !== 0) {
|
|
||||||
return lengthComparison;
|
|
||||||
}
|
|
||||||
return a.elem != b.elem ? a.elem > b.elem ? -1 : 1 : 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return frequency;
|
||||||
return true;
|
}, {});
|
||||||
|
item.content.sort(function (a, b) {
|
||||||
|
var frequencyComparison = frequency[b.elem] - frequency[a.elem];
|
||||||
|
if (frequencyComparison !== 0) {
|
||||||
|
return frequencyComparison;
|
||||||
|
}
|
||||||
|
var lengthComparison = b.elem.length - a.elem.length;
|
||||||
|
if (lengthComparison !== 0) {
|
||||||
|
return lengthComparison;
|
||||||
|
}
|
||||||
|
return a.elem != b.elem ? (a.elem > b.elem ? -1 : 1) : 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user