mirror of
https://github.com/svg/svgo.git
synced 2025-04-19 10:22:15 +03:00
- covered with tsdoc - replace another closestByName usage with visitSkip symbol to skip subtree instead of skipping element by ancestor Better review with hidden whitespaces as most code just got bigger indent.
94 lines
2.3 KiB
JavaScript
94 lines
2.3 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* @typedef {import('../lib/types').XastElement} XastElement
|
|
*/
|
|
|
|
const { visitSkip, detachNodeFromParent } = require('../lib/xast.js');
|
|
const JSAPI = require('../lib/svgo/jsAPI.js');
|
|
|
|
exports.name = 'mergeStyles';
|
|
exports.type = 'visitor';
|
|
exports.active = true;
|
|
exports.description = 'merge multiple style elements into one';
|
|
|
|
/**
|
|
* Merge multiple style elements into one.
|
|
*
|
|
* @author strarsis <strarsis@gmail.com>
|
|
*
|
|
* @type {import('../lib/types').Plugin<void>}
|
|
*/
|
|
exports.fn = () => {
|
|
/**
|
|
* @type {null | XastElement}
|
|
*/
|
|
let firstStyleElement = null;
|
|
let collectedStyles = '';
|
|
let styleContentType = 'text';
|
|
|
|
return {
|
|
element: {
|
|
enter: (node, parentNode) => {
|
|
// skip <foreignObject> content
|
|
if (node.name === 'foreignObject') {
|
|
return visitSkip;
|
|
}
|
|
|
|
// collect style elements
|
|
if (node.name !== 'style') {
|
|
return;
|
|
}
|
|
|
|
// skip <style> with invalid type attribute
|
|
if (
|
|
node.attributes.type != null &&
|
|
node.attributes.type !== '' &&
|
|
node.attributes.type !== 'text/css'
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// extract style element content
|
|
let css = '';
|
|
for (const child of node.children) {
|
|
if (child.type === 'text') {
|
|
css += child.value;
|
|
}
|
|
if (child.type === 'cdata') {
|
|
styleContentType = 'cdata';
|
|
css += child.value;
|
|
}
|
|
}
|
|
|
|
// remove empty style elements
|
|
if (css.trim().length === 0) {
|
|
detachNodeFromParent(node, parentNode);
|
|
return;
|
|
}
|
|
|
|
// collect css and wrap with media query if present in attribute
|
|
if (node.attributes.media == null) {
|
|
collectedStyles += css;
|
|
} else {
|
|
collectedStyles += `@media ${node.attributes.media}{${css}}`;
|
|
delete node.attributes.media;
|
|
}
|
|
|
|
// combine collected styles in the first style element
|
|
if (firstStyleElement == null) {
|
|
firstStyleElement = node;
|
|
} else {
|
|
detachNodeFromParent(node, parentNode);
|
|
firstStyleElement.children = [
|
|
new JSAPI(
|
|
{ type: styleContentType, value: collectedStyles },
|
|
firstStyleElement
|
|
),
|
|
];
|
|
}
|
|
},
|
|
},
|
|
};
|
|
};
|