/** * Styles.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /** * This class is used to parse CSS styles it also compresses styles to reduce the output size. * * @example * var Styles = new tinymce.html.Styles({ * url_converter: function(url) { * return url; * } * }); * * styles = Styles.parse('border: 1px solid red'); * styles.color = 'red'; * * console.log(new tinymce.html.StyleSerializer().serialize(styles)); * * @class tinymce.html.Styles * @version 3.4 */ tinymce.html.Styles = function(settings, schema) { var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi, urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi, styleRegExp = /\s*([^:]+):\s*([^;]+);?/g, trimRightRegExp = /\s+$/, urlColorRegExp = /rgb/, undef, i, encodingLookup = {}, encodingItems; settings = settings || {}; encodingItems = '\\" \\\' \\; \\: ; : \uFEFF'.split(' '); for (i = 0; i < encodingItems.length; i++) { encodingLookup[encodingItems[i]] = '\uFEFF' + i; encodingLookup['\uFEFF' + i] = encodingItems[i]; } function toHex(match, r, g, b) { function hex(val) { val = parseInt(val).toString(16); return val.length > 1 ? val : '0' + val; // 0 -> 00 }; return '#' + hex(r) + hex(g) + hex(b); }; return { /** * Parses the specified RGB color value and returns a hex version of that color. * * @method toHex * @param {String} color RGB string value like rgb(1,2,3) * @return {String} Hex version of that RGB value like #FF00FF. */ toHex : function(color) { return color.replace(rgbRegExp, toHex); }, /** * Parses the specified style value into an object collection. This parser will also * merge and remove any redundant items that browsers might have added. It will also convert non hex * colors to hex values. Urls inside the styles will also be converted to absolute/relative based on settings. * * @method parse * @param {String} css Style value to parse for example: border:1px solid red;. * @return {Object} Object representation of that style like {border : '1px solid red'} */ parse : function(css) { var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope || this; function compress(prefix, suffix) { var top, right, bottom, left; // IE 11 will produce a border-image: none when getting the style attribute from
// So lets asume it shouldn't be there if (styles['border-image'] === 'none') { delete styles['border-image']; } // Get values and check it it needs compressing top = styles[prefix + '-top' + suffix]; if (!top) return; right = styles[prefix + '-right' + suffix]; if (top != right) return; bottom = styles[prefix + '-bottom' + suffix]; if (right != bottom) return; left = styles[prefix + '-left' + suffix]; if (bottom != left) return; // Compress styles[prefix + suffix] = left; delete styles[prefix + '-top' + suffix]; delete styles[prefix + '-right' + suffix]; delete styles[prefix + '-bottom' + suffix]; delete styles[prefix + '-left' + suffix]; }; /** * Checks if the specific style can be compressed in other words if all border-width are equal. */ function canCompress(key) { var value = styles[key], i; if (!value || value.indexOf(' ') < 0) return; value = value.split(' '); i = value.length; while (i--) { if (value[i] !== value[0]) return false; } styles[key] = value[0]; return true; }; /** * Compresses multiple styles into one style. */ function compress2(target, a, b, c) { if (!canCompress(a)) return; if (!canCompress(b)) return; if (!canCompress(c)) return; // Compress styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c]; delete styles[a]; delete styles[b]; delete styles[c]; }; // Encodes the specified string by replacing all \" \' ; : with _