0.2.0 - Mid migration

This commit is contained in:
Daniel Mason 2022-04-25 14:47:15 +12:00
parent 139e6a915e
commit 7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions

2558
web/node_modules/svgo/plugins/_collections.js generated vendored Normal file

File diff suppressed because it is too large Load diff

988
web/node_modules/svgo/plugins/_path.js generated vendored Normal file
View file

@ -0,0 +1,988 @@
/* global a2c */
'use strict';
var rNumber = String.raw`[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?\s*`,
rCommaWsp = String.raw`(?:\s,?\s*|,\s*)`,
rNumberCommaWsp = `(${rNumber})` + rCommaWsp,
rFlagCommaWsp = `([01])${rCommaWsp}?`,
rCoordinatePair = String.raw`(${rNumber})${rCommaWsp}?(${rNumber})`,
rArcSeq = (rNumberCommaWsp + '?').repeat(2) + rNumberCommaWsp + rFlagCommaWsp.repeat(2) + rCoordinatePair;
var regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/,
regCoordinateSequence = new RegExp(rNumber, 'g'),
regArcArgumentSequence = new RegExp(rArcSeq, 'g'),
regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/,
transform2js = require('./_transforms').transform2js,
transformsMultiply = require('./_transforms').transformsMultiply,
transformArc = require('./_transforms').transformArc,
collections = require('./_collections.js'),
referencesProps = collections.referencesProps,
defaultStrokeWidth = collections.attrsGroupsDefaults.presentation['stroke-width'],
cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
prevCtrlPoint;
/**
* Convert path string to JS representation.
*
* @param {String} pathString input string
* @param {Object} params plugin params
* @return {Array} output array
*/
exports.path2js = function(path) {
if (path.pathJS) return path.pathJS;
var paramsLength = { // Number of parameters of every path command
H: 1, V: 1, M: 2, L: 2, T: 2, Q: 4, S: 4, C: 6, A: 7,
h: 1, v: 1, m: 2, l: 2, t: 2, q: 4, s: 4, c: 6, a: 7
},
pathData = [], // JS representation of the path data
instruction, // current instruction context
startMoveto = false;
// splitting path string into array like ['M', '10 50', 'L', '20 30']
path.attr('d').value.split(regPathInstructions).forEach(function(data) {
if (!data) return;
if (!startMoveto) {
if (data == 'M' || data == 'm') {
startMoveto = true;
} else return;
}
// instruction item
if (regPathInstructions.test(data)) {
instruction = data;
// z - instruction w/o data
if (instruction == 'Z' || instruction == 'z') {
pathData.push({
instruction: 'z'
});
}
// data item
} else {
/* jshint boss: true */
if (instruction == 'A' || instruction == 'a') {
var newData = [];
for (var args; (args = regArcArgumentSequence.exec(data));) {
for (var i = 1; i < args.length; i++) {
newData.push(args[i]);
}
}
data = newData;
} else {
data = data.match(regCoordinateSequence);
}
if (!data) return;
data = data.map(Number);
// Subsequent moveto pairs of coordinates are threated as implicit lineto commands
// http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
if (instruction == 'M' || instruction == 'm') {
pathData.push({
instruction: pathData.length == 0 ? 'M' : instruction,
data: data.splice(0, 2)
});
instruction = instruction == 'M' ? 'L' : 'l';
}
for (var pair = paramsLength[instruction]; data.length;) {
pathData.push({
instruction: instruction,
data: data.splice(0, pair)
});
}
}
});
// First moveto is actually absolute. Subsequent coordinates were separated above.
if (pathData.length && pathData[0].instruction == 'm') {
pathData[0].instruction = 'M';
}
path.pathJS = pathData;
return pathData;
};
/**
* Convert relative Path data to absolute.
*
* @param {Array} data input data
* @return {Array} output data
*/
var relative2absolute = exports.relative2absolute = function(data) {
var currentPoint = [0, 0],
subpathPoint = [0, 0],
i;
return data.map(function(item) {
var instruction = item.instruction,
itemData = item.data && item.data.slice();
if (instruction == 'M') {
set(currentPoint, itemData);
set(subpathPoint, itemData);
} else if ('mlcsqt'.indexOf(instruction) > -1) {
for (i = 0; i < itemData.length; i++) {
itemData[i] += currentPoint[i % 2];
}
set(currentPoint, itemData);
if (instruction == 'm') {
set(subpathPoint, itemData);
}
} else if (instruction == 'a') {
itemData[5] += currentPoint[0];
itemData[6] += currentPoint[1];
set(currentPoint, itemData);
} else if (instruction == 'h') {
itemData[0] += currentPoint[0];
currentPoint[0] = itemData[0];
} else if (instruction == 'v') {
itemData[0] += currentPoint[1];
currentPoint[1] = itemData[0];
} else if ('MZLCSQTA'.indexOf(instruction) > -1) {
set(currentPoint, itemData);
} else if (instruction == 'H') {
currentPoint[0] = itemData[0];
} else if (instruction == 'V') {
currentPoint[1] = itemData[0];
} else if (instruction == 'z') {
set(currentPoint, subpathPoint);
}
return instruction == 'z' ?
{ instruction: 'z' } :
{
instruction: instruction.toUpperCase(),
data: itemData
};
});
};
/**
* Apply transformation(s) to the Path data.
*
* @param {Object} elem current element
* @param {Array} path input path data
* @param {Object} params whether to apply transforms to stroked lines and transform precision (used for stroke width)
* @return {Array} output path data
*/
exports.applyTransforms = function(elem, path, params) {
// if there are no 'stroke' attr and references to other objects such as
// gradiends or clip-path which are also subjects to transform.
if (!elem.hasAttr('transform') || !elem.attr('transform').value ||
elem.someAttr(function(attr) {
return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
}))
return path;
var matrix = transformsMultiply(transform2js(elem.attr('transform').value)),
stroke = elem.computedAttr('stroke'),
id = elem.computedAttr('id'),
transformPrecision = params.transformPrecision,
newPoint, scale;
if (stroke && stroke != 'none') {
if (!params.applyTransformsStroked ||
(matrix.data[0] != matrix.data[3] || matrix.data[1] != -matrix.data[2]) &&
(matrix.data[0] != -matrix.data[3] || matrix.data[1] != matrix.data[2]))
return path;
// "stroke-width" should be inside the part with ID, otherwise it can be overrided in <use>
if (id) {
var idElem = elem,
hasStrokeWidth = false;
do {
if (idElem.hasAttr('stroke-width')) hasStrokeWidth = true;
} while (!idElem.hasAttr('id', id) && !hasStrokeWidth && (idElem = idElem.parentNode));
if (!hasStrokeWidth) return path;
}
scale = +Math.sqrt(matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]).toFixed(transformPrecision);
if (scale !== 1) {
var strokeWidth = elem.computedAttr('stroke-width') || defaultStrokeWidth;
if (!elem.hasAttr('vector-effect') || elem.attr('vector-effect').value !== 'non-scaling-stroke') {
if (elem.hasAttr('stroke-width')) {
elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value.trim()
.replace(regNumericValues, function(num) {
return removeLeadingZero(num * scale);
});
} else {
elem.addAttr({
name: 'stroke-width',
prefix: '',
local: 'stroke-width',
value: strokeWidth.replace(regNumericValues, function(num) {
return removeLeadingZero(num * scale);
})
});
}
}
}
} else if (id) { // Stroke and stroke-width can be redefined with <use>
return path;
}
path.forEach(function(pathItem) {
if (pathItem.data) {
// h -> l
if (pathItem.instruction === 'h') {
pathItem.instruction = 'l';
pathItem.data[1] = 0;
// v -> l
} else if (pathItem.instruction === 'v') {
pathItem.instruction = 'l';
pathItem.data[1] = pathItem.data[0];
pathItem.data[0] = 0;
}
// if there is a translate() transform
if (pathItem.instruction === 'M' &&
(matrix.data[4] !== 0 ||
matrix.data[5] !== 0)
) {
// then apply it only to the first absoluted M
newPoint = transformPoint(matrix.data, pathItem.data[0], pathItem.data[1]);
set(pathItem.data, newPoint);
set(pathItem.coords, newPoint);
// clear translate() data from transform matrix
matrix.data[4] = 0;
matrix.data[5] = 0;
} else {
if (pathItem.instruction == 'a') {
transformArc(pathItem.data, matrix.data);
// reduce number of digits in rotation angle
if (Math.abs(pathItem.data[2]) > 80) {
var a = pathItem.data[0],
rotation = pathItem.data[2];
pathItem.data[0] = pathItem.data[1];
pathItem.data[1] = a;
pathItem.data[2] = rotation + (rotation > 0 ? -90 : 90);
}
newPoint = transformPoint(matrix.data, pathItem.data[5], pathItem.data[6]);
pathItem.data[5] = newPoint[0];
pathItem.data[6] = newPoint[1];
} else {
for (var i = 0; i < pathItem.data.length; i += 2) {
newPoint = transformPoint(matrix.data, pathItem.data[i], pathItem.data[i + 1]);
pathItem.data[i] = newPoint[0];
pathItem.data[i + 1] = newPoint[1];
}
}
pathItem.coords[0] = pathItem.base[0] + pathItem.data[pathItem.data.length - 2];
pathItem.coords[1] = pathItem.base[1] + pathItem.data[pathItem.data.length - 1];
}
}
});
// remove transform attr
elem.removeAttr('transform');
return path;
};
/**
* Apply transform 3x3 matrix to x-y point.
*
* @param {Array} matrix transform 3x3 matrix
* @param {Array} point x-y point
* @return {Array} point with new coordinates
*/
function transformPoint(matrix, x, y) {
return [
matrix[0] * x + matrix[2] * y + matrix[4],
matrix[1] * x + matrix[3] * y + matrix[5]
];
}
/**
* Compute Cubic Bézie bounding box.
*
* @see http://processingjs.nihongoresources.com/bezierinfo/
*
* @param {Float} xa
* @param {Float} ya
* @param {Float} xb
* @param {Float} yb
* @param {Float} xc
* @param {Float} yc
* @param {Float} xd
* @param {Float} yd
*
* @return {Object}
*/
exports.computeCubicBoundingBox = function(xa, ya, xb, yb, xc, yc, xd, yd) {
var minx = Number.POSITIVE_INFINITY,
miny = Number.POSITIVE_INFINITY,
maxx = Number.NEGATIVE_INFINITY,
maxy = Number.NEGATIVE_INFINITY,
ts,
t,
x,
y,
i;
// X
if (xa < minx) { minx = xa; }
if (xa > maxx) { maxx = xa; }
if (xd < minx) { minx= xd; }
if (xd > maxx) { maxx = xd; }
ts = computeCubicFirstDerivativeRoots(xa, xb, xc, xd);
for (i = 0; i < ts.length; i++) {
t = ts[i];
if (t >= 0 && t <= 1) {
x = computeCubicBaseValue(t, xa, xb, xc, xd);
// y = computeCubicBaseValue(t, ya, yb, yc, yd);
if (x < minx) { minx = x; }
if (x > maxx) { maxx = x; }
}
}
// Y
if (ya < miny) { miny = ya; }
if (ya > maxy) { maxy = ya; }
if (yd < miny) { miny = yd; }
if (yd > maxy) { maxy = yd; }
ts = computeCubicFirstDerivativeRoots(ya, yb, yc, yd);
for (i = 0; i < ts.length; i++) {
t = ts[i];
if (t >= 0 && t <= 1) {
// x = computeCubicBaseValue(t, xa, xb, xc, xd);
y = computeCubicBaseValue(t, ya, yb, yc, yd);
if (y < miny) { miny = y; }
if (y > maxy) { maxy = y; }
}
}
return {
minx: minx,
miny: miny,
maxx: maxx,
maxy: maxy
};
};
// compute the value for the cubic bezier function at time=t
function computeCubicBaseValue(t, a, b, c, d) {
var mt = 1 - t;
return mt * mt * mt * a + 3 * mt * mt * t * b + 3 * mt * t * t * c + t * t * t * d;
}
// compute the value for the first derivative of the cubic bezier function at time=t
function computeCubicFirstDerivativeRoots(a, b, c, d) {
var result = [-1, -1],
tl = -a + 2 * b - c,
tr = -Math.sqrt(-a * (c - d) + b * b - b * (c + d) + c * c),
dn = -a + 3 * b - 3 * c + d;
if (dn !== 0) {
result[0] = (tl + tr) / dn;
result[1] = (tl - tr) / dn;
}
return result;
}
/**
* Compute Quadratic Bézier bounding box.
*
* @see http://processingjs.nihongoresources.com/bezierinfo/
*
* @param {Float} xa
* @param {Float} ya
* @param {Float} xb
* @param {Float} yb
* @param {Float} xc
* @param {Float} yc
*
* @return {Object}
*/
exports.computeQuadraticBoundingBox = function(xa, ya, xb, yb, xc, yc) {
var minx = Number.POSITIVE_INFINITY,
miny = Number.POSITIVE_INFINITY,
maxx = Number.NEGATIVE_INFINITY,
maxy = Number.NEGATIVE_INFINITY,
t,
x,
y;
// X
if (xa < minx) { minx = xa; }
if (xa > maxx) { maxx = xa; }
if (xc < minx) { minx = xc; }
if (xc > maxx) { maxx = xc; }
t = computeQuadraticFirstDerivativeRoot(xa, xb, xc);
if (t >= 0 && t <= 1) {
x = computeQuadraticBaseValue(t, xa, xb, xc);
// y = computeQuadraticBaseValue(t, ya, yb, yc);
if (x < minx) { minx = x; }
if (x > maxx) { maxx = x; }
}
// Y
if (ya < miny) { miny = ya; }
if (ya > maxy) { maxy = ya; }
if (yc < miny) { miny = yc; }
if (yc > maxy) { maxy = yc; }
t = computeQuadraticFirstDerivativeRoot(ya, yb, yc);
if (t >= 0 && t <=1 ) {
// x = computeQuadraticBaseValue(t, xa, xb, xc);
y = computeQuadraticBaseValue(t, ya, yb, yc);
if (y < miny) { miny = y; }
if (y > maxy) { maxy = y ; }
}
return {
minx: minx,
miny: miny,
maxx: maxx,
maxy: maxy
};
};
// compute the value for the quadratic bezier function at time=t
function computeQuadraticBaseValue(t, a, b, c) {
var mt = 1 - t;
return mt * mt * a + 2 * mt * t * b + t * t * c;
}
// compute the value for the first derivative of the quadratic bezier function at time=t
function computeQuadraticFirstDerivativeRoot(a, b, c) {
var t = -1,
denominator = a - 2 * b + c;
if (denominator !== 0) {
t = (a - b) / denominator;
}
return t;
}
/**
* Convert path array to string.
*
* @param {Array} path input path data
* @param {Object} params plugin params
* @return {String} output path string
*/
exports.js2path = function(path, data, params) {
path.pathJS = data;
if (params.collapseRepeated) {
data = collapseRepeated(data);
}
path.attr('d').value = data.reduce(function(pathString, item) {
var strData = '';
if (item.data) {
strData = cleanupOutData(item.data, params, item.instruction);
}
return pathString += item.instruction + strData;
}, '');
};
/**
* Collapse repeated instructions data
*
* @param {Array} path input path data
* @return {Array} output path data
*/
function collapseRepeated(data) {
var prev,
prevIndex;
// copy an array and modifieds item to keep original data untouched
data = data.reduce(function(newPath, item) {
if (
prev && item.data &&
item.instruction == prev.instruction
) {
// concat previous data with current
if (item.instruction != 'M') {
prev = newPath[prevIndex] = {
instruction: prev.instruction,
data: prev.data.concat(item.data),
coords: item.coords,
base: prev.base
};
} else {
prev.data = item.data;
prev.coords = item.coords;
}
} else {
newPath.push(item);
prev = item;
prevIndex = newPath.length - 1;
}
return newPath;
}, []);
return data;
}
function set(dest, source) {
dest[0] = source[source.length - 2];
dest[1] = source[source.length - 1];
return dest;
}
/**
* Checks if two paths have an intersection by checking convex hulls
* collision using Gilbert-Johnson-Keerthi distance algorithm
* http://entropyinteractive.com/2011/04/gjk-algorithm/
*
* @param {Array} path1 JS path representation
* @param {Array} path2 JS path representation
* @return {Boolean}
*/
exports.intersects = function(path1, path2) {
if (path1.length < 3 || path2.length < 3) return false; // nothing to fill
// Collect points of every subpath.
var points1 = relative2absolute(path1).reduce(gatherPoints, []),
points2 = relative2absolute(path2).reduce(gatherPoints, []);
// Axis-aligned bounding box check.
if (points1.maxX <= points2.minX || points2.maxX <= points1.minX ||
points1.maxY <= points2.minY || points2.maxY <= points1.minY ||
points1.every(function (set1) {
return points2.every(function (set2) {
return set1[set1.maxX][0] <= set2[set2.minX][0] ||
set2[set2.maxX][0] <= set1[set1.minX][0] ||
set1[set1.maxY][1] <= set2[set2.minY][1] ||
set2[set2.maxY][1] <= set1[set1.minY][1];
});
})
) return false;
// Get a convex hull from points of each subpath. Has the most complexity O(n·log n).
var hullNest1 = points1.map(convexHull),
hullNest2 = points2.map(convexHull);
// Check intersection of every subpath of the first path with every subpath of the second.
return hullNest1.some(function(hull1) {
if (hull1.length < 3) return false;
return hullNest2.some(function(hull2) {
if (hull2.length < 3) return false;
var simplex = [getSupport(hull1, hull2, [1, 0])], // create the initial simplex
direction = minus(simplex[0]); // set the direction to point towards the origin
var iterations = 1e4; // infinite loop protection, 10 000 iterations is more than enough
while (true) {
if (iterations-- == 0) {
console.error('Error: infinite loop while processing mergePaths plugin.');
return true; // true is the safe value that means “do nothing with paths”
}
// add a new point
simplex.push(getSupport(hull1, hull2, direction));
// see if the new point was on the correct side of the origin
if (dot(direction, simplex[simplex.length - 1]) <= 0) return false;
// process the simplex
if (processSimplex(simplex, direction)) return true;
}
});
});
function getSupport(a, b, direction) {
return sub(supportPoint(a, direction), supportPoint(b, minus(direction)));
}
// Computes farthest polygon point in particular direction.
// Thanks to knowledge of min/max x and y coordinates we can choose a quadrant to search in.
// Since we're working on convex hull, the dot product is increasing until we find the farthest point.
function supportPoint(polygon, direction) {
var index = direction[1] >= 0 ?
direction[0] < 0 ? polygon.maxY : polygon.maxX :
direction[0] < 0 ? polygon.minX : polygon.minY,
max = -Infinity,
value;
while ((value = dot(polygon[index], direction)) > max) {
max = value;
index = ++index % polygon.length;
}
return polygon[(index || polygon.length) - 1];
}
};
function processSimplex(simplex, direction) {
/* jshint -W004 */
// we only need to handle to 1-simplex and 2-simplex
if (simplex.length == 2) { // 1-simplex
var a = simplex[1],
b = simplex[0],
AO = minus(simplex[1]),
AB = sub(b, a);
// AO is in the same direction as AB
if (dot(AO, AB) > 0) {
// get the vector perpendicular to AB facing O
set(direction, orth(AB, a));
} else {
set(direction, AO);
// only A remains in the simplex
simplex.shift();
}
} else { // 2-simplex
var a = simplex[2], // [a, b, c] = simplex
b = simplex[1],
c = simplex[0],
AB = sub(b, a),
AC = sub(c, a),
AO = minus(a),
ACB = orth(AB, AC), // the vector perpendicular to AB facing away from C
ABC = orth(AC, AB); // the vector perpendicular to AC facing away from B
if (dot(ACB, AO) > 0) {
if (dot(AB, AO) > 0) { // region 4
set(direction, ACB);
simplex.shift(); // simplex = [b, a]
} else { // region 5
set(direction, AO);
simplex.splice(0, 2); // simplex = [a]
}
} else if (dot(ABC, AO) > 0) {
if (dot(AC, AO) > 0) { // region 6
set(direction, ABC);
simplex.splice(1, 1); // simplex = [c, a]
} else { // region 5 (again)
set(direction, AO);
simplex.splice(0, 2); // simplex = [a]
}
} else // region 7
return true;
}
return false;
}
function minus(v) {
return [-v[0], -v[1]];
}
function sub(v1, v2) {
return [v1[0] - v2[0], v1[1] - v2[1]];
}
function dot(v1, v2) {
return v1[0] * v2[0] + v1[1] * v2[1];
}
function orth(v, from) {
var o = [-v[1], v[0]];
return dot(o, minus(from)) < 0 ? minus(o) : o;
}
function gatherPoints(points, item, index, path) {
var subPath = points.length && points[points.length - 1],
prev = index && path[index - 1],
basePoint = subPath.length && subPath[subPath.length - 1],
data = item.data,
ctrlPoint = basePoint;
switch (item.instruction) {
case 'M':
points.push(subPath = []);
break;
case 'H':
addPoint(subPath, [data[0], basePoint[1]]);
break;
case 'V':
addPoint(subPath, [basePoint[0], data[0]]);
break;
case 'Q':
addPoint(subPath, data.slice(0, 2));
prevCtrlPoint = [data[2] - data[0], data[3] - data[1]]; // Save control point for shorthand
break;
case 'T':
if (prev.instruction == 'Q' || prev.instruction == 'T') {
ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]];
addPoint(subPath, ctrlPoint);
prevCtrlPoint = [data[0] - ctrlPoint[0], data[1] - ctrlPoint[1]];
}
break;
case 'C':
// Approximate quibic Bezier curve with middle points between control points
addPoint(subPath, [.5 * (basePoint[0] + data[0]), .5 * (basePoint[1] + data[1])]);
addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]);
addPoint(subPath, [.5 * (data[2] + data[4]), .5 * (data[3] + data[5])]);
prevCtrlPoint = [data[4] - data[2], data[5] - data[3]]; // Save control point for shorthand
break;
case 'S':
if (prev.instruction == 'C' || prev.instruction == 'S') {
addPoint(subPath, [basePoint[0] + .5 * prevCtrlPoint[0], basePoint[1] + .5 * prevCtrlPoint[1]]);
ctrlPoint = [basePoint[0] + prevCtrlPoint[0], basePoint[1] + prevCtrlPoint[1]];
}
addPoint(subPath, [.5 * (ctrlPoint[0] + data[0]), .5 * (ctrlPoint[1]+ data[1])]);
addPoint(subPath, [.5 * (data[0] + data[2]), .5 * (data[1] + data[3])]);
prevCtrlPoint = [data[2] - data[0], data[3] - data[1]];
break;
case 'A':
// Convert the arc to bezier curves and use the same approximation
var curves = a2c.apply(0, basePoint.concat(data));
for (var cData; (cData = curves.splice(0,6).map(toAbsolute)).length;) {
addPoint(subPath, [.5 * (basePoint[0] + cData[0]), .5 * (basePoint[1] + cData[1])]);
addPoint(subPath, [.5 * (cData[0] + cData[2]), .5 * (cData[1] + cData[3])]);
addPoint(subPath, [.5 * (cData[2] + cData[4]), .5 * (cData[3] + cData[5])]);
if (curves.length) addPoint(subPath, basePoint = cData.slice(-2));
}
break;
}
// Save final command coordinates
if (data && data.length >= 2) addPoint(subPath, data.slice(-2));
return points;
function toAbsolute(n, i) { return n + basePoint[i % 2] }
// Writes data about the extreme points on each axle
function addPoint(path, point) {
if (!path.length || point[1] > path[path.maxY][1]) {
path.maxY = path.length;
points.maxY = points.length ? Math.max(point[1], points.maxY) : point[1];
}
if (!path.length || point[0] > path[path.maxX][0]) {
path.maxX = path.length;
points.maxX = points.length ? Math.max(point[0], points.maxX) : point[0];
}
if (!path.length || point[1] < path[path.minY][1]) {
path.minY = path.length;
points.minY = points.length ? Math.min(point[1], points.minY) : point[1];
}
if (!path.length || point[0] < path[path.minX][0]) {
path.minX = path.length;
points.minX = points.length ? Math.min(point[0], points.minX) : point[0];
}
path.push(point);
}
}
/**
* Forms a convex hull from set of points of every subpath using monotone chain convex hull algorithm.
* http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
*
* @param points An array of [X, Y] coordinates
*/
function convexHull(points) {
/* jshint -W004 */
points.sort(function(a, b) {
return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0];
});
var lower = [],
minY = 0,
bottom = 0;
for (var i = 0; i < points.length; i++) {
while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) {
lower.pop();
}
if (points[i][1] < points[minY][1]) {
minY = i;
bottom = lower.length;
}
lower.push(points[i]);
}
var upper = [],
maxY = points.length - 1,
top = 0;
for (var i = points.length; i--;) {
while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) {
upper.pop();
}
if (points[i][1] > points[maxY][1]) {
maxY = i;
top = upper.length;
}
upper.push(points[i]);
}
// last points are equal to starting points of the other part
upper.pop();
lower.pop();
var hull = lower.concat(upper);
hull.minX = 0; // by sorting
hull.maxX = lower.length;
hull.minY = bottom;
hull.maxY = (lower.length + top) % hull.length;
return hull;
}
function cross(o, a, b) {
return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
}
/* Based on code from Snap.svg (Apache 2 license). http://snapsvg.io/
* Thanks to Dmitry Baranovskiy for his great work!
*/
// jshint ignore: start
function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
// for more information of where this Math came from visit:
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
var _120 = Math.PI * 120 / 180,
rad = Math.PI / 180 * (+angle || 0),
res = [],
rotateX = function(x, y, rad) { return x * Math.cos(rad) - y * Math.sin(rad) },
rotateY = function(x, y, rad) { return x * Math.sin(rad) + y * Math.cos(rad) };
if (!recursive) {
x1 = rotateX(x1, y1, -rad);
y1 = rotateY(x1, y1, -rad);
x2 = rotateX(x2, y2, -rad);
y2 = rotateY(x2, y2, -rad);
var x = (x1 - x2) / 2,
y = (y1 - y2) / 2;
var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
if (h > 1) {
h = Math.sqrt(h);
rx = h * rx;
ry = h * ry;
}
var rx2 = rx * rx,
ry2 = ry * ry,
k = (large_arc_flag == sweep_flag ? -1 : 1) *
Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
cx = k * rx * y / ry + (x1 + x2) / 2,
cy = k * -ry * x / rx + (y1 + y2) / 2,
f1 = Math.asin(((y1 - cy) / ry).toFixed(9)),
f2 = Math.asin(((y2 - cy) / ry).toFixed(9));
f1 = x1 < cx ? Math.PI - f1 : f1;
f2 = x2 < cx ? Math.PI - f2 : f2;
f1 < 0 && (f1 = Math.PI * 2 + f1);
f2 < 0 && (f2 = Math.PI * 2 + f2);
if (sweep_flag && f1 > f2) {
f1 = f1 - Math.PI * 2;
}
if (!sweep_flag && f2 > f1) {
f2 = f2 - Math.PI * 2;
}
} else {
f1 = recursive[0];
f2 = recursive[1];
cx = recursive[2];
cy = recursive[3];
}
var df = f2 - f1;
if (Math.abs(df) > _120) {
var f2old = f2,
x2old = x2,
y2old = y2;
f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
x2 = cx + rx * Math.cos(f2);
y2 = cy + ry * Math.sin(f2);
res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
}
df = f2 - f1;
var c1 = Math.cos(f1),
s1 = Math.sin(f1),
c2 = Math.cos(f2),
s2 = Math.sin(f2),
t = Math.tan(df / 4),
hx = 4 / 3 * rx * t,
hy = 4 / 3 * ry * t,
m = [
- hx * s1, hy * c1,
x2 + hx * s2 - x1, y2 - hy * c2 - y1,
x2 - x1, y2 - y1
];
if (recursive) {
return m.concat(res);
} else {
res = m.concat(res);
var newres = [];
for (var i = 0, n = res.length; i < n; i++) {
newres[i] = i % 2 ? rotateY(res[i - 1], res[i], rad) : rotateX(res[i], res[i + 1], rad);
}
return newres;
}
}
// jshint ignore: end

310
web/node_modules/svgo/plugins/_transforms.js generated vendored Normal file
View file

@ -0,0 +1,310 @@
'use strict';
var regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/,
regTransformSplit = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/,
regNumericValues = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
/**
* Convert transform string to JS representation.
*
* @param {String} transformString input string
* @param {Object} params plugin params
* @return {Array} output array
*/
exports.transform2js = function(transformString) {
// JS representation of the transform data
var transforms = [],
// current transform context
current;
// split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', '']
transformString.split(regTransformSplit).forEach(function(item) {
/*jshint -W084 */
var num;
if (item) {
// if item is a translate function
if (regTransformTypes.test(item)) {
// then collect it and change current context
transforms.push(current = { name: item });
// else if item is data
} else {
// then split it into [10, 50] and collect as context.data
while (num = regNumericValues.exec(item)) {
num = Number(num);
if (current.data)
current.data.push(num);
else
current.data = [num];
}
}
}
});
// return empty array if broken transform (no data)
return current && current.data ? transforms : [];
};
/**
* Multiply transforms into one.
*
* @param {Array} input transforms array
* @return {Array} output matrix array
*/
exports.transformsMultiply = function(transforms) {
// convert transforms objects to the matrices
transforms = transforms.map(function(transform) {
if (transform.name === 'matrix') {
return transform.data;
}
return transformToMatrix(transform);
});
// multiply all matrices into one
transforms = {
name: 'matrix',
data: transforms.length > 0 ? transforms.reduce(multiplyTransformMatrices) : []
};
return transforms;
};
/**
* Do math like a schoolgirl.
*
* @type {Object}
*/
var mth = exports.mth = {
rad: function(deg) {
return deg * Math.PI / 180;
},
deg: function(rad) {
return rad * 180 / Math.PI;
},
cos: function(deg) {
return Math.cos(this.rad(deg));
},
acos: function(val, floatPrecision) {
return +(this.deg(Math.acos(val)).toFixed(floatPrecision));
},
sin: function(deg) {
return Math.sin(this.rad(deg));
},
asin: function(val, floatPrecision) {
return +(this.deg(Math.asin(val)).toFixed(floatPrecision));
},
tan: function(deg) {
return Math.tan(this.rad(deg));
},
atan: function(val, floatPrecision) {
return +(this.deg(Math.atan(val)).toFixed(floatPrecision));
}
};
/**
* Decompose matrix into simple transforms. See
* http://frederic-wang.fr/decomposition-of-2d-transform-matrices.html
*
* @param {Object} data matrix transform object
* @return {Object|Array} transforms array or original transform object
*/
exports.matrixToTransform = function(transform, params) {
var floatPrecision = params.floatPrecision,
data = transform.data,
transforms = [],
sx = +Math.hypot(data[0], data[1]).toFixed(params.transformPrecision),
sy = +((data[0] * data[3] - data[1] * data[2]) / sx).toFixed(params.transformPrecision),
colsSum = data[0] * data[2] + data[1] * data[3],
rowsSum = data[0] * data[1] + data[2] * data[3],
scaleBefore = rowsSum != 0 || sx == sy;
// [..., ..., ..., ..., tx, ty] → translate(tx, ty)
if (data[4] || data[5]) {
transforms.push({ name: 'translate', data: data.slice(4, data[5] ? 6 : 5) });
}
// [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy)
if (!data[1] && data[2]) {
transforms.push({ name: 'skewX', data: [mth.atan(data[2] / sy, floatPrecision)] });
// [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy)
} else if (data[1] && !data[2]) {
transforms.push({ name: 'skewY', data: [mth.atan(data[1] / data[0], floatPrecision)] });
sx = data[0];
sy = data[3];
// [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or
// [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore)
} else if (!colsSum || (sx == 1 && sy == 1) || !scaleBefore) {
if (!scaleBefore) {
sx = (data[0] < 0 ? -1 : 1) * Math.hypot(data[0], data[2]);
sy = (data[3] < 0 ? -1 : 1) * Math.hypot(data[1], data[3]);
transforms.push({ name: 'scale', data: [sx, sy] });
}
var angle = Math.min(Math.max(-1, data[0] / sx), 1),
rotate = [mth.acos(angle, floatPrecision) * ((scaleBefore ? 1 : sy) * data[1] < 0 ? -1 : 1)];
if (rotate[0]) transforms.push({ name: 'rotate', data: rotate });
if (rowsSum && colsSum) transforms.push({
name: 'skewX',
data: [mth.atan(colsSum / (sx * sx), floatPrecision)]
});
// rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point)
if (rotate[0] && (data[4] || data[5])) {
transforms.shift();
var cos = data[0] / sx,
sin = data[1] / (scaleBefore ? sx : sy),
x = data[4] * (scaleBefore || sy),
y = data[5] * (scaleBefore || sx),
denom = (Math.pow(1 - cos, 2) + Math.pow(sin, 2)) * (scaleBefore || sx * sy);
rotate.push(((1 - cos) * x - sin * y) / denom);
rotate.push(((1 - cos) * y + sin * x) / denom);
}
// Too many transformations, return original matrix if it isn't just a scale/translate
} else if (data[1] || data[2]) {
return transform;
}
if (scaleBefore && (sx != 1 || sy != 1) || !transforms.length) transforms.push({
name: 'scale',
data: sx == sy ? [sx] : [sx, sy]
});
return transforms;
};
/**
* Convert transform to the matrix data.
*
* @param {Object} transform transform object
* @return {Array} matrix data
*/
function transformToMatrix(transform) {
if (transform.name === 'matrix') return transform.data;
var matrix;
switch (transform.name) {
case 'translate':
// [1, 0, 0, 1, tx, ty]
matrix = [1, 0, 0, 1, transform.data[0], transform.data[1] || 0];
break;
case 'scale':
// [sx, 0, 0, sy, 0, 0]
matrix = [transform.data[0], 0, 0, transform.data[1] || transform.data[0], 0, 0];
break;
case 'rotate':
// [cos(a), sin(a), -sin(a), cos(a), x, y]
var cos = mth.cos(transform.data[0]),
sin = mth.sin(transform.data[0]),
cx = transform.data[1] || 0,
cy = transform.data[2] || 0;
matrix = [cos, sin, -sin, cos, (1 - cos) * cx + sin * cy, (1 - cos) * cy - sin * cx];
break;
case 'skewX':
// [1, 0, tan(a), 1, 0, 0]
matrix = [1, 0, mth.tan(transform.data[0]), 1, 0, 0];
break;
case 'skewY':
// [1, tan(a), 0, 1, 0, 0]
matrix = [1, mth.tan(transform.data[0]), 0, 1, 0, 0];
break;
}
return matrix;
}
/**
* Applies transformation to an arc. To do so, we represent ellipse as a matrix, multiply it
* by the transformation matrix and use a singular value decomposition to represent in a form
* rotate(θ)·scale(a b)·rotate(φ). This gives us new ellipse params a, b and θ.
* SVD is being done with the formulae provided by Wolffram|Alpha (svd {{m0, m2}, {m1, m3}})
*
* @param {Array} arc [a, b, rotation in deg]
* @param {Array} transform transformation matrix
* @return {Array} arc transformed input arc
*/
exports.transformArc = function(arc, transform) {
var a = arc[0],
b = arc[1],
rot = arc[2] * Math.PI / 180,
cos = Math.cos(rot),
sin = Math.sin(rot),
h = Math.pow(arc[5] * cos + arc[6] * sin, 2) / (4 * a * a) +
Math.pow(arc[6] * cos - arc[5] * sin, 2) / (4 * b * b);
if (h > 1) {
h = Math.sqrt(h);
a *= h;
b *= h;
}
var ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0],
m = multiplyTransformMatrices(transform, ellipse),
// Decompose the new ellipse matrix
lastCol = m[2] * m[2] + m[3] * m[3],
squareSum = m[0] * m[0] + m[1] * m[1] + lastCol,
root = Math.hypot(m[0] - m[3], m[1] + m[2]) * Math.hypot(m[0] + m[3], m[1] - m[2]);
if (!root) { // circle
arc[0] = arc[1] = Math.sqrt(squareSum / 2);
arc[2] = 0;
} else {
var majorAxisSqr = (squareSum + root) / 2,
minorAxisSqr = (squareSum - root) / 2,
major = Math.abs(majorAxisSqr - lastCol) > 1e-6,
sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol,
rowsSum = m[0] * m[2] + m[1] * m[3],
term1 = m[0] * sub + m[2] * rowsSum,
term2 = m[1] * sub + m[3] * rowsSum;
arc[0] = Math.sqrt(majorAxisSqr);
arc[1] = Math.sqrt(minorAxisSqr);
arc[2] = ((major ? term2 < 0 : term1 > 0) ? -1 : 1) *
Math.acos((major ? term1 : term2) / Math.hypot(term1, term2)) * 180 / Math.PI;
}
if ((transform[0] < 0) !== (transform[3] < 0)) {
// Flip the sweep flag if coordinates are being flipped horizontally XOR vertically
arc[4] = 1 - arc[4];
}
return arc;
};
/**
* Multiply transformation matrices.
*
* @param {Array} a matrix A data
* @param {Array} b matrix B data
* @return {Array} result
*/
function multiplyTransformMatrices(a, b) {
return [
a[0] * b[0] + a[2] * b[1],
a[1] * b[0] + a[3] * b[1],
a[0] * b[2] + a[2] * b[3],
a[1] * b[2] + a[3] * b[3],
a[0] * b[4] + a[2] * b[5] + a[4],
a[1] * b[4] + a[3] * b[5] + a[5]
];
}

View file

@ -0,0 +1,82 @@
'use strict';
exports.type = 'full';
exports.active = false;
exports.description = 'adds attributes to an outer <svg> element';
var ENOCLS = `Error in plugin "addAttributesToSVGElement": absent parameters.
It should have a list of "attributes" or one "attribute".
Config example:
plugins:
- addAttributesToSVGElement:
attribute: "mySvg"
plugins:
- addAttributesToSVGElement:
attributes: ["mySvg", "size-big"]
plugins:
- addAttributesToSVGElement:
attributes:
- focusable: false
- data-image: icon`;
/**
* Add attributes to an outer <svg> element. Example config:
*
* plugins:
* - addAttributesToSVGElement:
* attribute: 'data-icon'
*
* plugins:
* - addAttributesToSVGElement:
* attributes: ['data-icon', 'data-disabled']
*
* plugins:
* - addAttributesToSVGElement:
* attributes:
* - focusable: false
* - data-image: icon
*
* @author April Arcus
*/
exports.fn = function(data, params) {
if (!params || !(Array.isArray(params.attributes) || params.attribute)) {
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;
};

View file

@ -0,0 +1,50 @@
'use strict';
exports.type = 'full';
exports.active = false;
exports.description = 'adds classnames to an outer <svg> element';
var ENOCLS = `Error in plugin "addClassesToSVGElement": absent parameters.
It should have a list of classes in "classNames" or one "className".
Config example:
plugins:
- addClassesToSVGElement:
className: "mySvg"
plugins:
- addClassesToSVGElement:
classNames: ["mySvg", "size-big"]
`;
/**
* Add classnames to an outer <svg> element. Example config:
*
* plugins:
* - addClassesToSVGElement:
* className: 'mySvg'
*
* plugins:
* - addClassesToSVGElement:
* classNames: ['mySvg', 'size-big']
*
* @author April Arcus
*/
exports.fn = function(data, params) {
if (!params || !(Array.isArray(params.classNames) && params.classNames.some(String) || params.className)) {
console.error(ENOCLS);
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;
};

56
web/node_modules/svgo/plugins/cleanupAttrs.js generated vendored Normal file
View file

@ -0,0 +1,56 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'cleanups attributes from newlines, trailing and repeating spaces';
exports.params = {
newlines: true,
trim: true,
spaces: true
};
var regNewlinesNeedSpace = /(\S)\r?\n(\S)/g,
regNewlines = /\r?\n/g,
regSpaces = /\s{2,}/g;
/**
* Cleanup attributes values from newlines, trailing and repeating spaces.
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
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;
});
// 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, ' ');
}
});
}
};

View file

@ -0,0 +1,84 @@
'use strict';
exports.type = 'full';
exports.active = true;
exports.description = 'remove or cleanup enable-background attribute when possible';
/**
* Remove or cleanup enable-background attr which coincides with a width/height box.
*
* @see http://www.w3.org/TR/SVG/filters.html#EnableBackgroundProperty
*
* @example
* <svg width="100" height="50" enable-background="new 0 0 100 50">
*
* <svg width="100" height="50">
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
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'];
function checkEnableBackground(item) {
if (
item.isElem(elems) &&
item.hasAttr('enable-background') &&
item.hasAttr('width') &&
item.hasAttr('height')
) {
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');
});
};

209
web/node_modules/svgo/plugins/cleanupIDs.js generated vendored Normal file
View file

@ -0,0 +1,209 @@
'use strict';
exports.type = 'full';
exports.active = true;
exports.description = 'removes unused IDs and minifies used';
exports.params = {
remove: true,
minify: true,
prefix: '',
preserve: [],
preservePrefixes: [],
force: false
};
var referencesProps = new Set(require('./_collections').referencesProps),
regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/,
regReferencesHref = /^#(.+?)$/,
regReferencesBegin = /(\w+)\./,
styleOrScript = ['style', 'script'],
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', '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
* (only if there are no any <style> or <script>).
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
*
* @author Kir Belevich
*/
exports.fn = function(data, params) {
var currentID,
currentIDstring,
IDs = new Map(),
referencesIDs = new Map(),
hasStyleOrScript = false,
preserveIDs = new Set(Array.isArray(params.preserve) ? params.preserve : params.preserve ? [params.preserve] : []),
preserveIDPrefixes = new Set(Array.isArray(params.preservePrefixes) ? params.preservePrefixes : (params.preservePrefixes ? [params.preservePrefixes] : [])),
idValuePrefix = '#',
idValuePostfix = '.';
/**
* Bananas!
*
* @param {Array} items input items
* @return {Array} output items
*/
function monkeys(items) {
for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
var item = items.content[i];
// quit if <style> or <script> present ('force' param prevents quitting)
if (!params.force) {
if (item.isElem(styleOrScript)) {
hasStyleOrScript = true;
continue;
}
// Don't remove IDs if the whole SVG consists only of defs.
if (item.isElem('defs') && item.parentNode.isElem('svg')) {
var hasDefsOnly = true;
for (var j = i + 1; j < items.content.length; j++) {
if (items.content[j].isElem()) {
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);
if (hasStyleOrScript) {
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;
};
/**
* Check if an ID starts with any one of a list of strings.
*
* @param {Array} of prefix strings
* @param {String} current ID
* @return {Boolean} if currentID starts with one of the strings in prefixArray
*/
function idMatchesPrefix(prefixArray, currentID) {
if (!currentID) return false;
for (var prefix of prefixArray) if (currentID.startsWith(prefix)) return true;
return false;
}
/**
* Generate unique minimal ID.
*
* @param {Array} [currentID] current ID
* @return {Array} generated ID array
*/
function generateID(currentID) {
if (!currentID) return [0];
currentID[currentID.length - 1]++;
for(var i = currentID.length - 1; i > 0; i--) {
if (currentID[i] > maxIDindex) {
currentID[i] = 0;
if (currentID[i - 1] !== undefined) {
currentID[i - 1]++;
}
}
}
if (currentID[0] > maxIDindex) {
currentID[0] = 0;
currentID.unshift(0);
}
return currentID;
}
/**
* Get string from generated ID array.
*
* @param {Array} arr input ID array
* @return {String} output ID string
*/
function getIDstring(arr, params) {
var str = params.prefix;
return str + arr.map(i => generateIDchars[i]).join('');
}

139
web/node_modules/svgo/plugins/cleanupListOfValues.js generated vendored Normal file
View file

@ -0,0 +1,139 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'rounds list of values to the fixed precision';
exports.params = {
floatPrecision: 3,
leadingZero: true,
defaultPx: true,
convertToPx: true
};
var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
regSeparator = /\s+,?\s*|,\s*/,
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
absoluteLengths = { // relative to px
cm: 96/2.54,
mm: 96/25.4,
in: 96,
pt: 4/3,
pc: 16
};
/**
* Round list of values to the fixed precision.
*
* @example
* <svg viewBox="0 0 200.28423 200.28423" enable-background="new 0 0 200.28423 200.28423">
*
* <svg viewBox="0 0 200.284 200.284" enable-background="new 0 0 200.284 200.284">
*
*
* <polygon points="208.250977 77.1308594 223.069336 ... "/>
*
* <polygon points="208.251 77.131 223.069 ... "/>
*
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author kiyopikko
*/
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('viewBox') ) {
roundValues(item.attrs.viewBox);
}
if ( item.hasAttr('stroke-dasharray') ) {
roundValues(item.attrs['stroke-dasharray']);
}
if ( item.hasAttr('dx') ) {
roundValues(item.attrs.dx);
}
if ( item.hasAttr('dy') ) {
roundValues(item.attrs.dy);
}
if ( item.hasAttr('x') ) {
roundValues(item.attrs.x);
}
if ( item.hasAttr('y') ) {
roundValues(item.attrs.y);
}
function roundValues($prop){
var num, units,
match,
matchNew,
lists = $prop.value,
listsArr = lists.split(regSeparator),
roundedListArr = [],
roundedList;
listsArr.forEach(function(elem){
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] || '';
// convert absolute values to pixels
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;
}
};

88
web/node_modules/svgo/plugins/cleanupNumericValues.js generated vendored Normal file
View file

@ -0,0 +1,88 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'rounds numeric values to the fixed precision, removes default px units';
exports.params = {
floatPrecision: 3,
leadingZero: true,
defaultPx: true,
convertToPx: true
};
var regNumericValues = /^([\-+]?\d*\.?\d+([eE][\-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/,
removeLeadingZero = require('../lib/svgo/tools').removeLeadingZero,
absoluteLengths = { // relative to px
cm: 96/2.54,
mm: 96/25.4,
in: 96,
pt: 4/3,
pc: 16
};
/**
* Round numeric values to the fixed precision,
* remove default 'px' units.
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
if (item.isElem()) {
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;
}
});
}
};

87
web/node_modules/svgo/plugins/collapseGroups.js generated vendored Normal file
View file

@ -0,0 +1,87 @@
'use strict';
exports.type = 'perItemReverse';
exports.active = true;
exports.description = 'collapses useless groups';
var collections = require('./_collections'),
attrsInheritable = collections.inheritableAttrs,
animationElems = collections.elemsGroups.animation;
function hasAnimatedAttr(item) {
/* jshint validthis:true */
return item.isElem(animationElems) && item.hasAttr('attributeName', this) ||
!item.isEmpty() && item.content.some(hasAnimatedAttr, this);
}
/*
* Collapse useless groups.
*
* @example
* <g>
* <g attr1="val1">
* <path d="..."/>
* </g>
* </g>
*
* <g>
* <g>
* <path attr1="val1" d="..."/>
* </g>
* </g>
*
* <path attr1="val1" d="..."/>
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
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];
if (inner.isElem() && !inner.hasAttr('id') && !g.hasAttr('filter') &&
!(g.hasAttr('class') && inner.hasAttr('class')) && (
!g.hasAttr('clip-path') && !g.hasAttr('mask') ||
inner.isElem('g') && !g.hasAttr('transform') && !inner.hasAttr('transform')
)
) {
g.eachAttr(function(attr) {
if (g.content.some(hasAnimatedAttr, attr.name)) return;
if (!inner.hasAttr(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) })) {
item.spliceContent(i, 1, g.content);
}
}
});
}
};

130
web/node_modules/svgo/plugins/convertColors.js generated vendored Normal file
View file

@ -0,0 +1,130 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'converts colors: rgb() to #rrggbb and #rrggbb to #rgb';
exports.params = {
currentColor: false,
names2hex: true,
rgb2hex: true,
shorthex: true,
shortname: true
};
var collections = require('./_collections'),
rNumber = '([+-]?(?:\\d*\\.\\d+|\\d+\\.?)%?)',
rComma = '\\s*,\\s*',
regRGB = new RegExp('^rgb\\(\\s*' + rNumber + rComma + rNumber + rComma + rNumber + '\\s*\\)$'),
regHEX = /^\#(([a-fA-F0-9])\2){3}$/,
none = /\bnone\b/i;
/**
* Convert different colors formats in element attributes to hex.
*
* @see http://www.w3.org/TR/SVG/types.html#DataTypeColor
* @see http://www.w3.org/TR/SVG/single-page.html#types-ColorKeywords
*
* @example
* Convert color name keyword to long hex:
* fuchsia #ff00ff
*
* Convert rgb() to long hex:
* rgb(255, 0, 255) #ff00ff
* rgb(50%, 100, 100%) #7f64ff
*
* Convert long hex to short hex:
* #aabbcc #abc
*
* Convert hex to short name
* #000080 navy
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
if (item.elem) {
item.eachAttr(function(attr) {
if (collections.colorsProps.indexOf(attr.name) > -1) {
var val = attr.value,
match;
// 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';
}
}
// Convert color name keyword to long hex
if (params.names2hex && val.toLowerCase() in collections.colorsNames) {
val = collections.colorsNames[val.toLowerCase()];
}
// 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);
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;
}
});
}
};
/**
* Convert [r, g, b] to #rrggbb.
*
* @see https://gist.github.com/983535
*
* @example
* rgb2hex([255, 255, 255]) // '#ffffff'
*
* @param {Array} rgb [r, g, b]
* @return {String} #rrggbb
*
* @author Jed Schmidt
*/
function rgb2hex(rgb) {
return '#' + ('00000' + (rgb[0] << 16 | rgb[1] << 8 | rgb[2]).toString(16)).slice(-6).toUpperCase();
}

View file

@ -0,0 +1,39 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'converts non-eccentric <ellipse>s to <circle>s';
/**
* Converts non-eccentric <ellipse>s to <circle>s.
*
* @see http://www.w3.org/TR/SVG/shapes.html
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Taylor Hunt
*/
exports.fn = function(item) {
if (item.isElem('ellipse')) {
var rx = item.attr('rx').value || 0;
var ry = item.attr('ry').value || 0;
if (rx === ry ||
rx === 'auto' || ry === 'auto' // SVG2
) {
var radius = rx !== 'auto' ? rx : ry;
item.renameElem('circle');
item.removeAttr(['rx', 'ry']);
item.addAttr({
name: 'r',
value: radius,
prefix: '',
local: 'r',
});
}
}
return;
};

971
web/node_modules/svgo/plugins/convertPathData.js generated vendored Normal file
View file

@ -0,0 +1,971 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'optimizes path data: writes in shorter form, applies transformations';
exports.params = {
applyTransforms: true,
applyTransformsStroked: true,
makeArcs: {
threshold: 2.5, // coefficient of rounding error
tolerance: 0.5 // percentage of radius
},
straightCurves: true,
lineShorthands: true,
curveSmoothShorthands: true,
floatPrecision: 3,
transformPrecision: 5,
removeUseless: true,
collapseRepeated: true,
utilizeAbsolute: true,
leadingZero: true,
negativeExtraSpace: true,
noSpaceAfterFlags: true,
forceAbsolutePath: false
};
var pathElems = require('./_collections.js').pathElems,
path2js = require('./_path.js').path2js,
js2path = require('./_path.js').js2path,
applyTransforms = require('./_path.js').applyTransforms,
cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
roundData,
precision,
error,
arcThreshold,
arcTolerance,
hasMarkerMid,
hasStrokeLinecap;
/**
* Convert absolute Path to relative,
* collapse repeated instructions,
* detect and convert Lineto shorthands,
* remove useless instructions like "l0,0",
* trim useless delimiters and leading zeros,
* decrease accuracy of floating-point numbers.
*
* @see http://www.w3.org/TR/SVG/paths.html#PathData
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
if (item.isElem(pathElems) && item.hasAttr('d')) {
precision = params.floatPrecision;
error = precision !== false ? +Math.pow(.1, precision).toFixed(precision) : 1e-2;
roundData = precision > 0 && precision < 20 ? strongRound : round;
if (params.makeArcs) {
arcThreshold = params.makeArcs.threshold;
arcTolerance = params.makeArcs.tolerance;
}
hasMarkerMid = item.hasAttr('marker-mid');
var stroke = item.computedAttr('stroke'),
strokeLinecap = item.computedAttr('stroke');
hasStrokeLinecap = stroke && stroke != 'none' && strokeLinecap && strokeLinecap != 'butt';
var data = path2js(item);
// TODO: get rid of functions returns
if (data.length) {
convertToRelative(data);
if (params.applyTransforms) {
data = applyTransforms(item, data, params);
}
data = filters(data, params);
if (params.utilizeAbsolute) {
data = convertToMixed(data, params);
}
js2path(item, data, params);
}
}
};
/**
* Convert absolute path data coordinates to relative.
*
* @param {Array} path input path data
* @param {Object} params plugin params
* @return {Array} output path data
*/
function convertToRelative(path) {
var point = [0, 0],
subpathPoint = [0, 0],
baseItem;
path.forEach(function(item, index) {
var instruction = item.instruction,
data = item.data;
// data !== !z
if (data) {
// already relative
// recalculate current point
if ('mcslqta'.indexOf(instruction) > -1) {
point[0] += data[data.length - 2];
point[1] += data[data.length - 1];
if (instruction === 'm') {
subpathPoint[0] = point[0];
subpathPoint[1] = point[1];
baseItem = item;
}
} else if (instruction === 'h') {
point[0] += data[0];
} else if (instruction === 'v') {
point[1] += data[0];
}
// convert absolute path data coordinates to relative
// if "M" was not transformed from "m"
// M → m
if (instruction === 'M') {
if (index > 0) instruction = 'm';
data[0] -= point[0];
data[1] -= point[1];
subpathPoint[0] = point[0] += data[0];
subpathPoint[1] = point[1] += data[1];
baseItem = item;
}
// L → l
// T → t
else if ('LT'.indexOf(instruction) > -1) {
instruction = instruction.toLowerCase();
// x y
// 0 1
data[0] -= point[0];
data[1] -= point[1];
point[0] += data[0];
point[1] += data[1];
// C → c
} else if (instruction === 'C') {
instruction = 'c';
// x1 y1 x2 y2 x y
// 0 1 2 3 4 5
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
data[4] -= point[0];
data[5] -= point[1];
point[0] += data[4];
point[1] += data[5];
// S → s
// Q → q
} else if ('SQ'.indexOf(instruction) > -1) {
instruction = instruction.toLowerCase();
// x1 y1 x y
// 0 1 2 3
data[0] -= point[0];
data[1] -= point[1];
data[2] -= point[0];
data[3] -= point[1];
point[0] += data[2];
point[1] += data[3];
// A → a
} else if (instruction === 'A') {
instruction = 'a';
// rx ry x-axis-rotation large-arc-flag sweep-flag x y
// 0 1 2 3 4 5 6
data[5] -= point[0];
data[6] -= point[1];
point[0] += data[5];
point[1] += data[6];
// H → h
} else if (instruction === 'H') {
instruction = 'h';
data[0] -= point[0];
point[0] += data[0];
// V → v
} else if (instruction === 'V') {
instruction = 'v';
data[0] -= point[1];
point[1] += data[0];
}
item.instruction = instruction;
item.data = data;
// store absolute coordinates for later use
item.coords = point.slice(-2);
}
// !data === z, reset current point
else if (instruction == 'z') {
if (baseItem) {
item.coords = baseItem.coords;
}
point[0] = subpathPoint[0];
point[1] = subpathPoint[1];
}
item.base = index > 0 ? path[index - 1].coords : [0, 0];
});
return path;
}
/**
* Main filters loop.
*
* @param {Array} path input path data
* @param {Object} params plugin params
* @return {Array} output path data
*/
function filters(path, params) {
var stringify = data2Path.bind(null, params),
relSubpoint = [0, 0],
pathBase = [0, 0],
prev = {};
path = path.filter(function(item, index, path) {
var instruction = item.instruction,
data = item.data,
next = path[index + 1];
if (data) {
var sdata = data,
circle;
if (instruction === 's') {
sdata = [0, 0].concat(data);
if ('cs'.indexOf(prev.instruction) > -1) {
var pdata = prev.data,
n = pdata.length;
// (-x, -y) of the prev tangent point relative to the current point
sdata[0] = pdata[n - 2] - pdata[n - 4];
sdata[1] = pdata[n - 1] - pdata[n - 3];
}
}
// convert curves to arcs if possible
if (
params.makeArcs &&
(instruction == 'c' || instruction == 's') &&
isConvex(sdata) &&
(circle = findCircle(sdata))
) {
var r = roundData([circle.radius])[0],
angle = findArcAngle(sdata, circle),
sweep = sdata[5] * sdata[0] - sdata[4] * sdata[1] > 0 ? 1 : 0,
arc = {
instruction: 'a',
data: [r, r, 0, 0, sweep, sdata[4], sdata[5]],
coords: item.coords.slice(),
base: item.base
},
output = [arc],
// relative coordinates to adjust the found circle
relCenter = [circle.center[0] - sdata[4], circle.center[1] - sdata[5]],
relCircle = { center: relCenter, radius: circle.radius },
arcCurves = [item],
hasPrev = 0,
suffix = '',
nextLonghand;
if (
prev.instruction == 'c' && isConvex(prev.data) && isArcPrev(prev.data, circle) ||
prev.instruction == 'a' && prev.sdata && isArcPrev(prev.sdata, circle)
) {
arcCurves.unshift(prev);
arc.base = prev.base;
arc.data[5] = arc.coords[0] - arc.base[0];
arc.data[6] = arc.coords[1] - arc.base[1];
var prevData = prev.instruction == 'a' ? prev.sdata : prev.data;
var prevAngle = findArcAngle(prevData,
{
center: [prevData[4] + circle.center[0], prevData[5] + circle.center[1]],
radius: circle.radius
}
);
angle += prevAngle;
if (angle > Math.PI) arc.data[3] = 1;
hasPrev = 1;
}
// check if next curves are fitting the arc
for (var j = index; (next = path[++j]) && ~'cs'.indexOf(next.instruction);) {
var nextData = next.data;
if (next.instruction == 's') {
nextLonghand = makeLonghand({instruction: 's', data: next.data.slice() },
path[j - 1].data);
nextData = nextLonghand.data;
nextLonghand.data = nextData.slice(0, 2);
suffix = stringify([nextLonghand]);
}
if (isConvex(nextData) && isArc(nextData, relCircle)) {
angle += findArcAngle(nextData, relCircle);
if (angle - 2 * Math.PI > 1e-3) break; // more than 360°
if (angle > Math.PI) arc.data[3] = 1;
arcCurves.push(next);
if (2 * Math.PI - angle > 1e-3) { // less than 360°
arc.coords = next.coords;
arc.data[5] = arc.coords[0] - arc.base[0];
arc.data[6] = arc.coords[1] - arc.base[1];
} else {
// full circle, make a half-circle arc and add a second one
arc.data[5] = 2 * (relCircle.center[0] - nextData[4]);
arc.data[6] = 2 * (relCircle.center[1] - nextData[5]);
arc.coords = [arc.base[0] + arc.data[5], arc.base[1] + arc.data[6]];
arc = {
instruction: 'a',
data: [r, r, 0, 0, sweep,
next.coords[0] - arc.coords[0], next.coords[1] - arc.coords[1]],
coords: next.coords,
base: arc.coords
};
output.push(arc);
j++;
break;
}
relCenter[0] -= nextData[4];
relCenter[1] -= nextData[5];
} else break;
}
if ((stringify(output) + suffix).length < stringify(arcCurves).length) {
if (path[j] && path[j].instruction == 's') {
makeLonghand(path[j], path[j - 1].data);
}
if (hasPrev) {
var prevArc = output.shift();
roundData(prevArc.data);
relSubpoint[0] += prevArc.data[5] - prev.data[prev.data.length - 2];
relSubpoint[1] += prevArc.data[6] - prev.data[prev.data.length - 1];
prev.instruction = 'a';
prev.data = prevArc.data;
item.base = prev.coords = prevArc.coords;
}
arc = output.shift();
if (arcCurves.length == 1) {
item.sdata = sdata.slice(); // preserve curve data for future checks
} else if (arcCurves.length - 1 - hasPrev > 0) {
// filter out consumed next items
path.splice.apply(path, [index + 1, arcCurves.length - 1 - hasPrev].concat(output));
}
if (!arc) return false;
instruction = 'a';
data = arc.data;
item.coords = arc.coords;
}
}
// Rounding relative coordinates, taking in account accummulating error
// to get closer to absolute coordinates. Sum of rounded value remains same:
// l .25 3 .25 2 .25 3 .25 2 -> l .3 3 .2 2 .3 3 .2 2
if (precision !== false) {
if ('mltqsc'.indexOf(instruction) > -1) {
for (var i = data.length; i--;) {
data[i] += item.base[i % 2] - relSubpoint[i % 2];
}
} else if (instruction == 'h') {
data[0] += item.base[0] - relSubpoint[0];
} else if (instruction == 'v') {
data[0] += item.base[1] - relSubpoint[1];
} else if (instruction == 'a') {
data[5] += item.base[0] - relSubpoint[0];
data[6] += item.base[1] - relSubpoint[1];
}
roundData(data);
if (instruction == 'h') relSubpoint[0] += data[0];
else if (instruction == 'v') relSubpoint[1] += data[0];
else {
relSubpoint[0] += data[data.length - 2];
relSubpoint[1] += data[data.length - 1];
}
roundData(relSubpoint);
if (instruction.toLowerCase() == 'm') {
pathBase[0] = relSubpoint[0];
pathBase[1] = relSubpoint[1];
}
}
// convert straight curves into lines segments
if (params.straightCurves) {
if (
instruction === 'c' &&
isCurveStraightLine(data) ||
instruction === 's' &&
isCurveStraightLine(sdata)
) {
if (next && next.instruction == 's')
makeLonghand(next, data); // fix up next curve
instruction = 'l';
data = data.slice(-2);
}
else if (
instruction === 'q' &&
isCurveStraightLine(data)
) {
if (next && next.instruction == 't')
makeLonghand(next, data); // fix up next curve
instruction = 'l';
data = data.slice(-2);
}
else if (
instruction === 't' &&
prev.instruction !== 'q' &&
prev.instruction !== 't'
) {
instruction = 'l';
data = data.slice(-2);
}
else if (
instruction === 'a' &&
(data[0] === 0 || data[1] === 0)
) {
instruction = 'l';
data = data.slice(-2);
}
}
// horizontal and vertical line shorthands
// l 50 0 → h 50
// l 0 50 → v 50
if (
params.lineShorthands &&
instruction === 'l'
) {
if (data[1] === 0) {
instruction = 'h';
data.pop();
} else if (data[0] === 0) {
instruction = 'v';
data.shift();
}
}
// collapse repeated commands
// h 20 h 30 -> h 50
if (
params.collapseRepeated &&
!hasMarkerMid &&
('mhv'.indexOf(instruction) > -1) &&
prev.instruction &&
instruction == prev.instruction.toLowerCase() &&
(
(instruction != 'h' && instruction != 'v') ||
(prev.data[0] >= 0) == (item.data[0] >= 0)
)) {
prev.data[0] += data[0];
if (instruction != 'h' && instruction != 'v') {
prev.data[1] += data[1];
}
prev.coords = item.coords;
path[index] = prev;
return false;
}
// convert curves into smooth shorthands
if (params.curveSmoothShorthands && prev.instruction) {
// curveto
if (instruction === 'c') {
// c + c → c + s
if (
prev.instruction === 'c' &&
data[0] === -(prev.data[2] - prev.data[4]) &&
data[1] === -(prev.data[3] - prev.data[5])
) {
instruction = 's';
data = data.slice(2);
}
// s + c → s + s
else if (
prev.instruction === 's' &&
data[0] === -(prev.data[0] - prev.data[2]) &&
data[1] === -(prev.data[1] - prev.data[3])
) {
instruction = 's';
data = data.slice(2);
}
// [^cs] + c → [^cs] + s
else if (
'cs'.indexOf(prev.instruction) === -1 &&
data[0] === 0 &&
data[1] === 0
) {
instruction = 's';
data = data.slice(2);
}
}
// quadratic Bézier curveto
else if (instruction === 'q') {
// q + q → q + t
if (
prev.instruction === 'q' &&
data[0] === (prev.data[2] - prev.data[0]) &&
data[1] === (prev.data[3] - prev.data[1])
) {
instruction = 't';
data = data.slice(2);
}
// t + q → t + t
else if (
prev.instruction === 't' &&
data[2] === prev.data[0] &&
data[3] === prev.data[1]
) {
instruction = 't';
data = data.slice(2);
}
}
}
// remove useless non-first path segments
if (params.removeUseless && !hasStrokeLinecap) {
// l 0,0 / h 0 / v 0 / q 0,0 0,0 / t 0,0 / c 0,0 0,0 0,0 / s 0,0 0,0
if (
(
'lhvqtcs'.indexOf(instruction) > -1
) &&
data.every(function(i) { return i === 0; })
) {
path[index] = prev;
return false;
}
// a 25,25 -30 0,1 0,0
if (
instruction === 'a' &&
data[5] === 0 &&
data[6] === 0
) {
path[index] = prev;
return false;
}
}
item.instruction = instruction;
item.data = data;
prev = item;
} else {
// z resets coordinates
relSubpoint[0] = pathBase[0];
relSubpoint[1] = pathBase[1];
if (prev.instruction == 'z') return false;
prev = item;
}
return true;
});
return path;
}
/**
* Writes data in shortest form using absolute or relative coordinates.
*
* @param {Array} data input path data
* @return {Boolean} output
*/
function convertToMixed(path, params) {
var prev = path[0];
path = path.filter(function(item, index) {
if (index == 0) return true;
if (!item.data) {
prev = item;
return true;
}
var instruction = item.instruction,
data = item.data,
adata = data && data.slice(0);
if ('mltqsc'.indexOf(instruction) > -1) {
for (var i = adata.length; i--;) {
adata[i] += item.base[i % 2];
}
} else if (instruction == 'h') {
adata[0] += item.base[0];
} else if (instruction == 'v') {
adata[0] += item.base[1];
} else if (instruction == 'a') {
adata[5] += item.base[0];
adata[6] += item.base[1];
}
roundData(adata);
var absoluteDataStr = cleanupOutData(adata, params),
relativeDataStr = cleanupOutData(data, params);
// Convert to absolute coordinates if it's shorter or forceAbsolutePath is true.
// v-20 -> V0
// Don't convert if it fits following previous instruction.
// l20 30-10-50 instead of l20 30L20 30
if (
params.forceAbsolutePath || (
absoluteDataStr.length < relativeDataStr.length &&
!(
params.negativeExtraSpace &&
instruction == prev.instruction &&
prev.instruction.charCodeAt(0) > 96 &&
absoluteDataStr.length == relativeDataStr.length - 1 &&
(data[0] < 0 || /^0\./.test(data[0]) && prev.data[prev.data.length - 1] % 1)
))
) {
item.instruction = instruction.toUpperCase();
item.data = adata;
}
prev = item;
return true;
});
return path;
}
/**
* Checks if curve is convex. Control points of such a curve must form
* a convex quadrilateral with diagonals crosspoint inside of it.
*
* @param {Array} data input path data
* @return {Boolean} output
*/
function isConvex(data) {
var center = getIntersection([0, 0, data[2], data[3], data[0], data[1], data[4], data[5]]);
return center &&
(data[2] < center[0] == center[0] < 0) &&
(data[3] < center[1] == center[1] < 0) &&
(data[4] < center[0] == center[0] < data[0]) &&
(data[5] < center[1] == center[1] < data[1]);
}
/**
* Computes lines equations by two points and returns their intersection point.
*
* @param {Array} coords 8 numbers for 4 pairs of coordinates (x,y)
* @return {Array|undefined} output coordinate of lines' crosspoint
*/
function getIntersection(coords) {
// Prev line equation parameters.
var a1 = coords[1] - coords[3], // y1 - y2
b1 = coords[2] - coords[0], // x2 - x1
c1 = coords[0] * coords[3] - coords[2] * coords[1], // x1 * y2 - x2 * y1
// Next line equation parameters
a2 = coords[5] - coords[7], // y1 - y2
b2 = coords[6] - coords[4], // x2 - x1
c2 = coords[4] * coords[7] - coords[5] * coords[6], // x1 * y2 - x2 * y1
denom = (a1 * b2 - a2 * b1);
if (!denom) return; // parallel lines havn't an intersection
var cross = [
(b1 * c2 - b2 * c1) / denom,
(a1 * c2 - a2 * c1) / -denom
];
if (
!isNaN(cross[0]) && !isNaN(cross[1]) &&
isFinite(cross[0]) && isFinite(cross[1])
) {
return cross;
}
}
/**
* Decrease accuracy of floating-point numbers
* in path data keeping a specified number of decimals.
* Smart rounds values like 2.3491 to 2.35 instead of 2.349.
* Doesn't apply "smartness" if the number precision fits already.
*
* @param {Array} data input data array
* @return {Array} output data array
*/
function strongRound(data) {
for (var i = data.length; i-- > 0;) {
if (data[i].toFixed(precision) != data[i]) {
var rounded = +data[i].toFixed(precision - 1);
data[i] = +Math.abs(rounded - data[i]).toFixed(precision + 1) >= error ?
+data[i].toFixed(precision) :
rounded;
}
}
return data;
}
/**
* Simple rounding function if precision is 0.
*
* @param {Array} data input data array
* @return {Array} output data array
*/
function round(data) {
for (var i = data.length; i-- > 0;) {
data[i] = Math.round(data[i]);
}
return data;
}
/**
* Checks if a curve is a straight line by measuring distance
* from middle points to the line formed by end points.
*
* @param {Array} xs array of curve points x-coordinates
* @param {Array} ys array of curve points y-coordinates
* @return {Boolean}
*/
function isCurveStraightLine(data) {
// Get line equation a·x + b·y + c = 0 coefficients a, b (c = 0) by start and end points.
var i = data.length - 2,
a = -data[i + 1], // y1 y2 (y1 = 0)
b = data[i], // x2 x1 (x1 = 0)
d = 1 / (a * a + b * b); // same part for all points
if (i <= 1 || !isFinite(d)) return false; // curve that ends at start point isn't the case
// Distance from point (x0, y0) to the line is sqrt((c a·x0 b·y0)² / (a² + b²))
while ((i -= 2) >= 0) {
if (Math.sqrt(Math.pow(a * data[i] + b * data[i + 1], 2) * d) > error)
return false;
}
return true;
}
/**
* Converts next curve from shorthand to full form using the current curve data.
*
* @param {Object} item curve to convert
* @param {Array} data current curve data
*/
function makeLonghand(item, data) {
switch (item.instruction) {
case 's': item.instruction = 'c'; break;
case 't': item.instruction = 'q'; break;
}
item.data.unshift(data[data.length - 2] - data[data.length - 4], data[data.length - 1] - data[data.length - 3]);
return item;
}
/**
* Returns distance between two points
*
* @param {Array} point1 first point coordinates
* @param {Array} point2 second point coordinates
* @return {Number} distance
*/
function getDistance(point1, point2) {
return Math.hypot(point1[0] - point2[0], point1[1] - point2[1]);
}
/**
* Returns coordinates of the curve point corresponding to the certain t
* a·(1 - t)³·p1 + b·(1 - t)²·t·p2 + c·(1 - t)··p3 + d··p4,
* where pN are control points and p1 is zero due to relative coordinates.
*
* @param {Array} curve array of curve points coordinates
* @param {Number} t parametric position from 0 to 1
* @return {Array} Point coordinates
*/
function getCubicBezierPoint(curve, t) {
var sqrT = t * t,
cubT = sqrT * t,
mt = 1 - t,
sqrMt = mt * mt;
return [
3 * sqrMt * t * curve[0] + 3 * mt * sqrT * curve[2] + cubT * curve[4],
3 * sqrMt * t * curve[1] + 3 * mt * sqrT * curve[3] + cubT * curve[5]
];
}
/**
* Finds circle by 3 points of the curve and checks if the curve fits the found circle.
*
* @param {Array} curve
* @return {Object|undefined} circle
*/
function findCircle(curve) {
var midPoint = getCubicBezierPoint(curve, 1/2),
m1 = [midPoint[0] / 2, midPoint[1] / 2],
m2 = [(midPoint[0] + curve[4]) / 2, (midPoint[1] + curve[5]) / 2],
center = getIntersection([
m1[0], m1[1],
m1[0] + m1[1], m1[1] - m1[0],
m2[0], m2[1],
m2[0] + (m2[1] - midPoint[1]), m2[1] - (m2[0] - midPoint[0])
]),
radius = center && getDistance([0, 0], center),
tolerance = Math.min(arcThreshold * error, arcTolerance * radius / 100);
if (center && radius < 1e15 &&
[1/4, 3/4].every(function(point) {
return Math.abs(getDistance(getCubicBezierPoint(curve, point), center) - radius) <= tolerance;
}))
return { center: center, radius: radius};
}
/**
* Checks if a curve fits the given circle.
*
* @param {Object} circle
* @param {Array} curve
* @return {Boolean}
*/
function isArc(curve, circle) {
var tolerance = Math.min(arcThreshold * error, arcTolerance * circle.radius / 100);
return [0, 1/4, 1/2, 3/4, 1].every(function(point) {
return Math.abs(getDistance(getCubicBezierPoint(curve, point), circle.center) - circle.radius) <= tolerance;
});
}
/**
* Checks if a previous curve fits the given circle.
*
* @param {Object} circle
* @param {Array} curve
* @return {Boolean}
*/
function isArcPrev(curve, circle) {
return isArc(curve, {
center: [circle.center[0] + curve[4], circle.center[1] + curve[5]],
radius: circle.radius
});
}
/**
* Finds angle of a curve fitting the given arc.
* @param {Array} curve
* @param {Object} relCircle
* @return {Number} angle
*/
function findArcAngle(curve, relCircle) {
var x1 = -relCircle.center[0],
y1 = -relCircle.center[1],
x2 = curve[4] - relCircle.center[0],
y2 = curve[5] - relCircle.center[1];
return Math.acos(
(x1 * x2 + y1 * y2) /
Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2))
);
}
/**
* Converts given path data to string.
*
* @param {Object} params
* @param {Array} pathData
* @return {String}
*/
function data2Path(params, pathData) {
return pathData.reduce(function(pathString, item) {
var strData = '';
if (item.data) {
strData = cleanupOutData(roundData(item.data.slice()), params);
}
return pathString + item.instruction + strData;
}, '');
}

149
web/node_modules/svgo/plugins/convertShapeToPath.js generated vendored Normal file
View file

@ -0,0 +1,149 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'converts basic shapes to more compact path form';
exports.params = {
convertArcs: false
};
var none = { value: 0 },
regNumber = /[-+]?(?:\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/g;
/**
* Converts basic shape to more compact path.
* It also allows further optimizations like
* combining paths with similar attributes.
*
* @see http://www.w3.org/TR/SVG/shapes.html
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Lev Solntsev
*/
exports.fn = function(item, params) {
var convertArcs = params && params.convertArcs;
if (
item.isElem('rect') &&
item.hasAttr('width') &&
item.hasAttr('height') &&
!item.hasAttr('rx') &&
!item.hasAttr('ry')
) {
var x = +(item.attr('x') || none).value,
y = +(item.attr('y') || none).value,
width = +item.attr('width').value,
height = +item.attr('height').value;
// Values like '100%' compute to NaN, thus running after
// cleanupNumericValues when 'px' units has already been removed.
// TODO: Calculate sizes from % and non-px units if possible.
if (isNaN(x - y + width - height)) return;
var pathData =
'M' + x + ' ' + y +
'H' + (x + width) +
'V' + (y + height) +
'H' + x +
'z';
item.addAttr({
name: 'd',
value: pathData,
prefix: '',
local: 'd'
});
item.renameElem('path')
.removeAttr(['x', 'y', 'width', 'height']);
} else if (item.isElem('line')) {
var x1 = +(item.attr('x1') || none).value,
y1 = +(item.attr('y1') || none).value,
x2 = +(item.attr('x2') || none).value,
y2 = +(item.attr('y2') || none).value;
if (isNaN(x1 - y1 + x2 - y2)) return;
item.addAttr({
name: 'd',
value: 'M' + x1 + ' ' + y1 + 'L' + x2 + ' ' + y2,
prefix: '',
local: 'd'
});
item.renameElem('path')
.removeAttr(['x1', 'y1', 'x2', 'y2']);
} else if ((
item.isElem('polyline') ||
item.isElem('polygon')
) &&
item.hasAttr('points')
) {
var coords = (item.attr('points').value.match(regNumber) || []).map(Number);
if (coords.length < 4) return false;
item.addAttr({
name: 'd',
value: 'M' + coords.slice(0,2).join(' ') +
'L' + coords.slice(2).join(' ') +
(item.isElem('polygon') ? 'z' : ''),
prefix: '',
local: 'd'
});
item.renameElem('path')
.removeAttr('points');
} else if (item.isElem('circle') && convertArcs) {
var cx = +(item.attr('cx') || none).value;
var cy = +(item.attr('cy') || none).value;
var r = +(item.attr('r') || none).value;
if (isNaN(cx - cy + r)) {
return;
}
var cPathData =
'M' + cx + ' ' + (cy - r) +
'A' + r + ' ' + r + ' 0 1 0 ' + cx + ' ' + (cy + r) +
'A' + r + ' ' + r + ' 0 1 0 ' + cx + ' ' + (cy - r) +
'Z';
item.addAttr({
name: 'd',
value: cPathData,
prefix: '',
local: 'd',
});
item.renameElem('path').removeAttr(['cx', 'cy', 'r']);
} else if (item.isElem('ellipse') && convertArcs) {
var ecx = +(item.attr('cx') || none).value;
var ecy = +(item.attr('cy') || none).value;
var rx = +(item.attr('rx') || none).value;
var ry = +(item.attr('ry') || none).value;
if (isNaN(ecx - ecy + rx - ry)) {
return;
}
var ePathData =
'M' + ecx + ' ' + (ecy - ry) +
'A' + rx + ' ' + ry + ' 0 1 0 ' + ecx + ' ' + (ecy + ry) +
'A' + rx + ' ' + ry + ' 0 1 0 ' + ecx + ' ' + (ecy - ry) +
'Z';
item.addAttr({
name: 'd',
value: ePathData,
prefix: '',
local: 'd',
});
item.renameElem('path').removeAttr(['cx', 'cy', 'rx', 'ry']);
}
};

125
web/node_modules/svgo/plugins/convertStyleToAttrs.js generated vendored Normal file
View file

@ -0,0 +1,125 @@
/* jshint quotmark: false */
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'converts style to attributes';
exports.params = {
keepImportant: false
};
var stylingProps = require('./_collections').attrsGroups.presentation,
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
rSingleQuotes = "'(?:[^'\\n\\r\\\\]|" + rEscape + ")*?(?:'|$)", // string in single quotes: 'smth'
rQuotes = '"(?:[^"\\n\\r\\\\]|' + rEscape + ')*?(?:"|$)', // string in double quotes: "smth"
rQuotedString = new RegExp('^' + g(rSingleQuotes, rQuotes) + '$'),
// Parentheses, E.g.: url(data:image/png;base64,iVBO...).
// ':' and ';' inside of it should be threated as is. (Just like in strings.)
rParenthesis = '\\(' + g('[^\'"()\\\\]+', rEscape, rSingleQuotes, rQuotes) + '*?' + '\\)',
// The value. It can have strings and parentheses (see above). Fallbacks to anything in case of unexpected input.
rValue = '\\s*(' + g('[^!\'"();\\\\]+?', rEscape, rSingleQuotes, rQuotes, rParenthesis, '[^;]*?') + '*?' + ')',
// End of declaration. Spaces outside of capturing groups help to do natural trimming.
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.
*
* @example
* <g style="fill:#000; color: #fff;">
*
* <g fill="#000" color="#fff">
*
* @example
* <g style="fill:#000; color: #fff; -webkit-blah: blah">
*
* <g fill="#000" color="#fff" style="-webkit-blah: blah">
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
/* jshint boss: true */
if (item.elem && item.hasAttr('style')) {
// ['opacity: 1', 'color: #000']
var styleValue = item.attr('style').value,
styles = [],
attrs = {};
// Strip CSS comments preserving escape sequences and strings.
styleValue = styleValue.replace(regStripComments, function(match) {
return match[0] == '/' ? '' :
match[0] == '\\' && /[-g-z]/i.test(match[1]) ? match[1] : match;
});
regDeclarationBlock.lastIndex = 0;
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() {
return '(?:' + Array.prototype.join.call(arguments, '|') + ')';
}

363
web/node_modules/svgo/plugins/convertTransform.js generated vendored Normal file
View file

@ -0,0 +1,363 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'collapses multiple transformations and optimizes it';
exports.params = {
convertToShorts: true,
// degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default
floatPrecision: 3,
transformPrecision: 5,
matrixToTransform: true,
shortTranslate: true,
shortScale: true,
shortRotate: true,
removeUseless: true,
collapseIntoOne: true,
leadingZero: true,
negativeExtraSpace: false
};
var cleanupOutData = require('../lib/svgo/tools').cleanupOutData,
transform2js = require('./_transforms.js').transform2js,
transformsMultiply = require('./_transforms.js').transformsMultiply,
matrixToTransform = require('./_transforms.js').matrixToTransform,
degRound,
floatRound,
transformRound;
/**
* Convert matrices to the short aliases,
* convert long translate, scale or rotate transform notations to the shorts ones,
* convert transforms to the matrices and multiply them all into one,
* remove useless transforms.
*
* @see http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
if (item.elem) {
// transform
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);
}
}
};
/**
* Main function.
*
* @param {Object} item input item
* @param {String} attrName attribute name
* @param {Object} params plugin params
*/
function convertTransform(item, attrName, params) {
var data = transform2js(item.attr(attrName).value);
params = definePrecision(data, params);
if (params.collapseIntoOne && data.length > 1) {
data = [transformsMultiply(data)];
}
if (params.convertToShorts) {
data = convertToShorts(data, params);
} else {
data.forEach(roundTransform);
}
if (params.removeUseless) {
data = removeUseless(data);
}
if (data.length) {
item.attr(attrName).value = js2transform(data, params);
} else {
item.removeAttr(attrName);
}
}
/**
* Defines precision to work with certain parts.
* transformPrecision - for scale and four first matrix parameters (needs a better precision due to multiplying),
* floatPrecision - for translate including two last matrix and rotate parameters,
* degPrecision - for rotate and skew. By default it's equal to (rougly)
* transformPrecision - 2 or floatPrecision whichever is lower. Can be set in params.
*
* @param {Array} transforms input array
* @param {Object} params plugin params
* @return {Array} output array
*/
function definePrecision(data, params) {
/* jshint validthis: true */
var matrixData = data.reduce(getMatrixData, []),
significantDigits = params.transformPrecision;
// Clone params so it don't affect other elements transformations.
params = Object.assign({}, params);
// Limit transform precision with matrix one. Calculating with larger precision doesn't add any value.
if (matrixData.length) {
params.transformPrecision = Math.min(params.transformPrecision,
Math.max.apply(Math, matrixData.map(floatDigits)) || params.transformPrecision);
significantDigits = Math.max.apply(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));
}
floatRound = params.floatPrecision >= 1 && params.floatPrecision < 20 ?
smartRound.bind(this, params.floatPrecision) :
round;
degRound = params.degPrecision >= 1 && params.floatPrecision < 20 ?
smartRound.bind(this, params.degPrecision) :
round;
transformRound = params.transformPrecision >= 1 && params.floatPrecision < 20 ?
smartRound.bind(this, params.transformPrecision) :
round;
return params;
}
/**
* Gathers four first matrix parameters.
*
* @param {Array} a array of data
* @param {Object} transform
* @return {Array} output array
*/
function getMatrixData(a, b) {
return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a;
}
/**
* Returns number of digits after the point. 0.125 3
*/
function floatDigits(n) {
return (n = String(n)).slice(n.indexOf('.')).length - 1;
}
/**
* Convert transforms to the shorthand alternatives.
*
* @param {Array} transforms input array
* @param {Object} params plugin params
* @return {Array} output array
*/
function convertToShorts(transforms, params) {
for(var i = 0; i < transforms.length; i++) {
var transform = transforms[i];
// convert matrix to the short aliases
if (
params.matrixToTransform &&
transform.name === 'matrix'
) {
var decomposed = matrixToTransform(transform, params);
if (decomposed != transform &&
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;
transform = transforms[i];
}
}
return transforms;
}
/**
* Remove useless transforms.
*
* @param {Array} transforms input array
* @return {Array} output array
*/
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 true;
});
}
/**
* Convert transforms JS representation to string.
*
* @param {Array} transformJS JS representation array
* @param {Object} params plugin params
* @return {String} output string
*/
function js2transform(transformJS, params) {
var transformString = '';
// collect output value string
transformJS.forEach(function(transform) {
roundTransform(transform);
transformString += (transformString && ' ') + transform.name + '(' + cleanupOutData(transform.data, params) + ')';
});
return transformString;
}
function roundTransform(transform) {
switch (transform.name) {
case 'translate':
transform.data = floatRound(transform.data);
break;
case 'rotate':
transform.data = degRound(transform.data.slice(0, 1)).concat(floatRound(transform.data.slice(1)));
break;
case 'skewX':
case 'skewY':
transform.data = degRound(transform.data);
break;
case 'scale':
transform.data = transformRound(transform.data);
break;
case 'matrix':
transform.data = transformRound(transform.data.slice(0, 4)).concat(floatRound(transform.data.slice(4)));
break;
}
return transform;
}
/**
* Rounds numbers in array.
*
* @param {Array} data input data array
* @return {Array} output data array
*/
function round(data) {
return data.map(Math.round);
}
/**
* Decrease accuracy of floating-point numbers
* in transforms keeping a specified number of decimals.
* Smart rounds values like 2.349 to 2.35.
*
* @param {Number} fixed number of decimals
* @param {Array} data input data array
* @return {Array} output data array
*/
function smartRound(precision, data) {
for (var i = data.length, tolerance = +Math.pow(.1, precision).toFixed(precision); i--;) {
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;
}

245
web/node_modules/svgo/plugins/inlineStyles.js generated vendored Normal file
View file

@ -0,0 +1,245 @@
'use strict';
exports.type = 'full';
exports.active = true;
exports.params = {
onlyMatchedOnce: true,
removeMatchedSelectors: true,
useMqs: ['', 'screen'],
usePseudos: ['']
};
exports.description = 'inline styles (additional options)';
var csstree = require('css-tree'),
cssTools = require('../lib/css-tools');
/**
* Moves + merges styles from style elements to element styles
*
* Options
* onlyMatchedOnce (default: true)
* inline only selectors that match once
*
* removeMatchedSelectors (default: true)
* clean up matched selectors,
* leave selectors that hadn't matched
*
* useMqs (default: ['', 'screen'])
* what media queries to be used
* empty string element for styles outside media queries
*
* usePseudos (default: [''])
* what pseudo-classes/-elements to be used
* empty string element for all non-pseudo-classes and/or -elements
*
* @param {Object} document document element
* @param {Object} opts plugin params
*
* @author strarsis <strarsis@gmail.com>
*/
exports.fn = function(document, opts) {
// collect <style/>s
var styleEls = document.querySelectorAll('style');
//no <styles/>s, nothing to do
if (styleEls === null) {
return document;
}
var styles = [],
selectors = [];
for (var styleEl of styleEls) {
if (styleEl.isEmpty() || styleEl.closestElem('foreignObject')) {
// skip empty <style/>s or <foreignObject> content.
continue;
}
var cssStr = cssTools.getCssStr(styleEl);
// collect <style/>s and their css ast
var cssAst = {};
try {
cssAst = csstree.parse(cssStr, {
parseValue: false,
parseCustomProperty: false
});
} catch (parseError) {
// console.warn('Warning: Parse error of styles of <style/> element, skipped. Error details: ' + parseError);
continue;
}
styles.push({
styleEl: styleEl,
cssAst: cssAst
});
selectors = selectors.concat(cssTools.flattenToSelectors(cssAst));
}
// filter for mediaqueries to be used or without any mediaquery
var selectorsMq = cssTools.filterByMqs(selectors, opts.useMqs);
// filter for pseudo elements to be used
var selectorsPseudo = cssTools.filterByPseudos(selectorsMq, opts.usePseudos);
// remove PseudoClass from its SimpleSelector for proper matching
cssTools.cleanPseudos(selectorsPseudo);
// stable sort selectors
var sortedSelectors = cssTools.sortSelectors(selectorsPseudo).reverse();
var selector,
selectedEl;
// match selectors
for (selector of sortedSelectors) {
var selectorStr = csstree.generate(selector.item.data),
selectedEls = null;
try {
selectedEls = document.querySelectorAll(selectorStr);
} catch (selectError) {
if (selectError.constructor === SyntaxError) {
// console.warn('Warning: Syntax error when trying to select \n\n' + selectorStr + '\n\n, skipped. Error details: ' + selectError);
continue;
}
throw selectError;
}
if (selectedEls === null) {
// nothing selected
continue;
}
selector.selectedEls = selectedEls;
}
// apply <style/> styles to matched elements
for (selector of sortedSelectors) {
if(!selector.selectedEls) {
continue;
}
if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) {
// skip selectors that match more than once if option onlyMatchedOnce is enabled
continue;
}
// apply <style/> to matched elements
for (selectedEl of selector.selectedEls) {
if (selector.rule === null) {
continue;
}
// merge declarations
csstree.walk(selector.rule, {visit: 'Declaration', enter: function(styleCsstreeDeclaration) {
// existing inline styles have higher priority
// no inline styles, external styles, external styles used
// inline styles, external styles same priority as inline styles, inline styles used
// inline styles, external styles higher priority than inline styles, external styles used
var styleDeclaration = cssTools.csstreeToStyleDeclaration(styleCsstreeDeclaration);
if (selectedEl.style.getPropertyValue(styleDeclaration.name) !== null &&
selectedEl.style.getPropertyPriority(styleDeclaration.name) >= styleDeclaration.priority) {
return;
}
selectedEl.style.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority);
}});
}
if (opts.removeMatchedSelectors && selector.selectedEls !== null && selector.selectedEls.length > 0) {
// clean up matching simple selectors if option removeMatchedSelectors is enabled
selector.rule.prelude.children.remove(selector.item);
}
}
if (!opts.removeMatchedSelectors) {
return document; // no further processing required
}
// clean up matched class + ID attribute values
for (selector of sortedSelectors) {
if(!selector.selectedEls) {
continue;
}
if (opts.onlyMatchedOnce && selector.selectedEls !== null && selector.selectedEls.length > 1) {
// skip selectors that match more than once if option onlyMatchedOnce is enabled
continue;
}
for (selectedEl of selector.selectedEls) {
// class
var firstSubSelector = selector.item.data.children.first();
if(firstSubSelector.type === 'ClassSelector') {
selectedEl.class.remove(firstSubSelector.name);
}
// clean up now empty class attributes
if(typeof selectedEl.class.item(0) === 'undefined') {
selectedEl.removeAttr('class');
}
// ID
if(firstSubSelector.type === 'IdSelector') {
selectedEl.removeAttr('id', firstSubSelector.name);
}
}
}
// clean up now empty elements
for (var style of styles) {
csstree.walk(style.cssAst, {visit: 'Rule', enter: function(node, item, list) {
// clean up <style/> atrules without any rulesets left
if (node.type === 'Atrule' &&
// only Atrules containing rulesets
node.block !== null &&
node.block.children.isEmpty()) {
list.remove(item);
return;
}
// clean up <style/> rulesets without any css selectors left
if (node.type === 'Rule' &&
node.prelude.children.isEmpty()) {
list.remove(item);
}
}});
if (style.cssAst.children.isEmpty()) {
// clean up now emtpy <style/>s
var styleParentEl = style.styleEl.parentNode;
styleParentEl.spliceContent(styleParentEl.content.indexOf(style.styleEl), 1);
if (styleParentEl.elem === 'defs' &&
styleParentEl.content.length === 0) {
// also clean up now empty <def/>s
var defsParentEl = styleParentEl.parentNode;
defsParentEl.spliceContent(defsParentEl.content.indexOf(styleParentEl), 1);
}
continue;
}
// update existing, left over <style>s
cssTools.setCssStr(style.styleEl, csstree.generate(style.cssAst));
}
return document;
};

73
web/node_modules/svgo/plugins/mergePaths.js generated vendored Normal file
View file

@ -0,0 +1,73 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'merges multiple paths in one if possible';
exports.params = {
collapseRepeated: true,
force: false,
leadingZero: true,
negativeExtraSpace: true,
noSpaceAfterFlags: true
};
var path2js = require('./_path.js').path2js,
js2path = require('./_path.js').js2path,
intersects = require('./_path.js').intersects;
/**
* Merge multiple Paths into one.
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich, Lev Solntsev
*/
exports.fn = function(item, params) {
if (!item.isElem() || item.isEmpty()) return;
var prevContentItem = null,
prevContentItemKeys = null;
item.content = item.content.filter(function(contentItem) {
if (prevContentItem &&
prevContentItem.isElem('path') &&
prevContentItem.isEmpty() &&
prevContentItem.hasAttr('d') &&
contentItem.isElem('path') &&
contentItem.isEmpty() &&
contentItem.hasAttr('d')
) {
if (!prevContentItemKeys) {
prevContentItemKeys = Object.keys(prevContentItem.attrs);
}
var contentItemAttrs = Object.keys(contentItem.attrs),
equalData = prevContentItemKeys.length == contentItemAttrs.length &&
contentItemAttrs.every(function(key) {
return key == 'd' ||
prevContentItem.hasAttr(key) &&
prevContentItem.attr(key).value == contentItem.attr(key).value;
}),
prevPathJS = path2js(prevContentItem),
curPathJS = path2js(contentItem);
if (equalData && (params.force || !intersects(prevPathJS, curPathJS))) {
js2path(prevContentItem, prevPathJS.concat(curPathJS), params);
return false;
}
}
prevContentItem = contentItem;
prevContentItemKeys = null;
return true;
});
};

160
web/node_modules/svgo/plugins/minifyStyles.js generated vendored Executable file
View file

@ -0,0 +1,160 @@
'use strict';
exports.type = 'full';
exports.active = true;
exports.description = 'minifies styles and removes unused styles based on usage data';
exports.params = {
// ... CSSO options goes here
// additional
usage: {
force: false, // force to use usage data even if it unsafe (document contains <script> or on* attributes)
ids: true,
classes: true,
tags: true
}
};
var csso = require('csso');
/**
* Minifies styles (<style> element + style attribute) using CSSO
*
* @author strarsis <strarsis@gmail.com>
*/
exports.fn = function(ast, options) {
options = options || {};
var minifyOptionsForStylesheet = cloneObject(options);
var minifyOptionsForAttribute = cloneObject(options);
var elems = findStyleElems(ast);
minifyOptionsForStylesheet.usage = collectUsageData(ast, options);
minifyOptionsForAttribute.usage = null;
elems.forEach(function(elem) {
if (elem.isElem('style')) {
// <style> element
var styleCss = elem.content[0].text || elem.content[0].cdata || [];
var DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text';
elem.content[0][DATA] = csso.minify(styleCss, minifyOptionsForStylesheet).css;
} else {
// style attribute
var elemStyle = elem.attr('style').value;
elem.attr('style').value = csso.minifyBlock(elemStyle, minifyOptionsForAttribute).css;
}
});
return ast;
};
function cloneObject(obj) {
var result = {};
for (var key in obj) {
result[key] = obj[key];
}
return result;
}
function findStyleElems(ast) {
function walk(items, styles) {
for (var i = 0; i < items.content.length; i++) {
var item = items.content[i];
// go deeper
if (item.content) {
walk(item, styles);
}
if (item.isElem('style') && !item.isEmpty()) {
styles.push(item);
} else if (item.isElem() && item.hasAttr('style')) {
styles.push(item);
}
}
return styles;
}
return walk(ast, []);
}
function shouldFilter(options, name) {
if ('usage' in options === false) {
return true;
}
if (options.usage && name in options.usage === false) {
return true;
}
return Boolean(options.usage && options.usage[name]);
}
function collectUsageData(ast, options) {
function walk(items, usageData) {
for (var i = 0; i < items.content.length; i++) {
var item = items.content[i];
// go deeper
if (item.content) {
walk(item, usageData);
}
if (item.isElem('script')) {
safe = false;
}
if (item.isElem()) {
usageData.tags[item.elem] = 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;
}
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 (var key in rawData) {
if (shouldFilter(options, key)) {
usageData[key] = Object.keys(rawData[key]);
hasData = true;
}
}
return safe && hasData ? usageData : null;
}

126
web/node_modules/svgo/plugins/moveElemsAttrsToGroup.js generated vendored Normal file
View file

@ -0,0 +1,126 @@
'use strict';
exports.type = 'perItemReverse';
exports.active = true;
exports.description = 'moves elements attributes to the existing group wrapper';
var inheritableAttrs = require('./_collections').inheritableAttrs,
pathElems = require('./_collections.js').pathElems;
/**
* Collapse content's intersected and inheritable
* attributes to the existing group wrapper.
*
* @example
* <g attr1="val1">
* <g attr2="val2">
* text
* </g>
* <circle attr2="val2" attr3="val3"/>
* </g>
*
* <g attr1="val1" attr2="val2">
* <g>
* text
* </g>
* <circle attr3="val3"/>
* </g>
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
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 (!intersection) return false;
}
return true;
}
}),
allPath = item.content.every(function(inner) {
return inner.isElem(pathElems);
});
if (intersected) {
item.content.forEach(function(g) {
for (var name in intersection) {
if (!allPath && !hasClip || name !== 'transform') {
g.removeAttr(name);
if (name === 'transform') {
if (!hasTransform) {
if (item.hasAttr('transform')) {
item.attr('transform').value += ' ' + intersection[name].value;
} else {
item.addAttr(intersection[name]);
}
hasTransform = true;
}
} else {
item.addAttr(intersection[name]);
}
}
}
});
}
}
};
/**
* Intersect inheritable attributes.
*
* @param {Object} a first attrs object
* @param {Object} b second attrs object
*
* @return {Object} intersected attrs object
*/
function intersectInheritableAttrs(a, b) {
var c = {};
for (var n in a) {
if (
b.hasOwnProperty(n) &&
inheritableAttrs.indexOf(n) > -1 &&
a[n].name === b[n].name &&
a[n].value === b[n].value &&
a[n].prefix === b[n].prefix &&
a[n].local === b[n].local
) {
c[n] = a[n];
}
}
if (!Object.keys(c).length) return false;
return c;
}

63
web/node_modules/svgo/plugins/moveGroupAttrsToElems.js generated vendored Normal file
View file

@ -0,0 +1,63 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'moves some group attributes to the content elements';
var collections = require('./_collections.js'),
pathElems = collections.pathElems.concat(['g', 'text']),
referencesProps = collections.referencesProps;
/**
* Move group attrs to the content elements.
*
* @example
* <g transform="scale(2)">
* <path transform="rotate(45)" d="M0,0 L10,20"/>
* <path transform="translate(10, 20)" d="M0,10 L20,30"/>
* </g>
*
* <g>
* <path transform="scale(2) rotate(45)" d="M0,0 L10,20"/>
* <path transform="scale(2) translate(10, 20)" d="M0,10 L20,30"/>
* </g>
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
// move group transform attr to content's pathElems
if (
item.isElem('g') &&
item.hasAttr('transform') &&
!item.isEmpty() &&
!item.someAttr(function(attr) {
return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
}) &&
item.content.every(function(inner) {
return inner.isElem(pathElems) && !inner.hasAttr('id');
})
) {
item.content.forEach(function(inner) {
var attr = item.attr('transform');
if (inner.hasAttr('transform')) {
inner.attr('transform').value = attr.value + ' ' + inner.attr('transform').value;
} else {
inner.addAttr({
'name': attr.name,
'local': attr.local,
'prefix': attr.prefix,
'value': attr.value
});
}
});
item.removeAttr('transform');
}
};

243
web/node_modules/svgo/plugins/prefixIds.js generated vendored Executable file
View file

@ -0,0 +1,243 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.params = {
delim: '__',
prefixIds: true,
prefixClassNames: true,
};
exports.description = 'prefix IDs';
var path = require('path'),
csstree = require('css-tree'),
unquote = require('unquote'),
collections = require('./_collections.js'),
referencesProps = collections.referencesProps,
rxId = /^#(.*)$/, // regular expression for matching an ID + extracing its name
addPrefix = null;
// Escapes a string for being used as ID
var escapeIdentifierName = function(str) {
return str.replace(/[\. ]/g, '_');
};
// Matches an #ID value, captures the ID name
var matchId = function(urlVal) {
var idUrlMatches = urlVal.match(rxId);
if (idUrlMatches === null) {
return false;
}
return idUrlMatches[1];
};
// Matches an url(...) value, captures the URL
var matchUrl = function(val) {
var urlMatches = /url\((.*?)\)/gi.exec(val);
if (urlMatches === null) {
return false;
}
return urlMatches[1];
};
// Checks if attribute is empty
var attrNotEmpty = function(attr) {
return (attr && attr.value && attr.value.length > 0);
};
// prefixes an #ID
var prefixId = function(val) {
var idName = matchId(val);
if (!idName) {
return false;
}
return '#' + addPrefix(idName);
};
// attr.value helper methods
// prefixes a class attribute value
var addPrefixToClassAttr = function(attr) {
if (!attrNotEmpty(attr)) {
return;
}
attr.value = attr.value.split(/\s+/).map(addPrefix).join(' ');
};
// prefixes an ID attribute value
var addPrefixToIdAttr = function(attr) {
if (!attrNotEmpty(attr)) {
return;
}
attr.value = addPrefix(attr.value);
};
// prefixes a href attribute value
var addPrefixToHrefAttr = function(attr) {
if (!attrNotEmpty(attr)) {
return;
}
var idPrefixed = prefixId(attr.value);
if (!idPrefixed) {
return;
}
attr.value = idPrefixed;
};
// prefixes an URL attribute value
var addPrefixToUrlAttr = function(attr) {
if (!attrNotEmpty(attr)) {
return;
}
// url(...) in value
var urlVal = matchUrl(attr.value);
if (!urlVal) {
return;
}
var idPrefixed = prefixId(urlVal);
if (!idPrefixed) {
return;
}
attr.value = 'url(' + idPrefixed + ')';
};
/**
* Prefixes identifiers
*
* @param {Object} node node
* @param {Object} opts plugin params
* @param {Object} extra plugin extra information
*
* @author strarsis <strarsis@gmail.com>
*/
exports.fn = function(node, opts, extra) {
// skip subsequent passes when multipass is used
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 = path.basename(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]);
}
return node;
};

View file

@ -0,0 +1,70 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes attributes of elements that match a css selector';
/**
* Removes attributes of elements that match a css selector.
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @example
* <caption>A selector removing a single attribute</caption>
* plugins:
* - removeAttributesBySelector:
* selector: "[fill='#00ff00']"
* attributes: "fill"
*
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
*
* <rect x="0" y="0" width="100" height="100" stroke="#00ff00"/>
*
* <caption>A selector removing multiple attributes</caption>
* plugins:
* - removeAttributesBySelector:
* selector: "[fill='#00ff00']"
* attributes:
* - fill
* - stroke
*
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
*
* <rect x="0" y="0" width="100" height="100"/>
*
* <caption>Multiple selectors removing attributes</caption>
* plugins:
* - removeAttributesBySelector:
* selectors:
* - selector: "[fill='#00ff00']"
* attributes: "fill"
*
* - selector: "#remove"
* attributes:
* - stroke
* - id
*
* <rect x="0" y="0" width="100" height="100" fill="#00ff00" stroke="#00ff00"/>
*
* <rect x="0" y="0" width="100" height="100"/>
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|MDN CSS Selectors}
*
* @author Bradley Mease
*/
exports.fn = function(item, params) {
var selectors = Array.isArray(params.selectors) ? params.selectors : [params];
selectors.map(function(i) {
if (item.matches(i.selector)) {
item.removeAttr(i.attributes);
}
});
};

150
web/node_modules/svgo/plugins/removeAttrs.js generated vendored Normal file
View file

@ -0,0 +1,150 @@
'use strict';
var DEFAULT_SEPARATOR = ':';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes specified attributes';
exports.params = {
elemSeparator: DEFAULT_SEPARATOR,
preserveCurrentColor: false,
attrs: []
};
/**
* Remove attributes
*
* @param elemSeparator
* format: string
*
* @param preserveCurrentColor
* format: boolean
*
* @param attrs:
*
* format: [ element* : attribute* : value* ]
*
* element : regexp (wrapped into ^...$), single * or omitted > all elements (must be present when value is used)
* attribute : regexp (wrapped into ^...$)
* value : regexp (wrapped into ^...$), single * or omitted > all values
*
* examples:
*
* > basic: remove fill attribute
* ---
* removeAttrs:
* attrs: 'fill'
*
* > remove fill attribute on path element
* ---
* attrs: 'path:fill'
*
* > remove fill attribute on path element where value is none
* ---
* attrs: 'path:fill:none'
*
*
* > remove all fill and stroke attribute
* ---
* attrs:
* - 'fill'
* - 'stroke'
*
* [is same as]
*
* attrs: '(fill|stroke)'
*
* [is same as]
*
* attrs: '*:(fill|stroke)'
*
* [is same as]
*
* attrs: '.*:(fill|stroke)'
*
* [is same as]
*
* attrs: '.*:(fill|stroke):.*'
*
*
* > remove all stroke related attributes
* ----
* attrs: 'stroke.*'
*
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Benny Schudel
*/
exports.fn = function(item, params) {
// wrap into an array if params is not
if (!Array.isArray(params.attrs)) {
params.attrs = [params.attrs];
}
if (item.isElem()) {
var elemSeparator = typeof params.elemSeparator == 'string' ? params.elemSeparator : DEFAULT_SEPARATOR;
var preserveCurrentColor = typeof params.preserveCurrentColor == 'boolean' ? params.preserveCurrentColor : false;
// prepare patterns
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 only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
} else if (pattern.split(elemSeparator).length < 3) {
pattern = [pattern, elemSeparator, '.*'].join('');
}
// 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);
}
}
}
});
}
});
}
};

27
web/node_modules/svgo/plugins/removeComments.js generated vendored Normal file
View file

@ -0,0 +1,27 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes comments';
/**
* Remove comments.
*
* @example
* <!-- Generator: Adobe Illustrator 15.0.0, SVG Export
* Plug-In . SVG Version: 6.00 Build 0) -->
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
if (item.comment && item.comment.charAt(0) !== '!') {
return false;
}
};

32
web/node_modules/svgo/plugins/removeDesc.js generated vendored Normal file
View file

@ -0,0 +1,32 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.params = {
removeAny: true
};
exports.description = 'removes <desc>';
var standardDescs = /^(Created with|Created using)/;
/**
* Removes <desc>.
* Removes only standard editors content or empty elements 'cause it can be used for accessibility.
* Enable parameter 'removeAny' to remove any description.
*
* https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Daniel Wabyick
*/
exports.fn = function(item, params) {
return !item.isElem('desc') || !(params.removeAny || item.isEmpty() ||
standardDescs.test(item.content[0].text));
};

49
web/node_modules/svgo/plugins/removeDimensions.js generated vendored Normal file
View file

@ -0,0 +1,49 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
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
*
* @example
* <svg width="100" height="50" />
*
* <svg viewBox="0 0 100 50" />
*
* @param {Object} item current iteration item
* @return {Boolean} if true, with and height will be filtered out
*
* @author Benny Schudel
*/
exports.fn = function(item) {
if (item.isElem('svg')) {
if (item.hasAttr('viewBox')) {
item.removeAttr('width');
item.removeAttr('height');
} else if (
item.hasAttr('width') &&
item.hasAttr('height') &&
!isNaN(Number(item.attr('width').value)) &&
!isNaN(Number(item.attr('height').value))
) {
item.addAttr({
name: 'viewBox',
value:
'0 0 ' +
Number(item.attr('width').value) +
' ' +
Number(item.attr('height').value),
prefix: '',
local: 'viewBox'
});
item.removeAttr('width');
item.removeAttr('height');
}
}
};

40
web/node_modules/svgo/plugins/removeDoctype.js generated vendored Normal file
View file

@ -0,0 +1,40 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes doctype declaration';
/**
* Remove DOCTYPE declaration.
*
* "Unfortunately the SVG DTDs are a source of so many
* issues that the SVG WG has decided not to write one
* for the upcoming SVG 1.2 standard. In fact SVG WG
* members are even telling people not to use a DOCTYPE
* declaration in SVG 1.0 and 1.1 documents"
* https://jwatt.org/svg/authoring/#doctype-declaration
*
* @example
* <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
* q"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
*
* @example
* <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
* "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [
* <!-- an internal subset can be embedded here -->
* ]>
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
if (item.doctype) {
return false;
}
};

65
web/node_modules/svgo/plugins/removeEditorsNSData.js generated vendored Normal file
View file

@ -0,0 +1,65 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes editors namespaces, elements and attributes';
var editorNamespaces = require('./_collections').editorNamespaces,
prefixes = [];
exports.params = {
additionalNamespaces: []
};
/**
* Remove editors namespaces, elements and attributes.
*
* @example
* <svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd">
* <sodipodi:namedview/>
* <path sodipodi:nodetypes="cccc"/>
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
if (Array.isArray(params.additionalNamespaces)) {
editorNamespaces = editorNamespaces.concat(params.additionalNamespaces);
}
if (item.elem) {
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);
}
});
}
// <* sodipodi:*="">
item.eachAttr(function(attr) {
if (prefixes.indexOf(attr.prefix) > -1) {
item.removeAttr(attr.name);
}
});
// <sodipodi:*>
if (prefixes.indexOf(item.prefix) > -1) {
return false;
}
}
};

80
web/node_modules/svgo/plugins/removeElementsByAttr.js generated vendored Normal file
View file

@ -0,0 +1,80 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes arbitrary elements by ID or className (disabled by default)';
exports.params = {
id: [],
class: []
};
/**
* Remove arbitrary SVG elements by ID or className.
*
* @param id
* examples:
*
* > single: remove element with ID of `elementID`
* ---
* removeElementsByAttr:
* id: 'elementID'
*
* > list: remove multiple elements by ID
* ---
* removeElementsByAttr:
* id:
* - 'elementID'
* - 'anotherID'
*
* @param class
* examples:
*
* > single: remove all elements with class of `elementClass`
* ---
* removeElementsByAttr:
* class: 'elementClass'
*
* > list: remove all elements with class of `elementClass` or `anotherClass`
* ---
* removeElementsByAttr:
* class:
* - 'elementClass'
* - 'anotherClass'
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Eli Dupuis (@elidupuis)
*/
exports.fn = function(item, params) {
var elemId, elemClass;
// wrap params in an array if not already
['id', 'class'].forEach(function(key) {
if (!Array.isArray(params[key])) {
params[key] = [ params[key] ];
}
});
// abort if current item is no an element
if (!item.isElem()) {
return;
}
// remove element if it's `id` matches configured `id` params
elemId = item.attr('id');
if (elemId) {
return params.id.indexOf(elemId.value) === -1;
}
// remove element if it's `class` contains any of the configured `class` params
elemClass = item.attr('class');
if (elemClass) {
var hasClassRegex = new RegExp(params.class.join('|'));
return !hasClassRegex.test(elemClass.value);
}
};

29
web/node_modules/svgo/plugins/removeEmptyAttrs.js generated vendored Normal file
View file

@ -0,0 +1,29 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes empty attributes';
/**
* Remove attributes with empty values.
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
if (item.elem) {
item.eachAttr(function(attr) {
if (attr.value === '') {
item.removeAttr(attr.name);
}
});
}
};

32
web/node_modules/svgo/plugins/removeEmptyContainers.js generated vendored Normal file
View file

@ -0,0 +1,32 @@
'use strict';
exports.type = 'perItemReverse';
exports.active = true;
exports.description = 'removes empty container elements';
var container = require('./_collections').elemsGroups.container;
/**
* Remove empty containers.
*
* @see http://www.w3.org/TR/SVG/intro.html#TermContainerElement
*
* @example
* <defs/>
*
* @example
* <g><marker><a/></marker></g>
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
return !(item.isElem(container) && !item.isElem('svg') && item.isEmpty() &&
(!item.isElem('pattern') || !item.hasAttrLocal('href')));
};

59
web/node_modules/svgo/plugins/removeEmptyText.js generated vendored Normal file
View file

@ -0,0 +1,59 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes empty <text> elements';
exports.params = {
text: true,
tspan: true,
tref: true
};
/**
* Remove empty Text elements.
*
* @see http://www.w3.org/TR/SVG/text.html
*
* @example
* Remove empty text element:
* <text/>
*
* Remove empty tspan element:
* <tspan/>
*
* Remove tref with empty xlink:href attribute:
* <tref xlink:href=""/>
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
// Remove empty text element
if (
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;
};

225
web/node_modules/svgo/plugins/removeHiddenElems.js generated vendored Normal file
View file

@ -0,0 +1,225 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes hidden elements (zero sized, with absent attributes)';
exports.params = {
isHidden: true,
displayNone: true,
opacity0: true,
circleR0: true,
ellipseRX0: true,
ellipseRY0: true,
rectWidth0: true,
rectHeight0: true,
patternWidth0: true,
patternHeight0: true,
imageWidth0: true,
imageHeight0: true,
pathEmptyD: true,
polylineEmptyPoints: true,
polygonEmptyPoints: true
};
var regValidPath = /M\s*(?:[-+]?(?:\d*\.\d+|\d+(?:\.|(?!\.)))([eE][-+]?\d+)?(?!\d)\s*,?\s*){2}\D*\d/i;
/**
* Remove hidden elements with disabled rendering:
* - display="none"
* - opacity="0"
* - circle with zero radius
* - ellipse with zero x-axis or y-axis radius
* - rectangle with zero width or height
* - pattern with zero width or height
* - image with zero width or height
* - path with empty data
* - polyline with empty points
* - polygon with empty points
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function (item, params) {
if (item.elem) {
// Removes hidden elements
// https://www.w3schools.com/cssref/pr_class_visibility.asp
if (
params.isHidden &&
item.hasAttr('visibility', 'hidden')
) return false;
// display="none"
//
// http://www.w3.org/TR/SVG/painting.html#DisplayProperty
// "A value of display: none indicates that the given element
// and its children shall not be rendered directly"
if (
params.displayNone &&
item.hasAttr('display', 'none')
) return false;
// opacity="0"
//
// http://www.w3.org/TR/SVG/masking.html#ObjectAndGroupOpacityProperties
if (
params.opacity0 &&
item.hasAttr('opacity', '0')
) return false;
// Circles with zero radius
//
// http://www.w3.org/TR/SVG/shapes.html#CircleElementRAttribute
// "A value of zero disables rendering of the element"
//
// <circle r="0">
if (
params.circleR0 &&
item.isElem('circle') &&
item.isEmpty() &&
item.hasAttr('r', '0')
) return false;
// Ellipse with zero x-axis radius
//
// http://www.w3.org/TR/SVG/shapes.html#EllipseElementRXAttribute
// "A value of zero disables rendering of the element"
//
// <ellipse rx="0">
if (
params.ellipseRX0 &&
item.isElem('ellipse') &&
item.isEmpty() &&
item.hasAttr('rx', '0')
) return false;
// Ellipse with zero y-axis radius
//
// http://www.w3.org/TR/SVG/shapes.html#EllipseElementRYAttribute
// "A value of zero disables rendering of the element"
//
// <ellipse ry="0">
if (
params.ellipseRY0 &&
item.isElem('ellipse') &&
item.isEmpty() &&
item.hasAttr('ry', '0')
) return false;
// Rectangle with zero width
//
// http://www.w3.org/TR/SVG/shapes.html#RectElementWidthAttribute
// "A value of zero disables rendering of the element"
//
// <rect width="0">
if (
params.rectWidth0 &&
item.isElem('rect') &&
item.isEmpty() &&
item.hasAttr('width', '0')
) return false;
// Rectangle with zero height
//
// http://www.w3.org/TR/SVG/shapes.html#RectElementHeightAttribute
// "A value of zero disables rendering of the element"
//
// <rect height="0">
if (
params.rectHeight0 &&
params.rectWidth0 &&
item.isElem('rect') &&
item.isEmpty() &&
item.hasAttr('height', '0')
) return false;
// Pattern with zero width
//
// http://www.w3.org/TR/SVG/pservers.html#PatternElementWidthAttribute
// "A value of zero disables rendering of the element (i.e., no paint is applied)"
//
// <pattern width="0">
if (
params.patternWidth0 &&
item.isElem('pattern') &&
item.hasAttr('width', '0')
) return false;
// Pattern with zero height
//
// http://www.w3.org/TR/SVG/pservers.html#PatternElementHeightAttribute
// "A value of zero disables rendering of the element (i.e., no paint is applied)"
//
// <pattern height="0">
if (
params.patternHeight0 &&
item.isElem('pattern') &&
item.hasAttr('height', '0')
) return false;
// Image with zero width
//
// http://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
// "A value of zero disables rendering of the element"
//
// <image width="0">
if (
params.imageWidth0 &&
item.isElem('image') &&
item.hasAttr('width', '0')
) return false;
// Image with zero height
//
// http://www.w3.org/TR/SVG/struct.html#ImageElementHeightAttribute
// "A value of zero disables rendering of the element"
//
// <image height="0">
if (
params.imageHeight0 &&
item.isElem('image') &&
item.hasAttr('height', '0')
) return false;
// Path with empty data
//
// http://www.w3.org/TR/SVG/paths.html#DAttribute
//
// <path d=""/>
if (
params.pathEmptyD &&
item.isElem('path') &&
(!item.hasAttr('d') || !regValidPath.test(item.attr('d').value))
) return false;
// Polyline with empty points
//
// http://www.w3.org/TR/SVG/shapes.html#PolylineElementPointsAttribute
//
// <polyline points="">
if (
params.polylineEmptyPoints &&
item.isElem('polyline') &&
!item.hasAttr('points')
) return false;
// Polygon with empty points
//
// http://www.w3.org/TR/SVG/shapes.html#PolygonElementPointsAttribute
//
// <polygon points="">
if (
params.polygonEmptyPoints &&
item.isElem('polygon') &&
!item.hasAttr('points')
) return false;
}
};

23
web/node_modules/svgo/plugins/removeMetadata.js generated vendored Normal file
View file

@ -0,0 +1,23 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes <metadata>';
/**
* Remove <metadata>.
*
* http://www.w3.org/TR/SVG/metadata.html
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
return !item.isElem('metadata');
};

View file

@ -0,0 +1,37 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes non-inheritable groups presentational attributes';
var inheritableAttrs = require('./_collections').inheritableAttrs,
attrsGroups = require('./_collections').attrsGroups,
applyGroups = require('./_collections').presentationNonInheritableGroupAttrs;
/**
* Remove non-inheritable group's "presentation" attributes.
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
if (item.isElem('g')) {
item.eachAttr(function(attr) {
if (
~attrsGroups.presentation.indexOf(attr.name) &&
!~inheritableAttrs.indexOf(attr.name) &&
!~applyGroups.indexOf(attr.name)
) {
item.removeAttr(attr.name);
}
});
}
};

133
web/node_modules/svgo/plugins/removeOffCanvasPaths.js generated vendored Normal file
View file

@ -0,0 +1,133 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes elements that are drawn outside of the viewbox (disabled by default)';
var SVGO = require('../lib/svgo.js'),
_path = require('./_path.js'),
intersects = _path.intersects,
path2js = _path.path2js,
viewBox,
viewBoxJS;
/**
* Remove elements that are drawn outside of the viewbox.
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author JoshyPHP
*/
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;
}
var pathJS = path2js(item);
if (pathJS.length === 2)
{
// Use a closed clone of the path if it's too short for intersects()
pathJS = JSON.parse(JSON.stringify(pathJS));
pathJS.push({ instruction: 'z' });
}
return intersects(viewBoxJS, pathJS);
}
if (item.isElem('svg'))
{
parseViewBox(item);
}
return true;
};
/**
* Test whether given item or any of its ancestors has a transform attribute.
*
* @param {String} path
* @return {Boolean}
*/
function hasTransform(item)
{
return item.hasAttr('transform') || (item.parentNode && hasTransform(item.parentNode));
}
/**
* Parse the viewBox coordinates and compute the JS representation of its path.
*
* @param {Object} svg svg element item
*/
function parseViewBox(svg)
{
var viewBoxData = '';
if (svg.hasAttr('viewBox'))
{
// Remove commas and plus signs, normalize and trim whitespace
viewBoxData = svg.attr('viewBox').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
viewBoxData = viewBoxData.replace(/[,+]|px/g, ' ').replace(/\s+/g, ' ').replace(/^\s*|\s*$/g, '');
// Ensure that the dimensions are 4 values separated by space
var m = /^(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+)$/.exec(viewBoxData);
if (!m)
{
return;
}
// Store the viewBox boundaries
viewBox = {
left: parseFloat(m[1]),
top: parseFloat(m[2]),
right: parseFloat(m[1]) + parseFloat(m[3]),
bottom: parseFloat(m[2]) + parseFloat(m[4])
};
var path = new SVGO().createContentItem({
elem: 'path',
prefix: '',
local: 'path'
});
path.addAttr({
name: 'd',
prefix: '',
local: 'd',
value: 'M' + m[1] + ' ' + m[2] + 'h' + m[3] + 'v' + m[4] + 'H' + m[1] + 'z'
});
viewBoxJS = path2js(path);
}
/**
* Test whether given path has a M instruction with coordinates within the viewBox.
*
* @param {String} path
* @return {Boolean}
*/
function pathMovesWithinViewBox(path)
{
var regexp = /M\s*(-?\d*\.?\d+)(?!\d)\s*(-?\d*\.?\d+)/g, m;
while (null !== (m = regexp.exec(path)))
{
if (m[1] >= viewBox.left && m[1] <= viewBox.right && m[2] >= viewBox.top && m[2] <= viewBox.bottom)
{
return true;
}
}
return false;
}

28
web/node_modules/svgo/plugins/removeRasterImages.js generated vendored Normal file
View file

@ -0,0 +1,28 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes raster images (disabled by default)';
/**
* Remove raster images references in <image>.
*
* @see https://bugs.webkit.org/show_bug.cgi?id=63548
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
if (
item.isElem('image') &&
item.hasAttrLocal('href', /(\.|image\/)(jpg|png|gif)/)
) {
return false;
}
};

23
web/node_modules/svgo/plugins/removeScriptElement.js generated vendored Normal file
View file

@ -0,0 +1,23 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes <script> elements (disabled by default)';
/**
* Remove <script>.
*
* https://www.w3.org/TR/SVG/script.html
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Patrick Klingemann
*/
exports.fn = function(item) {
return !item.isElem('script');
};

23
web/node_modules/svgo/plugins/removeStyleElement.js generated vendored Normal file
View file

@ -0,0 +1,23 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes <style> element (disabled by default)';
/**
* Remove <style>.
*
* http://www.w3.org/TR/SVG/styling.html#StyleElement
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Betsy Dupuis
*/
exports.fn = function(item) {
return !item.isElem('style');
};

23
web/node_modules/svgo/plugins/removeTitle.js generated vendored Normal file
View file

@ -0,0 +1,23 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes <title>';
/**
* Remove <title>.
*
* https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Igor Kalashnikov
*/
exports.fn = function(item) {
return !item.isElem('title');
};

View file

@ -0,0 +1,150 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes unknown elements content and attributes, removes attrs with default values';
exports.params = {
unknownContent: true,
unknownAttrs: true,
defaultAttrs: true,
uselessOverrides: true,
keepDataAttrs: true,
keepAriaAttrs: true,
keepRoleAttr: false
};
var collections = require('./_collections'),
elems = collections.elems,
attrsGroups = collections.attrsGroups,
elemsGroups = collections.elemsGroups,
attrsGroupsDefaults = collections.attrsGroupsDefaults,
attrsInheritable = collections.inheritableAttrs,
applyGroups = collections.presentationNonInheritableGroupAttrs;
// collect and extend all references
for (var elem in elems) {
elem = elems[elem];
if (elem.attrsGroups) {
elem.attrs = elem.attrs || [];
elem.attrsGroups.forEach(function(attrsGroupName) {
elem.attrs = elem.attrs.concat(attrsGroups[attrsGroupName]);
var groupDefaults = attrsGroupsDefaults[attrsGroupName];
if (groupDefaults) {
elem.defaults = elem.defaults || {};
for (var attrName in groupDefaults) {
elem.defaults[attrName] = groupDefaults[attrName];
}
}
});
}
if (elem.contentGroups) {
elem.content = elem.content || [];
elem.contentGroups.forEach(function(contentGroupName) {
elem.content = elem.content.concat(elemsGroups[contentGroupName]);
});
}
}
/**
* Remove unknown elements content and attributes,
* remove attributes with default values.
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
// elems w/o namespace prefix
if (item.isElem() && !item.prefix) {
var elem = item.elem;
// remove unknown element's content
if (
params.unknownContent &&
!item.isEmpty() &&
elems[elem] && // make sure we know of this element before checking its children
elem !== 'foreignObject' // Don't check foreignObject
) {
item.content.forEach(function(content, i) {
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);
}
}
});
}
}
};

109
web/node_modules/svgo/plugins/removeUnusedNS.js generated vendored Normal file
View file

@ -0,0 +1,109 @@
'use strict';
exports.type = 'full';
exports.active = true;
exports.description = 'removes unused namespaces declaration';
/**
* Remove unused namespaces declaration.
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(data) {
var svgElem,
xmlnsCollection = [];
/**
* Remove namespace from collection.
*
* @param {String} ns namescape name
*/
function removeNSfromCollection(ns) {
var pos = xmlnsCollection.indexOf(ns);
// if found - remove ns from the namespaces collection
if (pos > -1) {
xmlnsCollection.splice(pos, 1);
}
}
/**
* Bananas!
*
* @param {Array} items input items
*
* @return {Array} output items
*/
function monkeys(items) {
var i = 0,
length = items.content.length;
while(i < length) {
var item = items.content[i];
if (item.isElem('svg')) {
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);
});
}
return data;
};

53
web/node_modules/svgo/plugins/removeUselessDefs.js generated vendored Normal file
View file

@ -0,0 +1,53 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes elements in <defs> without id';
var nonRendering = require('./_collections').elemsGroups.nonRendering;
/**
* Removes content of defs and properties that aren't rendered directly without ids.
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Lev Solntsev
*/
exports.fn = function(item) {
if (item.isElem('defs')) {
if (item.content) {
item.content = getUsefulItems(item, []);
}
if (item.isEmpty()) return false;
} else if (item.isElem(nonRendering) && !item.hasAttr('id')) {
return false;
}
};
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);
}
});
return usefulItems;
}

View file

@ -0,0 +1,100 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes useless stroke and fill attributes';
exports.params = {
stroke: true,
fill: true,
removeNone: false,
hasStyleOrScript: false
};
var shape = require('./_collections').elemsGroups.shape,
regStrokeProps = /^stroke/,
regFillProps = /^fill-/,
styleOrScript = ['style', 'script'];
/**
* Remove useless stroke and fill attrs.
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item, params) {
if (item.isElem(styleOrScript)) {
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')
)
) {
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;
}
}
};

48
web/node_modules/svgo/plugins/removeViewBox.js generated vendored Normal file
View file

@ -0,0 +1,48 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes viewBox attribute when possible';
var viewBoxElems = ['svg', 'pattern', 'symbol'];
/**
* Remove viewBox attr which coincides with a width/height box.
*
* @see http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
*
* @example
* <svg width="100" height="50" viewBox="0 0 100 50">
*
* <svg width="100" height="50">
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
if (
item.isElem(viewBoxElems) &&
item.hasAttr('viewBox') &&
item.hasAttr('width') &&
item.hasAttr('height')
) {
var nums = item.attr('viewBox').value.split(/[ ,]+/g);
if (
nums[0] === '0' &&
nums[1] === '0' &&
item.attr('width').value.replace(/px$/, '') === nums[2] && // could use parseFloat too
item.attr('height').value.replace(/px$/, '') === nums[3]
) {
item.removeAttr('viewBox');
}
}
};

28
web/node_modules/svgo/plugins/removeXMLNS.js generated vendored Normal file
View file

@ -0,0 +1,28 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'removes xmlns attribute (for inline svg, disabled by default)';
/**
* Remove the xmlns attribute when present.
*
* @example
* <svg viewBox="0 0 100 50" xmlns="http://www.w3.org/2000/svg">
*
* <svg viewBox="0 0 100 50">
*
* @param {Object} item current iteration item
* @return {Boolean} if true, xmlns will be filtered out
*
* @author Ricardo Tomasi
*/
exports.fn = function(item) {
if (item.isElem('svg') && item.hasAttr('xmlns')) {
item.removeAttr('xmlns');
}
};

24
web/node_modules/svgo/plugins/removeXMLProcInst.js generated vendored Normal file
View file

@ -0,0 +1,24 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'removes XML processing instructions';
/**
* Remove XML Processing Instruction.
*
* @example
* <?xml version="1.0" encoding="utf-8"?>
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author Kir Belevich
*/
exports.fn = function(item) {
return !(item.processinginstruction && item.processinginstruction.name === 'xml');
};

168
web/node_modules/svgo/plugins/reusePaths.js generated vendored Normal file
View file

@ -0,0 +1,168 @@
/**
* @license
* The MIT License
*
* Copyright © 20122016 Kir Belevich
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Лицензия MIT
*
* Copyright © 20122016 Кир Белевич
*
* Данная лицензия разрешает лицам, получившим копию
* данного
* программного обеспечения и сопутствующей
* документации
* (в дальнейшем именуемыми «Программное Обеспечение»),
* безвозмездно
* использовать Программное Обеспечение без
* ограничений, включая
* неограниченное право на использование, копирование,
* изменение,
* добавление, публикацию, распространение,
* сублицензирование
* и/или продажу копий Программного Обеспечения, также
* как и лицам,
* которым предоставляется данное Программное
* Обеспечение,
* при соблюдении следующих условий:
*
* Указанное выше уведомление об авторском праве и
* данные условия
* должны быть включены во все копии или значимые части
* данного
* Программного Обеспечения.
*
* ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК
* ЕСТЬ»,
* БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ
* ПОДРАЗУМЕВАЕМЫХ,
* ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ
* ПРИГОДНОСТИ,
* СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И
* ОТСУТСТВИЯ НАРУШЕНИЙ
* ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ
* НЕСУТ
* ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ
* ИЛИ ДРУГИХ
* ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ
* ИНОМУ,
* ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С
* ПРОГРАММНЫМ
* ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО
* ОБЕСПЕЧЕНИЯ
* ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
*/
'use strict';
var JSAPI = require('../lib/svgo/jsAPI');
exports.type = 'full';
exports.active = false;
exports.description = 'Finds <path> elements with the same d, fill, and ' +
'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
* <use> elements referencing a single <path> def.
*
* @author Jacob Howcroft
*/
exports.fn = function(data) {
const seen = new Map();
let count = 0;
const defs = [];
traverse(data, item => {
if (!item.isElem('path') || !item.hasAttr('d')) {
return;
}
const d = item.attr('d').value;
const fill = (item.hasAttr('fill') && item.attr('fill').value) || '';
const stroke = (item.hasAttr('stroke') && item.attr('stroke').value) || '';
const key = d + ';s:' + stroke + ';f:' + fill;
const hasSeen = seen.get(key);
if (!hasSeen) {
seen.set(key, {elem: item, reused: false});
return;
}
if (!hasSeen.reused) {
hasSeen.reused = true;
if (!hasSeen.elem.hasAttr('id')) {
hasSeen.elem.addAttr({name: 'id', local: 'id',
prefix: '', value: 'reuse-' + (count++)});
}
defs.push(hasSeen.elem);
}
item = convertToUse(item, hasSeen.elem.attr('id').value);
});
const defsTag = new JSAPI({
elem: 'defs', prefix: '', local: 'defs', content: [], attrs: []}, data);
data.content[0].spliceContent(0, 0, defsTag);
for (let def of defs) {
// Remove class and style before copying to avoid circular refs in
// JSON.stringify. This is fine because we don't actually want class or
// style information to be copied.
const style = def.style;
const defClass = def.class;
delete def.style;
delete def.class;
const defClone = def.clone();
def.style = style;
def.class = defClass;
defClone.removeAttr('transform');
defsTag.spliceContent(0, 0, defClone);
// Convert the original def to a use so the first usage isn't duplicated.
def = convertToUse(def, defClone.attr('id').value);
def.removeAttr('id');
}
return data;
};
/** */
function convertToUse(item, href) {
item.renameElem('use');
item.removeAttr('d');
item.removeAttr('stroke');
item.removeAttr('fill');
item.addAttr({name: 'xlink:href', local: 'xlink:href',
prefix: 'none', value: '#' + href});
delete item.pathJS;
return item;
}
/** */
function traverse(parent, callback) {
if (parent.isEmpty()) {
return;
}
for (let child of parent.content) {
callback(child);
traverse(child, callback);
}
}

84
web/node_modules/svgo/plugins/sortAttrs.js generated vendored Normal file
View file

@ -0,0 +1,84 @@
'use strict';
exports.type = 'perItem';
exports.active = false;
exports.description = 'sorts element attributes (disabled by default)';
exports.params = {
order: [
'id',
'width', 'height',
'x', 'x1', 'x2',
'y', 'y1', 'y2',
'cx', 'cy', 'r',
'fill', 'stroke', 'marker',
'd', 'points'
]
};
/**
* Sort element attributes for epic readability.
*
* @param {Object} item current iteration item
* @param {Object} params plugin params
*
* @author Nikolay Frantsev
*/
exports.fn = function(item, params) {
var attrs = [],
sorted = {},
orderlen = params.order.length + 1,
xmlnsOrder = params.xmlnsOrder || 'front';
if (item.elem) {
item.eachAttr(function(attr) {
attrs.push(attr);
});
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;
}
var aindex = orderlen;
var bindex = orderlen;
for (var i = 0; i < params.order.length; i++) {
if (a.name == params.order[i]) {
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;
}
};

47
web/node_modules/svgo/plugins/sortDefsChildren.js generated vendored Normal file
View file

@ -0,0 +1,47 @@
'use strict';
exports.type = 'perItem';
exports.active = true;
exports.description = 'Sorts children of <defs> to improve compression';
/**
* Sorts children of defs in order to improve compression.
* Sorted first by frequency then by element name length then by element name (to ensure grouping).
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
*
* @author David Leston
*/
exports.fn = function(item) {
if (item.isElem('defs')) {
if (item.content) {
var frequency = item.content.reduce(function (frequency, child) {
if (child.elem in frequency) {
frequency[child.elem]++;
} 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 true;
}
};