133 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | ||
| 
 | ||
| exports.name = 'convertStyleToAttrs';
 | ||
| 
 | ||
| exports.type = 'perItem';
 | ||
| 
 | ||
| exports.active = false;
 | ||
| 
 | ||
| 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) {
 | ||
|   if (item.type === 'element' && item.attributes.style != null) {
 | ||
|     // ['opacity: 1', 'color: #000']
 | ||
|     let styles = [];
 | ||
|     const newAttributes = {};
 | ||
| 
 | ||
|     // Strip CSS comments preserving escape sequences and strings.
 | ||
|     const styleValue = item.attributes.style.replace(
 | ||
|       regStripComments,
 | ||
|       (match) => {
 | ||
|         return match[0] == '/'
 | ||
|           ? ''
 | ||
|           : match[0] == '\\' && /[-g-z]/i.test(match[1])
 | ||
|           ? match[1]
 | ||
|           : match;
 | ||
|       }
 | ||
|     );
 | ||
| 
 | ||
|     regDeclarationBlock.lastIndex = 0;
 | ||
|     // eslint-disable-next-line no-cond-assign
 | ||
|     for (var rule; (rule = regDeclarationBlock.exec(styleValue)); ) {
 | ||
|       if (!params.keepImportant || !rule[3]) {
 | ||
|         styles.push([rule[1], rule[2]]);
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     if (styles.length) {
 | ||
|       styles = styles.filter(function (style) {
 | ||
|         if (style[0]) {
 | ||
|           var prop = style[0].toLowerCase(),
 | ||
|             val = style[1];
 | ||
| 
 | ||
|           if (rQuotedString.test(val)) {
 | ||
|             val = val.slice(1, -1);
 | ||
|           }
 | ||
| 
 | ||
|           if (stylingProps.includes(prop)) {
 | ||
|             newAttributes[prop] = val;
 | ||
| 
 | ||
|             return false;
 | ||
|           }
 | ||
|         }
 | ||
| 
 | ||
|         return true;
 | ||
|       });
 | ||
| 
 | ||
|       Object.assign(item.attributes, newAttributes);
 | ||
| 
 | ||
|       if (styles.length) {
 | ||
|         item.attributes.style = styles
 | ||
|           .map((declaration) => declaration.join(':'))
 | ||
|           .join(';');
 | ||
|       } else {
 | ||
|         delete item.attributes.style;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| };
 | ||
| 
 | ||
| function g() {
 | ||
|   return '(?:' + Array.prototype.join.call(arguments, '|') + ')';
 | ||
| }
 |