Add inlineStyles plugin (rewrite of localStyles plugin) (#592)
Add inlineStyles plugin
@ -23,6 +23,7 @@ plugins:
|
|||||||
- removeXMLNS
|
- removeXMLNS
|
||||||
- removeEditorsNSData
|
- removeEditorsNSData
|
||||||
- cleanupAttrs
|
- cleanupAttrs
|
||||||
|
- inlineStyles
|
||||||
- minifyStyles
|
- minifyStyles
|
||||||
- convertStyleToAttrs
|
- convertStyleToAttrs
|
||||||
- cleanupIDs
|
- cleanupIDs
|
||||||
|
@ -199,6 +199,114 @@ And of course, writing plugins would not have been so cool without some sugar AP
|
|||||||
* @param {Object} [context] callback context
|
* @param {Object} [context] callback context
|
||||||
* @return {Boolean} false if there are no any attributes
|
* @return {Boolean} false if there are no any attributes
|
||||||
|
|
||||||
|
|
||||||
|
##### querySelectorAll(selectors)
|
||||||
|
* Evaluate a string of CSS selectors against the element and returns matched elements
|
||||||
|
* @param {String} selectors CSS selector(s) string
|
||||||
|
* @return {Array} null if no elements matched
|
||||||
|
|
||||||
|
##### querySelector(selectors)
|
||||||
|
* Evaluate a string of CSS selectors against the element and returns only the first matched element
|
||||||
|
* @param {String} selectors CSS selector(s) string
|
||||||
|
* @return {Array} null if no element matched
|
||||||
|
|
||||||
|
##### matches(selector)
|
||||||
|
* Test if a selector matches a given element
|
||||||
|
* @param {String} selector CSS selector string
|
||||||
|
* @return {Boolean} true if element would be selected by selector string, false if it does not
|
||||||
|
|
||||||
|
|
||||||
|
##### style.getCssText()
|
||||||
|
* Get the textual representation of the declaration block (equivalent to .cssText attribute).
|
||||||
|
* @return {String} Textual representation of the declaration block (empty string for no properties)
|
||||||
|
|
||||||
|
##### style.getPropertyPriority(propertyName)
|
||||||
|
* Return the optional priority, "important".
|
||||||
|
* @param {String} propertyName representing the property name to be checked.
|
||||||
|
* @return {String} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string.
|
||||||
|
|
||||||
|
##### style.getPropertyValue(propertyName)
|
||||||
|
* Return the property value given a property name.
|
||||||
|
* @param {String} propertyName representing the property name to be checked.
|
||||||
|
* @return {String} value containing the value of the property. If not set, returns the empty string.
|
||||||
|
|
||||||
|
##### style.item(index)
|
||||||
|
* Return a property name.
|
||||||
|
* @param {Number} index of the node to be fetched. The index is zero-based.
|
||||||
|
* @return {String} propertyName that is the name of the CSS property at the specified index.
|
||||||
|
|
||||||
|
##### style.getProperties()
|
||||||
|
* Return all properties of the node.
|
||||||
|
* @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value.
|
||||||
|
|
||||||
|
##### style.removeProperty(propertyName)
|
||||||
|
* Remove a property from the CSS declaration block.
|
||||||
|
* @param {String} propertyName representing the property name to be removed.
|
||||||
|
* @return {String} oldValue equal to the value of the CSS property before it was removed.
|
||||||
|
|
||||||
|
##### style.setProperty(propertyName, value, priority)
|
||||||
|
* Modify an existing CSS property or creates a new CSS property in the declaration block.
|
||||||
|
* @param {String} propertyName representing the CSS property name to be modified.
|
||||||
|
* @param {String} [value] containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter.
|
||||||
|
* @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
|
||||||
|
* @return {undefined}
|
||||||
|
|
||||||
|
|
||||||
|
##### css-tools.flattenToSelectors(cssAst)
|
||||||
|
* Flatten a CSS AST to a selectors list.
|
||||||
|
* @param {Object} CSS AST to flatten
|
||||||
|
* @return {Array} selectors
|
||||||
|
|
||||||
|
##### css-tools.filterByMqs(selectors, useMqs)
|
||||||
|
* Filter selectors by Media Query.
|
||||||
|
* @param {Array} Selectors to filter
|
||||||
|
* @param {Array} Strings of media queries that should pass (<name> <expression>)
|
||||||
|
* @return {Array} Filtered selectors that match the passed media queries
|
||||||
|
|
||||||
|
##### css-tools.filterByPseudos(selectors, useMqs)
|
||||||
|
* Filter selectors by the pseudo-elements and/or -classes they contain.
|
||||||
|
* @param {Array} Selectors to filter
|
||||||
|
* @param {Array} Strings of single or sequence of pseudo-elements and/or -classes that should pass
|
||||||
|
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
|
||||||
|
|
||||||
|
##### css-tools.cleanPseudos(selectors)
|
||||||
|
* Remove pseudo-elements and/or -classes from the selectors for proper matching.
|
||||||
|
* @param {Array} Selectors to clean
|
||||||
|
* @return {Array} Selectors without pseudo-elements and/or -classes
|
||||||
|
|
||||||
|
##### css-tools.compareSpecificity(aSpecificity, bSpecificity)
|
||||||
|
* Compare two selector specificities.
|
||||||
|
* @param {Array} Specificity of selector A
|
||||||
|
* @param {Array} Specificity of selector B
|
||||||
|
* @return {Number} Score of selector specificity A compared to selector specificity B
|
||||||
|
|
||||||
|
##### css-tools.compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode)
|
||||||
|
* Compare two simple selectors.
|
||||||
|
* @param {Object} Simple selector A
|
||||||
|
* @param {Object} Simple selector B
|
||||||
|
* @return {Number} Score of selector A compared to selector B
|
||||||
|
|
||||||
|
##### css-tools.sortSelectors(selectors)
|
||||||
|
* Sort selectors stably by their specificity.
|
||||||
|
* @param {Array} Selectors to be sorted
|
||||||
|
* @return {Array} Stable sorted selectors
|
||||||
|
|
||||||
|
##### css-tools.csstreeToStyleDeclaration(declaration)
|
||||||
|
* Convert a css-tree AST style declaration to CSSStyleDeclaration property.
|
||||||
|
* @param {Object} css-tree style declaration
|
||||||
|
* @return {Object} CSSStyleDeclaration property
|
||||||
|
|
||||||
|
##### css-tools.getCssStr(elem)
|
||||||
|
* Gets the CSS string of a style element
|
||||||
|
* @param {Object} element style element
|
||||||
|
* @return {String|Array} CSS string or empty array if no styles are set
|
||||||
|
|
||||||
|
##### css-tools.csstreeToStyleDeclaration(elem, css)
|
||||||
|
* @param {Object} element style element
|
||||||
|
* @param {String} CSS string to be set
|
||||||
|
* @return {Object} reference to field with CSS
|
||||||
|
|
||||||
|
|
||||||
#### 3.3 tests
|
#### 3.3 tests
|
||||||
|
|
||||||
There is nothing easier than testing your plugin:
|
There is nothing easier than testing your plugin:
|
||||||
|
222
lib/css-tools.js
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var csstree = require('css-tree'),
|
||||||
|
List = csstree.List,
|
||||||
|
stable = require('stable'),
|
||||||
|
specificity = require('csso/lib/restructure/prepare/specificity');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flatten a CSS AST to a selectors list.
|
||||||
|
*
|
||||||
|
* @param {Object} cssAst css-tree AST to flatten
|
||||||
|
* @return {Array} selectors
|
||||||
|
*/
|
||||||
|
function flattenToSelectors(cssAst) {
|
||||||
|
var selectors = [];
|
||||||
|
|
||||||
|
csstree.walkRules(cssAst, function(node) {
|
||||||
|
if (node.type !== 'Rule') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var atrule = this.atrule;
|
||||||
|
var rule = node;
|
||||||
|
|
||||||
|
node.selector.children.each(function(selectorNode, selectorItem) {
|
||||||
|
var selector = {
|
||||||
|
item: selectorItem,
|
||||||
|
atrule: atrule,
|
||||||
|
rule: rule,
|
||||||
|
pseudos: []
|
||||||
|
};
|
||||||
|
|
||||||
|
selectorNode.children.each(function(selectorChildNode, selectorChildItem, selectorChildList) {
|
||||||
|
if (selectorChildNode.type === 'PseudoClassSelector' ||
|
||||||
|
selectorChildNode.type === 'PseudoElementSelector') {
|
||||||
|
selector.pseudos.push({
|
||||||
|
item: selectorChildItem,
|
||||||
|
list: selectorChildList
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
selectors.push(selector);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return selectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter selectors by Media Query.
|
||||||
|
*
|
||||||
|
* @param {Array} selectors to filter
|
||||||
|
* @param {Array} useMqs Array with strings of media queries that should pass (<name> <expression>)
|
||||||
|
* @return {Array} Filtered selectors that match the passed media queries
|
||||||
|
*/
|
||||||
|
function filterByMqs(selectors, useMqs) {
|
||||||
|
return selectors.filter(function(selector) {
|
||||||
|
if (selector.atrule === null) {
|
||||||
|
return ~useMqs.indexOf('');
|
||||||
|
}
|
||||||
|
|
||||||
|
var mqName = selector.atrule.name;
|
||||||
|
var mqStr = mqName;
|
||||||
|
if (selector.atrule.expression &&
|
||||||
|
selector.atrule.expression.children.first().type === 'MediaQueryList') {
|
||||||
|
var mqExpr = csstree.translate(selector.atrule.expression);
|
||||||
|
mqStr = [mqName, mqExpr].join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ~useMqs.indexOf(mqStr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter selectors by the pseudo-elements and/or -classes they contain.
|
||||||
|
*
|
||||||
|
* @param {Array} selectors to filter
|
||||||
|
* @param {Array} usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass
|
||||||
|
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
|
||||||
|
*/
|
||||||
|
function filterByPseudos(selectors, usePseudos) {
|
||||||
|
return selectors.filter(function(selector) {
|
||||||
|
var pseudoSelectorsStr = csstree.translate({
|
||||||
|
type: 'Selector',
|
||||||
|
children: new List().fromArray(selector.pseudos.map(function(pseudo) {
|
||||||
|
return pseudo.item.data;
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
return ~usePseudos.indexOf(pseudoSelectorsStr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove pseudo-elements and/or -classes from the selectors for proper matching.
|
||||||
|
*
|
||||||
|
* @param {Array} selectors to clean
|
||||||
|
* @return {Array} Selectors without pseudo-elements and/or -classes
|
||||||
|
*/
|
||||||
|
function cleanPseudos(selectors) {
|
||||||
|
selectors.forEach(function(selector) {
|
||||||
|
selector.pseudos.forEach(function(pseudo) {
|
||||||
|
pseudo.list.remove(pseudo.item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two selector specificities.
|
||||||
|
* extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
|
||||||
|
*
|
||||||
|
* @param {Array} aSpecificity Specificity of selector A
|
||||||
|
* @param {Array} bSpecificity Specificity of selector B
|
||||||
|
* @return {Number} Score of selector specificity A compared to selector specificity B
|
||||||
|
*/
|
||||||
|
function compareSpecificity(aSpecificity, bSpecificity) {
|
||||||
|
for (var i = 0; i < 4; i += 1) {
|
||||||
|
if (aSpecificity[i] < bSpecificity[i]) {
|
||||||
|
return -1;
|
||||||
|
} else if (aSpecificity[i] > bSpecificity[i]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare two simple selectors.
|
||||||
|
*
|
||||||
|
* @param {Object} aSimpleSelectorNode Simple selector A
|
||||||
|
* @param {Object} bSimpleSelectorNode Simple selector B
|
||||||
|
* @return {Number} Score of selector A compared to selector B
|
||||||
|
*/
|
||||||
|
function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) {
|
||||||
|
var aSpecificity = specificity(aSimpleSelectorNode),
|
||||||
|
bSpecificity = specificity(bSimpleSelectorNode);
|
||||||
|
return compareSpecificity(aSpecificity, bSpecificity);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bySelectorSpecificity(selectorA, selectorB) {
|
||||||
|
return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort selectors stably by their specificity.
|
||||||
|
*
|
||||||
|
* @param {Array} selectors to be sorted
|
||||||
|
* @return {Array} Stable sorted selectors
|
||||||
|
*/
|
||||||
|
function sortSelectors(selectors) {
|
||||||
|
return stable(selectors, _bySelectorSpecificity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a css-tree AST style declaration to CSSStyleDeclaration property.
|
||||||
|
*
|
||||||
|
* @param {Object} declaration css-tree style declaration
|
||||||
|
* @return {Object} CSSStyleDeclaration property
|
||||||
|
*/
|
||||||
|
function csstreeToStyleDeclaration(declaration) {
|
||||||
|
var propertyName = declaration.property,
|
||||||
|
propertyValue = csstree.translate(declaration.value),
|
||||||
|
propertyPriority = (declaration.important ? 'important' : '');
|
||||||
|
return {
|
||||||
|
name: propertyName,
|
||||||
|
value: propertyValue,
|
||||||
|
priority: propertyPriority
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the CSS string of a style element
|
||||||
|
*
|
||||||
|
* @param {Object} element style element
|
||||||
|
* @return {String|Array} CSS string or empty array if no styles are set
|
||||||
|
*/
|
||||||
|
function getCssStr(elem) {
|
||||||
|
return elem.content[0].text || elem.content[0].cdata || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the CSS string of a style element
|
||||||
|
*
|
||||||
|
* @param {Object} element style element
|
||||||
|
* @param {String} CSS string to be set
|
||||||
|
* @return {Object} reference to field with CSS
|
||||||
|
*/
|
||||||
|
function setCssStr(elem, css) {
|
||||||
|
// in case of cdata field
|
||||||
|
if(elem.content[0].cdata) {
|
||||||
|
elem.content[0].cdata = css;
|
||||||
|
return elem.content[0].cdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case of text field + if nothing was set yet
|
||||||
|
elem.content[0].text = css;
|
||||||
|
return elem.content[0].text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports.flattenToSelectors = flattenToSelectors;
|
||||||
|
|
||||||
|
module.exports.filterByMqs = filterByMqs;
|
||||||
|
module.exports.filterByPseudos = filterByPseudos;
|
||||||
|
module.exports.cleanPseudos = cleanPseudos;
|
||||||
|
|
||||||
|
module.exports.compareSpecificity = compareSpecificity;
|
||||||
|
module.exports.compareSimpleSelectorNode = compareSimpleSelectorNode;
|
||||||
|
|
||||||
|
module.exports.sortSelectors = sortSelectors;
|
||||||
|
|
||||||
|
module.exports.csstreeToStyleDeclaration = csstreeToStyleDeclaration;
|
||||||
|
|
||||||
|
module.exports.getCssStr = getCssStr;
|
||||||
|
module.exports.setCssStr = setCssStr;
|
116
lib/svgo/css-class-list.js
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var values = require('object.values');
|
||||||
|
if (!Object.values) {
|
||||||
|
values.shim();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var CSSClassList = function(node) {
|
||||||
|
this.parentNode = node;
|
||||||
|
this.classNames = new Set();
|
||||||
|
this.classAttr = null;
|
||||||
|
//this.classValue = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CSSClassList.prototype.hasClass = function() {
|
||||||
|
this.classAttr = { // empty class attr
|
||||||
|
'name': 'class',
|
||||||
|
'value': null
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addClassHandler();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// attr.class
|
||||||
|
|
||||||
|
CSSClassList.prototype.addClassHandler = function() {
|
||||||
|
|
||||||
|
Object.defineProperty(this.parentNode.attrs, 'class', {
|
||||||
|
get: this.getClassAttr.bind(this),
|
||||||
|
set: this.setClassAttr.bind(this),
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addClassValueHandler();
|
||||||
|
};
|
||||||
|
|
||||||
|
// attr.class.value
|
||||||
|
|
||||||
|
CSSClassList.prototype.addClassValueHandler = function() {
|
||||||
|
|
||||||
|
Object.defineProperty(this.classAttr, 'value', {
|
||||||
|
get: this.getClassValue.bind(this),
|
||||||
|
set: this.setClassValue.bind(this),
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype.getClassAttr = function() {
|
||||||
|
return this.classAttr;
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype.setClassAttr = function(newClassAttr) {
|
||||||
|
this.setClassValue(newClassAttr.value); // must before applying value handler!
|
||||||
|
|
||||||
|
this.classAttr = newClassAttr;
|
||||||
|
this.addClassValueHandler();
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype.getClassValue = function() {
|
||||||
|
var arrClassNames = Array.from(this.classNames);
|
||||||
|
return arrClassNames.join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype.setClassValue = function(newValue) {
|
||||||
|
if(typeof newValue === 'undefined') {
|
||||||
|
this.classNames.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var arrClassNames = newValue.split(' ');
|
||||||
|
this.classNames = new Set(arrClassNames);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CSSClassList.prototype.add = function(/* variadic */) {
|
||||||
|
this.hasClass();
|
||||||
|
Object.values(arguments).forEach(this._addSingle.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype._addSingle = function(className) {
|
||||||
|
this.classNames.add(className);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CSSClassList.prototype.remove = function(/* variadic */) {
|
||||||
|
this.hasClass();
|
||||||
|
Object.values(arguments).forEach(this._removeSingle.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype._removeSingle = function(className) {
|
||||||
|
this.classNames.delete(className);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CSSClassList.prototype.item = function(index) {
|
||||||
|
var arrClassNames = Array.from(this.classNames);
|
||||||
|
return arrClassNames[index];
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype.toggle = function(className, force) {
|
||||||
|
if(this.contains(className) || force === false) {
|
||||||
|
this.classNames.delete(className);
|
||||||
|
}
|
||||||
|
this.classNames.add(className);
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSClassList.prototype.contains = function(className) {
|
||||||
|
return this.classNames.has(className);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = CSSClassList;
|
53
lib/svgo/css-select-adapter.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var baseCssAdapter = require('css-select-base-adapter');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOMUtils API for SVGO AST (used by css-select)
|
||||||
|
*/
|
||||||
|
var svgoCssSelectAdapterMin = {
|
||||||
|
|
||||||
|
// is the node a tag?
|
||||||
|
// isTag: ( node:Node ) => isTag:Boolean
|
||||||
|
isTag: function(node) {
|
||||||
|
return node.isElem();
|
||||||
|
},
|
||||||
|
|
||||||
|
// get the parent of the node
|
||||||
|
// getParent: ( node:Node ) => parentNode:Node
|
||||||
|
// returns null when no parent exists
|
||||||
|
getParent: function(node) {
|
||||||
|
return node.parentNode || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// get the node's children
|
||||||
|
// getChildren: ( node:Node ) => children:[Node]
|
||||||
|
getChildren: function(node) {
|
||||||
|
return node.content || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
// get the name of the tag
|
||||||
|
// getName: ( elem:ElementNode ) => tagName:String
|
||||||
|
getName: function(elemAst) {
|
||||||
|
return elemAst.elem;
|
||||||
|
},
|
||||||
|
|
||||||
|
// get the text content of the node, and its children if it has any
|
||||||
|
// getText: ( node:Node ) => text:String
|
||||||
|
// returns empty string when there is no text
|
||||||
|
getText: function(node) {
|
||||||
|
return node.content[0].text || node.content[0].cdata || '';
|
||||||
|
},
|
||||||
|
|
||||||
|
// get the attribute value
|
||||||
|
// getAttributeValue: ( elem:ElementNode, name:String ) => value:String
|
||||||
|
// returns null when attribute doesn't exist
|
||||||
|
getAttributeValue: function(elem, name) {
|
||||||
|
return elem.hasAttr(name) ? elem.attr(name).value : null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// use base adapter for default implementation
|
||||||
|
var svgoCssSelectAdapter = baseCssAdapter(svgoCssSelectAdapterMin);
|
||||||
|
|
||||||
|
module.exports = svgoCssSelectAdapter;
|
257
lib/svgo/css-style-declaration.js
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var csstree = require('css-tree'),
|
||||||
|
csstools = require('../css-tools');
|
||||||
|
|
||||||
|
|
||||||
|
var CSSStyleDeclaration = function(node) {
|
||||||
|
this.parentNode = node;
|
||||||
|
|
||||||
|
this.properties = new Map();
|
||||||
|
this.hasSynced = false;
|
||||||
|
|
||||||
|
this.styleAttr = null;
|
||||||
|
this.styleValue = null;
|
||||||
|
|
||||||
|
this.parseError = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.hasStyle = function() {
|
||||||
|
this.styleAttr = { // empty style attr
|
||||||
|
'name': 'style',
|
||||||
|
'value': null
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addStyleHandler();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// attr.style
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.addStyleHandler = function() {
|
||||||
|
|
||||||
|
Object.defineProperty(this.parentNode.attrs, 'style', {
|
||||||
|
get: this.getStyleAttr.bind(this),
|
||||||
|
set: this.setStyleAttr.bind(this),
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addStyleValueHandler();
|
||||||
|
};
|
||||||
|
|
||||||
|
// attr.style.value
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.addStyleValueHandler = function() {
|
||||||
|
|
||||||
|
Object.defineProperty(this.styleAttr, 'value', {
|
||||||
|
get: this.getStyleValue.bind(this),
|
||||||
|
set: this.setStyleValue.bind(this),
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.getStyleAttr = function() {
|
||||||
|
return this.styleAttr;
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.setStyleAttr = function(newStyleAttr) {
|
||||||
|
this.setStyleValue(newStyleAttr.value); // must before applying value handler!
|
||||||
|
|
||||||
|
this.styleAttr = newStyleAttr;
|
||||||
|
this.addStyleValueHandler();
|
||||||
|
this.hasSynced = false; // raw css changed
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.getStyleValue = function() {
|
||||||
|
return this.getCssText();
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype.setStyleValue = function(newValue) {
|
||||||
|
this.properties.clear(); // reset all existing properties
|
||||||
|
this.styleValue = newValue;
|
||||||
|
this.hasSynced = false; // raw css changed
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype._loadCssText = function() {
|
||||||
|
if (this.hasSynced) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.hasSynced = true; // must be set here to prevent loop in setProperty(...)
|
||||||
|
|
||||||
|
if (!this.styleValue || this.styleValue.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var inlineCssStr = this.styleValue;
|
||||||
|
|
||||||
|
var declarations = {};
|
||||||
|
try {
|
||||||
|
declarations = csstree.parse(inlineCssStr, {
|
||||||
|
context: 'declarationList',
|
||||||
|
parseValue: false
|
||||||
|
});
|
||||||
|
} catch (parseError) {
|
||||||
|
this.parseError = parseError;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.parseError = false;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
declarations.children.each(function(declaration) {
|
||||||
|
var styleDeclaration = csstools.csstreeToStyleDeclaration(declaration);
|
||||||
|
self.setProperty(styleDeclaration.name, styleDeclaration.value, styleDeclaration.priority);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// only reads from properties
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the textual representation of the declaration block (equivalent to .cssText attribute).
|
||||||
|
*
|
||||||
|
* @return {String} Textual representation of the declaration block (empty string for no properties)
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.getCssText = function() {
|
||||||
|
var properties = this.getProperties();
|
||||||
|
|
||||||
|
if (this.parseError) {
|
||||||
|
// in case of a parse error, pass through original styles
|
||||||
|
return this.styleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cssText = [];
|
||||||
|
properties.forEach(function(property, propertyName) {
|
||||||
|
var strImportant = property.priority === 'important' ? '!important' : '';
|
||||||
|
cssText.push(propertyName.trim() + ':' + property.value.trim() + strImportant);
|
||||||
|
});
|
||||||
|
return cssText.join(';');
|
||||||
|
};
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype._handleParseError = function() {
|
||||||
|
if (this.parseError) {
|
||||||
|
console.warn('Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr(\'style\').value. Error details: ' + this.parseError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CSSStyleDeclaration.prototype._getProperty = function(propertyName) {
|
||||||
|
if(typeof propertyName === 'undefined') {
|
||||||
|
throw Error('1 argument required, but only 0 present.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = this.getProperties();
|
||||||
|
this._handleParseError();
|
||||||
|
|
||||||
|
var property = properties.get(propertyName.trim());
|
||||||
|
return property;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the optional priority, "important".
|
||||||
|
*
|
||||||
|
* @param {String} propertyName representing the property name to be checked.
|
||||||
|
* @return {String} priority that represents the priority (e.g. "important") if one exists. If none exists, returns the empty string.
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.getPropertyPriority = function(propertyName) {
|
||||||
|
var property = this._getProperty(propertyName);
|
||||||
|
return property ? property.priority : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the property value given a property name.
|
||||||
|
*
|
||||||
|
* @param {String} propertyName representing the property name to be checked.
|
||||||
|
* @return {String} value containing the value of the property. If not set, returns the empty string.
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.getPropertyValue = function(propertyName) {
|
||||||
|
var property = this._getProperty(propertyName);
|
||||||
|
return property ? property.value : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a property name.
|
||||||
|
*
|
||||||
|
* @param {Number} index of the node to be fetched. The index is zero-based.
|
||||||
|
* @return {String} propertyName that is the name of the CSS property at the specified index.
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.item = function(index) {
|
||||||
|
if(typeof index === 'undefined') {
|
||||||
|
throw Error('1 argument required, but only 0 present.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = this.getProperties();
|
||||||
|
this._handleParseError();
|
||||||
|
|
||||||
|
return Array.from(properties.keys())[index];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all properties of the node.
|
||||||
|
*
|
||||||
|
* @return {Map} properties that is a Map with propertyName as key and property (propertyValue + propertyPriority) as value.
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.getProperties = function() {
|
||||||
|
this._loadCssText();
|
||||||
|
return this.properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// writes to properties
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a property from the CSS declaration block.
|
||||||
|
*
|
||||||
|
* @param {String} propertyName representing the property name to be removed.
|
||||||
|
* @return {String} oldValue equal to the value of the CSS property before it was removed.
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.removeProperty = function(propertyName) {
|
||||||
|
if(typeof propertyName === 'undefined') {
|
||||||
|
throw Error('1 argument required, but only 0 present.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasStyle();
|
||||||
|
|
||||||
|
var properties = this.getProperties();
|
||||||
|
this._handleParseError();
|
||||||
|
|
||||||
|
var oldValue = this.getPropertyValue(propertyName);
|
||||||
|
properties.delete(propertyName.trim());
|
||||||
|
return oldValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify an existing CSS property or creates a new CSS property in the declaration block.
|
||||||
|
*
|
||||||
|
* @param {String} propertyName representing the CSS property name to be modified.
|
||||||
|
* @param {String} [value] containing the new property value. If not specified, treated as the empty string. value must not contain "!important" -- that should be set using the priority parameter.
|
||||||
|
* @param {String} [priority] allowing the "important" CSS priority to be set. If not specified, treated as the empty string.
|
||||||
|
* @return {undefined}
|
||||||
|
*/
|
||||||
|
CSSStyleDeclaration.prototype.setProperty = function(propertyName, value, priority) {
|
||||||
|
if(typeof propertyName === 'undefined') {
|
||||||
|
throw Error('propertyName argument required, but only not present.');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasStyle();
|
||||||
|
|
||||||
|
var properties = this.getProperties();
|
||||||
|
this._handleParseError();
|
||||||
|
|
||||||
|
var property = {
|
||||||
|
value: value.trim(),
|
||||||
|
priority: priority.trim()
|
||||||
|
};
|
||||||
|
properties.set(propertyName.trim(), property);
|
||||||
|
|
||||||
|
return property;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = CSSStyleDeclaration;
|
@ -1,5 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var cssSelect = require('css-select');
|
||||||
|
|
||||||
|
var svgoCssSelectAdapter = require('./css-select-adapter');
|
||||||
|
var cssSelectOpts = {
|
||||||
|
xmlMode: true,
|
||||||
|
adapter: svgoCssSelectAdapter
|
||||||
|
};
|
||||||
|
|
||||||
var JSAPI = module.exports = function(data, parentNode) {
|
var JSAPI = module.exports = function(data, parentNode) {
|
||||||
Object.assign(this, data);
|
Object.assign(this, data);
|
||||||
if (parentNode) {
|
if (parentNode) {
|
||||||
@ -252,6 +260,14 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
this.attrs = this.attrs || {};
|
this.attrs = this.attrs || {};
|
||||||
this.attrs[attr.name] = attr;
|
this.attrs[attr.name] = attr;
|
||||||
|
|
||||||
|
if(attr.name === 'class') { // newly added class attribute
|
||||||
|
this.class.hasClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attr.name === 'style') { // newly added style attribute
|
||||||
|
this.style.hasStyle();
|
||||||
|
}
|
||||||
|
|
||||||
return this.attrs[attr.name];
|
return this.attrs[attr.name];
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -293,3 +309,41 @@ JSAPI.prototype.renameElem = function(name) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a string of CSS selectors against the element and returns matched elements.
|
||||||
|
*
|
||||||
|
* @param {String} selectors CSS selector(s) string
|
||||||
|
* @return {Array} null if no elements matched
|
||||||
|
*/
|
||||||
|
JSAPI.prototype.querySelectorAll = function(selectors) {
|
||||||
|
|
||||||
|
var matchedEls = cssSelect(selectors, this, cssSelectOpts);
|
||||||
|
|
||||||
|
return matchedEls.length > 0 ? matchedEls : null;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a string of CSS selectors against the element and returns only the first matched element.
|
||||||
|
*
|
||||||
|
* @param {String} selectors CSS selector(s) string
|
||||||
|
* @return {Array} null if no element matched
|
||||||
|
*/
|
||||||
|
JSAPI.prototype.querySelector = function(selectors) {
|
||||||
|
|
||||||
|
return cssSelect.selectOne(selectors, this, cssSelectOpts);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a selector matches a given element.
|
||||||
|
*
|
||||||
|
* @param {String} selector CSS selector string
|
||||||
|
* @return {Boolean} true if element would be selected by selector string, false if it does not
|
||||||
|
*/
|
||||||
|
JSAPI.prototype.matches = function(selector) {
|
||||||
|
|
||||||
|
return cssSelect.is(this, selector, cssSelectOpts);
|
||||||
|
|
||||||
|
};
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
var SAX = require('sax'),
|
var SAX = require('sax'),
|
||||||
JSAPI = require('./jsAPI.js'),
|
JSAPI = require('./jsAPI.js'),
|
||||||
|
CSSClassList = require('./css-class-list'),
|
||||||
|
CSSStyleDeclaration = require('./css-style-declaration'),
|
||||||
entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^\']+)'|"([^\"]+)")\s*>/g;
|
entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^\']+)'|"([^\"]+)")\s*>/g;
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
@ -87,11 +89,23 @@ module.exports = function(data, callback) {
|
|||||||
prefix: data.prefix,
|
prefix: data.prefix,
|
||||||
local: data.local
|
local: data.local
|
||||||
};
|
};
|
||||||
|
elem.class = new CSSClassList(elem);
|
||||||
|
elem.style = new CSSStyleDeclaration(elem);
|
||||||
|
|
||||||
if (Object.keys(data.attributes).length) {
|
if (Object.keys(data.attributes).length) {
|
||||||
elem.attrs = {};
|
elem.attrs = {};
|
||||||
|
|
||||||
|
|
||||||
for (var name in data.attributes) {
|
for (var name in data.attributes) {
|
||||||
|
|
||||||
|
if (name === 'class') { // has class attribute
|
||||||
|
elem.class.hasClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'style') { // has style attribute
|
||||||
|
elem.style.hasStyle();
|
||||||
|
}
|
||||||
|
|
||||||
elem.attrs[name] = {
|
elem.attrs[name] = {
|
||||||
name: name,
|
name: name,
|
||||||
value: data.attributes[name].value,
|
value: data.attributes[name].value,
|
||||||
|
14
package.json
@ -50,20 +50,26 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"coa": "~1.0.1",
|
"coa": "~1.0.1",
|
||||||
"colors": "~1.1.2",
|
"colors": "~1.1.2",
|
||||||
"csso": "~2.3.1",
|
"css-select": "^1.3.0-rc0",
|
||||||
|
"css-select-base-adapter": "^0.1.0",
|
||||||
|
"css-tree": "1.0.0-alpha22",
|
||||||
|
"csso": "^3.0.1",
|
||||||
"js-yaml": "~3.7.0",
|
"js-yaml": "~3.7.0",
|
||||||
"mkdirp": "~0.5.1",
|
"mkdirp": "~0.5.1",
|
||||||
|
"object.values": "^1.0.4",
|
||||||
"sax": "~1.2.1",
|
"sax": "~1.2.1",
|
||||||
|
"stable": "^0.1.5",
|
||||||
|
"whet.extend": "~0.9.9",
|
||||||
"util.promisify": "~1.0.0"
|
"util.promisify": "~1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"coveralls": "~2.11.14",
|
||||||
"fs-extra": "~4.0.1",
|
"fs-extra": "~4.0.1",
|
||||||
"mocha": "~3.2.0",
|
|
||||||
"should": "11.2.0",
|
|
||||||
"istanbul": "~0.4.5",
|
"istanbul": "~0.4.5",
|
||||||
|
"mocha": "~3.2.0",
|
||||||
"mocha-istanbul": "~0.3.0",
|
"mocha-istanbul": "~0.3.0",
|
||||||
"mock-stdin": "~0.3.1",
|
"mock-stdin": "~0.3.1",
|
||||||
"coveralls": "~2.11.14"
|
"should": "11.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0.0"
|
"node": ">=4.0.0"
|
||||||
|
236
plugins/inlineStyles.js
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
'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()) {
|
||||||
|
// skip empty <style/>s
|
||||||
|
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.translate(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.walkDeclarations(selector.rule, 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.selector.children.remove(selector.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (opts.removeMatchedSelectors) {
|
||||||
|
// clean up matched class + ID attribute values
|
||||||
|
for (selector of sortedSelectors) {
|
||||||
|
if(!selector.selectedEls) {
|
||||||
|
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 elements
|
||||||
|
for (var style of styles) {
|
||||||
|
csstree.walkRules(style.cssAst, 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.selector.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.translate(style.cssAst));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return document;
|
||||||
|
};
|
9
test/plugins/inlineStyles.01.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" class="st0"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" class="st0"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 264 B |
12
test/plugins/inlineStyles.02.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.st0{fill:blue;}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="st0"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 320 B |
24
test/plugins/inlineStyles.03.svg
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="dark" viewBox="0 0 258.12 225.88">
|
||||||
|
<!-- for https://github.com/svg/svgo/pull/592#issuecomment-266327016 -->
|
||||||
|
<style>
|
||||||
|
.cls-7 {
|
||||||
|
only-cls-7: 1;
|
||||||
|
}
|
||||||
|
.cls-7,
|
||||||
|
.cls-8 {
|
||||||
|
cls-7-and-8: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<path class="cls-7"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="dark" viewBox="0 0 258.12 225.88">
|
||||||
|
<!--for https://github.com/svg/svgo/pull/592#issuecomment-266327016-->
|
||||||
|
<style>
|
||||||
|
.cls-8{cls-7-and-8: 1}
|
||||||
|
</style>
|
||||||
|
<path style="cls-7-and-8:1;only-cls-7:1"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 602 B |
13
test/plugins/inlineStyles.04.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.st0{fill:blue;}
|
||||||
|
.st1{fill:red; }
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="st0 st1"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:red"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 348 B |
17
test/plugins/inlineStyles.05.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.st1 {
|
||||||
|
fill: red;
|
||||||
|
}
|
||||||
|
.st0 {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="st0 st1" style="color:yellow"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="color:yellow;fill:red"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 430 B |
23
test/plugins/inlineStyles.06.svg
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.red {
|
||||||
|
fill: red;
|
||||||
|
}
|
||||||
|
.blue {
|
||||||
|
fill: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="red blue"/>
|
||||||
|
<rect width="100" height="100" class="blue red"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
{"onlyMatchedOnce":false}
|
After Width: | Height: | Size: 539 B |
17
test/plugins/inlineStyles.07.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.red {
|
||||||
|
fill: red !important;
|
||||||
|
}
|
||||||
|
.blue {
|
||||||
|
fill: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="blue red"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:red!important"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 418 B |
17
test/plugins/inlineStyles.08.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.red {
|
||||||
|
fill: red !important;
|
||||||
|
}
|
||||||
|
.blue {
|
||||||
|
fill: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="blue red" style="fill:yellow"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:red!important"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 438 B |
17
test/plugins/inlineStyles.09.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.red {
|
||||||
|
fill: red !important;
|
||||||
|
}
|
||||||
|
.blue {
|
||||||
|
fill: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="blue red" style="fill:yellow !important"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:yellow!important"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 452 B |
14
test/plugins/inlineStyles.10.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
<![CDATA[
|
||||||
|
.st0{fill:blue;}
|
||||||
|
]]>
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="st0"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 354 B |
16
test/plugins/inlineStyles.11.svg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.st0{fill:blue;}
|
||||||
|
.st0:hover{stroke:red;}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="st0"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.st0:hover{stroke:red}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 408 B |
16
test/plugins/inlineStyles.12.svg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<style>
|
||||||
|
.st0:hover{stroke:red;}
|
||||||
|
</style>
|
||||||
|
<rect width="100" height="100" class="st0"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<rect width="100" height="100" style="stroke:red"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
{"usePseudos":[":hover"]}
|
After Width: | Height: | Size: 360 B |
68
test/plugins/inlineStyles.13.svg
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.285 81.285">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
/* Simple Atrules */
|
||||||
|
@charset 'UTF-8';
|
||||||
|
|
||||||
|
@namespace svg url(http://www.w3.org/2000/svg);
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Roboto');
|
||||||
|
|
||||||
|
/* Atrules with block */
|
||||||
|
@font-face {
|
||||||
|
font-family: SomeFont;
|
||||||
|
src: local("Some Font"),
|
||||||
|
local("SomeFont"),
|
||||||
|
url(SomeFont.ttf);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@viewport {
|
||||||
|
zoom: 0.8;
|
||||||
|
min-zoom: 0.4;
|
||||||
|
max-zoom: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes identifier {
|
||||||
|
0% { top: 0; }
|
||||||
|
50% { top: 30px; left: 20px; }
|
||||||
|
50% { top: 10px; }
|
||||||
|
100% { top: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Nested rules */
|
||||||
|
@page :first {
|
||||||
|
margin: 1in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports (display: flex) {
|
||||||
|
.module { display: flex; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@document url('http://example.com/test.html') {
|
||||||
|
rect {
|
||||||
|
stroke: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.blue {
|
||||||
|
fill: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect width="100" height="100" class="blue"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.285 81.285">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
@charset 'UTF-8';@namespace svg url(http://www.w3.org/2000/svg);@import url('https://fonts.googleapis.com/css?family=Roboto');@font-face{font-family: SomeFont;src: local("Some Font"), local("SomeFont"), url(SomeFont.ttf);font-weight: bold}@viewport{zoom: 0.8;min-zoom: 0.4;max-zoom: 0.9}@keyframes identifier{0%{top: 0}50%{top: 30px;left: 20px}50%{top: 10px}100%{top: 0}}@page :first{margin: 1in}@supports (display: flex){.module{display: flex}}@document url('http://example.com/test.html'){rect{stroke: red}}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
25
test/plugins/inlineStyles.14.svg
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.285 81.285">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
@media only screen
|
||||||
|
and (min-device-width: 320px)
|
||||||
|
and (max-device-width: 480px)
|
||||||
|
and (-webkit-min-device-pixel-ratio: 2) {
|
||||||
|
|
||||||
|
.blue { fill: blue; }
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect width="100" height="100" class="blue"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="test" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.285 81.285">
|
||||||
|
<rect width="100" height="100" style="fill:blue"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
{"useMqs": ["media only screen and (min-device-width:320px) and (max-device-width:480px) and (-webkit-min-device-pixel-ratio:2)"]}
|
After Width: | Height: | Size: 699 B |
67
test/plugins/inlineStyles.15.svg
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<style type="text/css">
|
||||||
|
html /deep/ [layout][horizontal], html /deep/ [layout][vertical] { display: flex; }
|
||||||
|
html /deep/ [layout][horizontal][inline], html /deep/ [layout][vertical][inline] { display: inline-flex; }
|
||||||
|
html /deep/ [layout][horizontal] { flex-direction: row; }
|
||||||
|
html /deep/ [layout][horizontal][reverse] { flex-direction: row-reverse; }
|
||||||
|
html /deep/ [layout][vertical] { flex-direction: column; }
|
||||||
|
html /deep/ [layout][vertical][reverse] { flex-direction: column-reverse; }
|
||||||
|
html /deep/ [layout][wrap] { flex-wrap: wrap; }
|
||||||
|
html /deep/ [layout][wrap-reverse] { flex-wrap: wrap-reverse; }
|
||||||
|
html /deep/ [flex] { flex: 1 1 0px; }
|
||||||
|
html /deep/ [flex][auto] { flex: 1 1 auto; }
|
||||||
|
html /deep/ [flex][none] { flex: 0 0 auto; }
|
||||||
|
html /deep/ [flex][one] { flex: 1 1 0px; }
|
||||||
|
html /deep/ [flex][two] { flex: 2 1 0px; }
|
||||||
|
html /deep/ [flex][three] { flex: 3 1 0px; }
|
||||||
|
html /deep/ [flex][four] { flex: 4 1 0px; }
|
||||||
|
html /deep/ [flex][five] { flex: 5 1 0px; }
|
||||||
|
html /deep/ [flex][six] { flex: 6 1 0px; }
|
||||||
|
html /deep/ [flex][seven] { flex: 7 1 0px; }
|
||||||
|
html /deep/ [flex][eight] { flex: 8 1 0px; }
|
||||||
|
html /deep/ [flex][nine] { flex: 9 1 0px; }
|
||||||
|
html /deep/ [flex][ten] { flex: 10 1 0px; }
|
||||||
|
html /deep/ [flex][eleven] { flex: 11 1 0px; }
|
||||||
|
html /deep/ [flex][twelve] { flex: 12 1 0px; }
|
||||||
|
html /deep/ [layout][start] { align-items: flex-start; }
|
||||||
|
html /deep/ [layout][center] { align-items: center; }
|
||||||
|
html /deep/ [layout][end] { align-items: flex-end; }
|
||||||
|
html /deep/ [layout][start-justified] { justify-content: flex-start; }
|
||||||
|
html /deep/ [layout][center-justified] { justify-content: center; }
|
||||||
|
html /deep/ [layout][end-justified] { justify-content: flex-end; }
|
||||||
|
html /deep/ [layout][around-justified] { justify-content: space-around; }
|
||||||
|
html /deep/ [layout][justified] { justify-content: space-between; }
|
||||||
|
html /deep/ [self-start] { align-self: flex-start; }
|
||||||
|
html /deep/ [self-center] { align-self: center; }
|
||||||
|
html /deep/ [self-end] { align-self: flex-end; }
|
||||||
|
html /deep/ [self-stretch] { align-self: stretch; }
|
||||||
|
html /deep/ [block] { display: block; }
|
||||||
|
html /deep/ [hidden] { display: none !important; }
|
||||||
|
html /deep/ [relative] { position: relative; }
|
||||||
|
html /deep/ [fit] { position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px; }
|
||||||
|
body[fullbleed] { margin: 0px; height: 100vh; }
|
||||||
|
html /deep/ [segment], html /deep/ segment { display: block; position: relative; box-sizing: border-box; margin: 1em 0.5em; padding: 1em; -webkit-box-shadow: rgba(0, 0, 0, 0.0980392) 0px 0px 0px 1px; box-shadow: rgba(0, 0, 0, 0.0980392) 0px 0px 0px 1px; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; background-color: white; }
|
||||||
|
html /deep/ core-icon { display: inline-block; vertical-align: middle; background-repeat: no-repeat; }
|
||||||
|
html /deep/ core-icon[size=""] { position: relative; }
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="airplanemode-on">
|
||||||
|
<path d="M10.2,9"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<defs xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<style type="text/css">
|
||||||
|
html /deep/ [layout][horizontal],html /deep/ [layout][vertical]{display: flex}html /deep/ [layout][horizontal][inline],html /deep/ [layout][vertical][inline]{display: inline-flex}html /deep/ [layout][horizontal]{flex-direction: row}html /deep/ [layout][horizontal][reverse]{flex-direction: row-reverse}html /deep/ [layout][vertical]{flex-direction: column}html /deep/ [layout][vertical][reverse]{flex-direction: column-reverse}html /deep/ [layout][wrap]{flex-wrap: wrap}html /deep/ [layout][wrap-reverse]{flex-wrap: wrap-reverse}html /deep/ [flex]{flex: 1 1 0px}html /deep/ [flex][auto]{flex: 1 1 auto}html /deep/ [flex][none]{flex: 0 0 auto}html /deep/ [flex][one]{flex: 1 1 0px}html /deep/ [flex][two]{flex: 2 1 0px}html /deep/ [flex][three]{flex: 3 1 0px}html /deep/ [flex][four]{flex: 4 1 0px}html /deep/ [flex][five]{flex: 5 1 0px}html /deep/ [flex][six]{flex: 6 1 0px}html /deep/ [flex][seven]{flex: 7 1 0px}html /deep/ [flex][eight]{flex: 8 1 0px}html /deep/ [flex][nine]{flex: 9 1 0px}html /deep/ [flex][ten]{flex: 10 1 0px}html /deep/ [flex][eleven]{flex: 11 1 0px}html /deep/ [flex][twelve]{flex: 12 1 0px}html /deep/ [layout][start]{align-items: flex-start}html /deep/ [layout][center]{align-items: center}html /deep/ [layout][end]{align-items: flex-end}html /deep/ [layout][start-justified]{justify-content: flex-start}html /deep/ [layout][center-justified]{justify-content: center}html /deep/ [layout][end-justified]{justify-content: flex-end}html /deep/ [layout][around-justified]{justify-content: space-around}html /deep/ [layout][justified]{justify-content: space-between}html /deep/ [self-start]{align-self: flex-start}html /deep/ [self-center]{align-self: center}html /deep/ [self-end]{align-self: flex-end}html /deep/ [self-stretch]{align-self: stretch}html /deep/ [block]{display: block}html /deep/ [hidden]{display: none !important}html /deep/ [relative]{position: relative}html /deep/ [fit]{position: absolute;top: 0px;right: 0px;bottom: 0px;left: 0px}body[fullbleed]{margin: 0px;height: 100vh}html /deep/ [segment],html /deep/ segment{display: block;position: relative;box-sizing: border-box;margin: 1em 0.5em;padding: 1em;-webkit-box-shadow: rgba(0, 0, 0, 0.0980392) 0px 0px 0px 1px;box-shadow: rgba(0, 0, 0, 0.0980392) 0px 0px 0px 1px;border-top-left-radius: 5px;border-top-right-radius: 5px;border-bottom-right-radius: 5px;border-bottom-left-radius: 5px;background-color: white}html /deep/ core-icon{display: inline-block;vertical-align: middle;background-repeat: no-repeat}html /deep/ core-icon[size=""]{position: relative}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="airplanemode-on">
|
||||||
|
<path d="M10.2,9"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.4 KiB |
40
test/plugins/inlineStyles.16.svg
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 222 57.28">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
#id0 {
|
||||||
|
stroke: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-1 {
|
||||||
|
fill: #37d0cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-2{
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<title>button</title>
|
||||||
|
<rect id="id0" class="cls-1" width="222" height="57.28" rx="28.64" ry="28.64"/>
|
||||||
|
<path class="cls-2" d="M312.75,168.66A2.15,2.15,0,0,1,311.2,165L316,160l-4.8-5a2.15,2.15,0,1,1,3.1-3l6.21,6.49a2.15,2.15,0,0,1,0,3L314.31,168a2.14,2.14,0,0,1-1.56.67Zm0,0" transform="translate(-119 -131.36)"/>
|
||||||
|
<circle class="cls-2" cx="33.5" cy="27.25" r="2.94"/>
|
||||||
|
<circle class="cls-2" cx="162.5" cy="158.61" r="2.94" transform="translate(-181.03 61.15) rotate(-52.89)"/>
|
||||||
|
<circle class="cls-2" cx="172.5" cy="158.61" r="2.94" transform="translate(-157.03 -75.67) rotate(-16.55)"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 222 57.28">
|
||||||
|
<title>
|
||||||
|
button
|
||||||
|
</title>
|
||||||
|
<rect width="222" height="57.28" rx="28.64" ry="28.64" style="stroke:red;fill:#37d0cd"/>
|
||||||
|
<path d="M312.75,168.66A2.15,2.15,0,0,1,311.2,165L316,160l-4.8-5a2.15,2.15,0,1,1,3.1-3l6.21,6.49a2.15,2.15,0,0,1,0,3L314.31,168a2.14,2.14,0,0,1-1.56.67Zm0,0" transform="translate(-119 -131.36)" style="fill:#fff"/>
|
||||||
|
<circle cx="33.5" cy="27.25" r="2.94" style="fill:#fff"/>
|
||||||
|
<circle cx="162.5" cy="158.61" r="2.94" transform="translate(-181.03 61.15) rotate(-52.89)" style="fill:#fff"/>
|
||||||
|
<circle cx="172.5" cy="158.61" r="2.94" transform="translate(-157.03 -75.67) rotate(-16.55)" style="fill:#fff"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
@@@
|
||||||
|
|
||||||
|
{"onlyMatchedOnce":false}
|
After Width: | Height: | Size: 1.7 KiB |
@ -7,6 +7,6 @@
|
|||||||
@@@
|
@@@
|
||||||
|
|
||||||
<?xml version="1.0" encoding="utf-16"?>
|
<?xml version="1.0" encoding="utf-16"?>
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100" xml:space="preserve">
|
||||||
<circle class="st0" cx="50" cy="50" r="50"/>
|
<circle class="st0" cx="50" cy="50" r="50"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 663 B After Width: | Height: | Size: 662 B |
@ -11,6 +11,6 @@
|
|||||||
@@@
|
@@@
|
||||||
|
|
||||||
<?xml version="1.0" encoding="utf-16"?>
|
<?xml version="1.0" encoding="utf-16"?>
|
||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100" xml:space="preserve">
|
||||||
<circle class="st0" cx="50" cy="50" r="50"/>
|
<circle class="st0" cx="50" cy="50" r="50"/>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 737 B After Width: | Height: | Size: 736 B |