UNPKG

cssom

Version:

CSS Object Model implementation and CSS parser

519 lines (475 loc) 11 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>CSSOM.js parse method</title> <script> var exports = {}; function require(){ return exports; } </script> <script src="../lib/CSSStyleDeclaration.js"></script> <script src="../lib/CSSRule.js"></script> <script src="../lib/CSSStyleRule.js"></script> <script src="../lib/CSSImportRule.js"></script> <script src="../lib/MediaList.js"></script> <script src="../lib/CSSMediaRule.js"></script> <script src="../lib/StyleSheet.js"></script> <script src="../lib/CSSStyleSheet.js"></script> <script src="../lib/parse.js"></script> <script> window.CSSOM = exports; </script> <style> .corner{ background: none; border-radius:8px; padding: 0 3px 3px; border:none } </style> <style> /*@import url(foo.css);*/ /*@media all {*/ html { background-position: 0; border: red; } /*}*/ </style> <style type="text/css"> html, body { background: #333; color: #EEE; font: 12px sans-serif; margin: 0; height: 100%; } body { padding-bottom: 1.7em; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } table { width: 100%; table-layout: fixed; margin: 0 auto; } td { vertical-align: top; } h1 { font: normal 1em sans-serif; display: inline; } #labels { color: #FFE992; width: 66%; } #labels td { width: 50%; text-align: center; } #labels td::before { content: '↱ '; color: #998e62; position: relative; top: .4em; } #labels td::after { content: ' ↴'; color: #998e62; position: relative; top: .4em; } #content { width: 100%; height: 100%; } #content td { width: 33%; } #content td + td { padding-left: 1%; } .style-cell textarea { width: 99%; height: 100%; font: 12px monospace; white-space: pre-wrap; } .serialized-cell { border-left: 1px solid #363636; } #message { visibility: hidden; } .error #message { visibility: visible; position: absolute; top: 0; left: 34%; padding: 1em; background: black; color: #e34343; font-size: 24px; } </style> </head> <body> <table id="labels"> <tr><td><h1>CSSOM.parse</h1></td><td>.toString</td></tr> </table> <table id="content"> <tr> <td class="style-cell"> <textarea id="style" spellcheck="false" rows="40">img { border: none }</textarea></td> <td class="output-cell"><pre id="output"></pre></td> <td class="serialized-cell"><pre id="serialized"></pre></td> </tr> </table> <div id="message"></div> <script defer> //console.log(document.styleSheets[0].cssRules[0].style["table-layout"]); var CSS = { background: [ "background-image", "background-repeat", "background-attachment", "background-position", "background-origin", "background-clip", "background-color" ], "background-repeat": [ "background-repeat-x", "background-repeat-y" ], "background-position": [ "background-position-x", "background-position-y" ], border: [ "border-top", "border-right", "border-bottom", "border-left", "border-width", "border-style", "border-color" ], "border-top": [ "border-top-width", "border-top-style", "border-top-color" ], "border-right": [ "border-right-width", "border-right-style", "border-right-color" ], "border-bottom": [ "border-bottom-width", "border-bottom-style", "border-bottom-color" ], "border-left": [ "border-left-width", "border-left-style", "border-left-color" ], "border-style": [ "border-top-style", "border-right-style", "border-bottom-style", "border-left-style" ], "border-width": [ "border-top-width", "border-right-width", "border-bottom-width", "border-left-width" ], "border-color": [ "border-top-color", "border-right-color", "border-bottom-color", "border-left-color" ], "border-radius": [ "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius" ], font: [ "font-style", "font-variant", "font-weight", "font-size", "font-size-adjust", "font-stretch", "line-height", "font-family" ], "list-style": [ "list-style-type", "list-style-position", "list-style-image" ], margin: [ "margin-top", "margin-right", "margin-bottom", "margin-left" ], padding: [ "padding-top", "padding-right", "padding-bottom", "padding-left" ] }; function camelize(string) { return string.replace(/-+(.)?/g, function(match, chr) { return chr ? chr.toUpperCase() : ''; }); } CSS["background-repeat"].shorthand = function(style) { if (style["background-repeat-x"] == style["background-repeat-y"]) { return style["background-repeat-x"]; } else { return style["background-repeat-x"] + " " + style["background-repeat-y"]; } }; CSS["background-position"].shorthand = function(style) { if (style["background-position-x"] == style["background-position-y"]) { return style["background-position-x"]; } else { return style["background-position-x"] + " " + style["background-position-y"]; } }; CSS["border-radius"].shorthand = function(style) { var radius = style["border-top-left-radius"]; if (style["border-top-right-radius"] == radius && style["border-bottom-right-radius"] == radius && style["border-bottom-left-radius"] == radius) { var couple = radius.split(' '); if (couple[0] == couple[1]) { return couple[0]; } else { return radius; } } }; /* CSS.background.shorthand = function(style) { var values = []; //FIXME // Support CSS3 background shorthand // http://www.w3.org/TR/css3-background/#the-background var backgroundColor = style["background-color"]; if (backgroundColor != "initial" && backgroundColor != "transparent") { values.push(backgroundColor); } var backgroundImage = style["background-image"]; if (backgroundImage != "initial" && backgroundImage != "none") { values.push(backgroundImage); } var backgroundRepeat = style["background-repeat"]; if (backgroundRepeat != "initial" && backgroundRepeat != "repeat") { values.push(backgroundRepeat); } var backgroundAttachment = style["background-attachment"]; if (backgroundAttachment != "initial" && backgroundAttachment != "scroll") { values.push(backgroundAttachment); } var backgroundPosition = style["background-position"]; if (backgroundPosition != "initial" && parseInt(backgroundPosition) !== 0) { values.push(backgroundPosition); } return values.join(" ") || ""; }; */ (function(){ for (var key in CSS) { var longhand = CSS[key]; if (!longhand.length) { continue; } for (var i=0, ii=longhand.length; i<ii; i++) { var siblings = longhand.slice(0); siblings.splice(i, 1); if (CSS[longhand[i]]) { //console.log("array", CSS[longhand[i]]); } else { CSS[longhand[i]] = {} } CSS[longhand[i]].parent = key; CSS[longhand[i]].siblings = siblings; } } })(); function cloneMinimized(stylesheet) { var cloned = new CSSOM.CSSStyleSheet; var rules = stylesheet.cssRules; if (!rules) { return cloned; } var RULE_TYPES = { 1: CSSOM.CSSStyleRule, 4: CSSOM.CSSMediaRule //FIXME //3: CSSOM.CSSImportRule, //5: CSSOM.CSSFontFaceRule, //6: CSSOM.CSSPageRule, }; for (var i=0, rulesLength=rules.length; i < rulesLength; i++) { var rule = rules[i]; var ruleClone = cloned.cssRules[i] = new RULE_TYPES[rule.type]; var style = rule.style; if (style) { var styleClone = ruleClone.style = minimizeStyle(style); } if ("selectorText" in rule) { ruleClone.selectorText = rule.selectorText; } if ("mediaText" in rule) { ruleClone.mediaText = rule.mediaText; } if ("cssRules" in rule) { rule.cssRules = clone(rule).cssRules; } } return cloned; } function minimizeStyle(style) { var result = new CSSOM.CSSStyleDeclaration; for (var i=0; i<style.length; i++) { var name = closestShorthand(style, style[i]); if (!(name in result)) { var value; if (CSS[name].shorthand) { value = CSS[name].shorthand(style); } else { value = style[camelize(name)]; } if (value == 'initial') { //console.warn(name +':'+ value); } else { result[name] = value; result[result.length++] = name; } } } return result; } CSSStyleSheet.prototype.stringify = function() { var result = ''; var rules = this.cssRules; for (var i = 0; i < rules.length; i++) { var rule = rules[i]; switch (rule.type) { case CSSRule.STYLE_RULE: case CSSRule.MEDIA_RULE: result += rule.stringify(); break; case CSSRule.IMPORT_RULE: result += rule.cssText; break; } } return result; }; onload = function(){ console.log(document.styleSheets[0].stringify()); }; CSSStyleRule.prototype.stringify = function() { return this.selectorText + ' {' + minimizeStyle(this.style).cssText +'}\n'; }; function closestShorthand(style, name) { if (!(name in CSS)) { return name; } var siblings = CSS[name].siblings; if (!siblings || !siblings.length) { return name; } var properties = {}; var allPresent = true; for (var j=0; j<siblings.length; j++) { var sibling = siblings[j]; var aSibling = camelize(sibling); if (style[aSibling] === "") { // console.warn(sibling); if (CSS[sibling].length) { for (var i=0; i<CSS[sibling].length; i++) { if (style[camelize(CSS[sibling][i])] === "") { allPresent = false; break; } } } else { allPresent = false; break; } } } if (allPresent) { return closestShorthand(style, CSS[name].parent); } else { return name; } } //console.log(cloneMinimized(document.styleSheets[0]).toString()); //console.log(CSSOM.CSSStyleSheet.prototype.toString.call(minimize(document.styleSheets[0].cssRules[0].style))); //console.log(document.styleSheets[0].cssRules[0].style["background-image"]); //console.log(CSS); var errors = []; //if (!Object.defineProperty) { // errors.push("Object.defineProperty isn’t supported"); //} if (errors.length) { document.getElementById("message").innerHTML = errors.join("<br>"); document.body.className = "error"; throw errors.join("\n\n"); } var style = document.getElementById("style"); var output = document.getElementById("output"); var serialized = document.getElementById("serialized"); function outputUpdated() { var value = style.value; if (value != style.prevValue) { var css = CSSOM.parse(value); output.innerHTML = JSON.stringify(css, null, 2); serialized.innerHTML = cloneMinimized(css).toString(); style.prevValue = value; } } function hashChanged() { var hash = location.hash; var splitted = hash.split("="); if (splitted.length < 2) { return; } var name = splitted[0]; var value = splitted[1]; if (name == "#css") { style.value = decodeURIComponent(value); outputUpdated(); } } hashChanged(); outputUpdated(); window.onhashchange = hashChanged; style.onkeyup = style.onpaste = function changed(){ outputUpdated(); }; style.onchange = function updateLocation(){ location.hash = "css=" + encodeURIComponent(style.value); }; </script> </body> </html>