1
0
mirror of https://github.com/svg/svgo.git synced 2025-08-07 15:22:54 +03:00

Add mergeStyles plugin (#1381)

This commit is contained in:
strarsis
2021-03-27 14:59:56 +01:00
committed by GitHub
parent d89d36eace
commit 19c77d2398
15 changed files with 301 additions and 6 deletions

87
plugins/mergeStyles.js Normal file
View File

@@ -0,0 +1,87 @@
'use strict';
const { querySelectorAll, closestByName } = require('../lib/xast.js');
const { getCssStr, setCssStr } = require('../lib/css-tools');
exports.type = 'full';
exports.active = true;
exports.description = 'merge multiple style elements into one';
/**
* Merge multiple style elements into one.
*
* @param {Object} document document element
*
* @author strarsis <strarsis@gmail.com>
*/
exports.fn = function (document) {
// collect <style/>s with valid type attribute (preserve order)
const styleElements = querySelectorAll(document, 'style');
// no <styles/>s, nothing to do
if (styleElements.length === 0) {
return document;
}
const styles = [];
for (const styleElement of styleElements) {
if (
styleElement.attributes.type &&
styleElement.attributes.type !== 'text/css'
) {
// skip <style> with invalid type attribute
continue;
}
if (closestByName(styleElement, 'foreignObject')) {
// skip <foreignObject> content
continue;
}
const cssString = getCssStr(styleElement);
styles.push({
styleElement: styleElement,
mq: styleElement.attributes.media,
cssStr: cssString,
});
}
const collectedStyles = [];
for (let styleNo = 0; styleNo < styles.length; styleNo += 1) {
const style = styles[styleNo];
if (style.mq) {
const wrappedStyles = `@media ${style.mq}{${style.cssStr}}`;
collectedStyles.push(wrappedStyles);
} else {
collectedStyles.push(style.cssStr);
}
// remove all processed style elements except the first one
if (styleNo > 0) {
removeFromParent(style.styleElement);
}
}
const collectedStylesString = collectedStyles.join('');
// combine collected styles in the first style element
const firstStyle = styles[0];
delete firstStyle.styleElement.attributes.media; // remove media mq attribute as CSS media queries are used
if (collectedStylesString.trim().length > 0) {
setCssStr(firstStyle.styleElement, collectedStylesString);
} else {
removeFromParent(firstStyle.styleElement);
}
return document;
};
function removeFromParent(element) {
const parentElement = element.parentNode;
return parentElement.children.splice(
parentElement.children.indexOf(element),
1
);
}