parse2.html 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>CSSOM.js parse method</title>
  6. <script>
  7. var exports = {};
  8. function require(){
  9. return exports;
  10. }
  11. </script>
  12. <script src="../lib/CSSStyleDeclaration.js"></script>
  13. <script src="../lib/CSSRule.js"></script>
  14. <script src="../lib/CSSStyleRule.js"></script>
  15. <script src="../lib/CSSImportRule.js"></script>
  16. <script src="../lib/MediaList.js"></script>
  17. <script src="../lib/CSSMediaRule.js"></script>
  18. <script src="../lib/StyleSheet.js"></script>
  19. <script src="../lib/CSSStyleSheet.js"></script>
  20. <script src="../lib/parse.js"></script>
  21. <script>
  22. window.CSSOM = exports;
  23. </script>
  24. <style>
  25. html {
  26. padding: 0;
  27. }
  28. </style>
  29. <style type="text/css">
  30. html, body {
  31. background: #333;
  32. color: #EEE;
  33. font: 12px sans-serif;
  34. margin: 0;
  35. height: 100%;
  36. }
  37. body {
  38. padding-bottom: 1.7em;
  39. -webkit-box-sizing: border-box;
  40. -moz-box-sizing: border-box;
  41. box-sizing: border-box;
  42. }
  43. table {
  44. width: 100%;
  45. table-layout: fixed;
  46. margin: 0 auto;
  47. }
  48. td {
  49. vertical-align: top;
  50. }
  51. h1 {
  52. font: normal 1em sans-serif;
  53. display: inline;
  54. }
  55. #labels {
  56. color: #FFE992;
  57. width: 66%;
  58. }
  59. #labels td {
  60. width: 50%;
  61. text-align: center;
  62. }
  63. #labels td::before {
  64. content: '↱ ';
  65. color: #998e62;
  66. position: relative;
  67. top: .4em;
  68. }
  69. #labels td::after {
  70. content: ' ↴';
  71. color: #998e62;
  72. position: relative;
  73. top: .4em;
  74. }
  75. #content {
  76. width: 100%;
  77. height: 100%;
  78. }
  79. #content td {
  80. width: 33%;
  81. }
  82. #content td + td {
  83. padding-left: 1%;
  84. }
  85. .style-cell textarea {
  86. width: 99%;
  87. height: 100%;
  88. font: 12px monospace;
  89. white-space: pre-wrap;
  90. }
  91. .serialized-cell {
  92. border-left: 1px solid #363636;
  93. }
  94. #message {
  95. visibility: hidden;
  96. }
  97. .error #message {
  98. visibility: visible;
  99. position: absolute;
  100. top: 0;
  101. left: 34%;
  102. padding: 1em;
  103. background: black;
  104. color: #e34343;
  105. font-size: 24px;
  106. }
  107. </style>
  108. </head>
  109. <body>
  110. <table id="labels">
  111. <tr><td><h1>CSSOM.parse</h1></td><td>.toString</td></tr>
  112. </table>
  113. <table id="content">
  114. <tr>
  115. <td class="style-cell">
  116. <textarea id="style" spellcheck="false" rows="40">img {
  117. border: none
  118. }</textarea></td>
  119. <td class="output-cell"><pre id="output"></pre></td>
  120. <td class="serialized-cell"><pre id="serialized"></pre></td>
  121. </tr>
  122. </table>
  123. <div id="message"></div>
  124. <script defer>
  125. console.dir(document.styleSheets[0].cssRules[0].style);
  126. //console.log(document.styleSheets[0].cssRules[0].style["table-layout"]);
  127. var CSS = {
  128. background: [
  129. "background-image",
  130. "background-repeat",
  131. "background-attachment",
  132. "background-position",
  133. "background-origin",
  134. "background-clip",
  135. "background-color"
  136. ],
  137. "background-repeat": [
  138. "background-repeat-x",
  139. "background-repeat-y"
  140. ],
  141. "background-position": [
  142. "background-position-x",
  143. "background-position-y"
  144. ],
  145. border: [
  146. "border-top",
  147. "border-right",
  148. "border-bottom",
  149. "border-left",
  150. "border-width",
  151. "border-style",
  152. "border-color"
  153. ],
  154. "border-top": [
  155. "border-top-width",
  156. "border-top-style",
  157. "border-top-color"
  158. ],
  159. "border-right": [
  160. "border-right-width",
  161. "border-right-style",
  162. "border-right-color"
  163. ],
  164. "border-bottom": [
  165. "border-bottom-width",
  166. "border-bottom-style",
  167. "border-bottom-color"
  168. ],
  169. "border-left": [
  170. "border-left-width",
  171. "border-left-style",
  172. "border-left-color"
  173. ],
  174. font: [
  175. "font-style",
  176. "font-variant",
  177. "font-weight",
  178. "font-size",
  179. "font-size-adjust",
  180. "font-stretch",
  181. "line-height",
  182. "font-family"
  183. ],
  184. "list-style": [
  185. "list-style-type",
  186. "list-style-position",
  187. "list-style-image"
  188. ],
  189. margin: [
  190. "margin-top",
  191. "margin-right",
  192. "margin-bottom",
  193. "margin-left"
  194. ],
  195. padding: [
  196. "padding-top",
  197. "padding-right",
  198. "padding-bottom",
  199. "padding-left"
  200. ]
  201. };
  202. function camelize(string) {
  203. return string.replace(/-+(.)?/g, function(match, chr) {
  204. return chr ? chr.toUpperCase() : '';
  205. });
  206. }
  207. CSS["background-repeat"].shorthand = function(style) {
  208. if (style["background-repeat-x"] == style["background-repeat-y"]) {
  209. return style["background-repeat-x"];
  210. } else {
  211. return style["background-repeat-x"] + " " + style["background-repeat-y"];
  212. }
  213. };
  214. CSS["background-position"].shorthand = function(style) {
  215. if (style["background-position-x"] == style["background-position-y"]) {
  216. return style["background-position-x"];
  217. } else {
  218. return style["background-position-x"] + " " + style["background-position-y"];
  219. }
  220. };
  221. CSS.background.shorthand = function(style) {
  222. var values = [];
  223. //FIXME
  224. // Support CSS3 background shorthand
  225. // http://www.w3.org/TR/css3-background/#the-background
  226. var backgroundColor = style["background-color"];
  227. if (backgroundColor != "initial" && backgroundColor != "transparent") {
  228. values.push(backgroundColor);
  229. }
  230. var backgroundImage = style["background-image"];
  231. if (backgroundImage != "initial" && backgroundImage != "none") {
  232. values.push(backgroundImage);
  233. }
  234. var backgroundRepeat = style["background-repeat"];
  235. if (backgroundRepeat != "initial" && backgroundRepeat != "repeat") {
  236. values.push(backgroundRepeat);
  237. }
  238. var backgroundAttachment = style["background-attachment"];
  239. if (backgroundAttachment != "initial" && backgroundAttachment != "scroll") {
  240. values.push(backgroundAttachment);
  241. }
  242. var backgroundPosition = style["background-position"];
  243. if (backgroundPosition != "initial" && parseInt(backgroundPosition) !== 0) {
  244. values.push(backgroundPosition);
  245. }
  246. return values.join(" ") || "";
  247. };
  248. (function(){
  249. for (var key in CSS) {
  250. var longhand = CSS[key];
  251. if (!longhand.length) {
  252. continue;
  253. }
  254. for (var i=0, ii=longhand.length; i<ii; i++) {
  255. var siblings = longhand.slice(0);
  256. siblings.splice(i, 1);
  257. if (CSS[longhand[i]]) {
  258. //console.log("array", CSS[longhand[i]]);
  259. } else {
  260. CSS[longhand[i]] = {}
  261. }
  262. CSS[longhand[i]].parent = key;
  263. CSS[longhand[i]].siblings = siblings;
  264. }
  265. }
  266. })();
  267. function cloneMinimized(stylesheet) {
  268. var cloned = new CSSOM.CSSStyleSheet;
  269. var rules = stylesheet.cssRules;
  270. if (!rules) {
  271. return cloned;
  272. }
  273. var RULE_TYPES = {
  274. 1: CSSOM.CSSStyleRule,
  275. 4: CSSOM.CSSMediaRule
  276. //FIXME
  277. //3: CSSOM.CSSImportRule,
  278. //5: CSSOM.CSSFontFaceRule,
  279. //6: CSSOM.CSSPageRule,
  280. };
  281. for (var i=0, rulesLength=rules.length; i < rulesLength; i++) {
  282. var rule = rules[i];
  283. var ruleClone = cloned.cssRules[i] = new RULE_TYPES[rule.type];
  284. var style = rule.style;
  285. if (style) {
  286. var styleClone = ruleClone.style = minimizeStyle(style);
  287. }
  288. if ("selectorText" in rule) {
  289. ruleClone.selectorText = rule.selectorText;
  290. }
  291. if ("mediaText" in rule) {
  292. ruleClone.mediaText = rule.mediaText;
  293. }
  294. if ("cssRules" in rule) {
  295. rule.cssRules = clone(rule).cssRules;
  296. }
  297. }
  298. return cloned;
  299. };
  300. function minimizeStyle(style) {
  301. var result = new CSSOM.CSSStyleDeclaration;
  302. for (var i=0; i<style.length; i++) {
  303. var name = closestShorthand(style, style[i]);
  304. if (!(name in result)) {
  305. result[name] = style[camelize(name)];
  306. result[result.length++] = name;
  307. }
  308. }
  309. return result;
  310. }
  311. function closestShorthand(style, name) {
  312. if (!(name in CSS)) {
  313. return name;
  314. }
  315. var siblings = CSS[name].siblings;
  316. if (!siblings || !siblings.length) {
  317. return name;
  318. }
  319. var properties = {};
  320. var allPresent = true;
  321. for (var j=0; j<siblings.length; j++) {
  322. var sibling = siblings[j];
  323. var aSibling = camelize(sibling);
  324. if (style[aSibling] === "") {
  325. console.warn(sibling);
  326. if (CSS[sibling].length) {
  327. for (var i=0; i<CSS[sibling].length; i++) {
  328. if (style[camelize(CSS[sibling][i])] === "") {
  329. allPresent = false;
  330. break;
  331. }
  332. }
  333. } else {
  334. allPresent = false;
  335. break;
  336. }
  337. }
  338. }
  339. if (allPresent) {
  340. return closestShorthand(style, CSS[name].parent);
  341. } else {
  342. return name;
  343. }
  344. }
  345. console.log(cloneMinimized(document.styleSheets[0]).toString());
  346. //console.log(CSSOM.CSSStyleSheet.prototype.toString.call(minimize(document.styleSheets[0].cssRules[0].style)));
  347. //console.log(document.styleSheets[0].cssRules[0].style["background-image"]);
  348. //console.log(CSS);
  349. var errors = [];
  350. //if (!Object.defineProperty) {
  351. // errors.push("Object.defineProperty isn’t supported");
  352. //}
  353. if (errors.length) {
  354. document.getElementById("message").innerHTML = errors.join("<br>");
  355. document.body.className = "error";
  356. throw errors.join("\n\n");
  357. }
  358. var style = document.getElementById("style");
  359. var output = document.getElementById("output");
  360. var serialized = document.getElementById("serialized");
  361. function outputUpdated(){
  362. var value = style.value;
  363. if (value != style.prevValue) {
  364. var css = CSSOM.parse(value);
  365. output.innerHTML = JSON.stringify(css, null, 2);
  366. serialized.innerHTML = css.toString();
  367. style.prevValue = value;
  368. }
  369. }
  370. function hashChanged(){
  371. var hash = location.hash;
  372. var splitted = hash.split("=");
  373. if (splitted.length < 2) {
  374. return;
  375. }
  376. var name = splitted[0];
  377. var value = splitted[1];
  378. if (name == "#css") {
  379. style.value = decodeURIComponent(value);
  380. outputUpdated();
  381. }
  382. }
  383. hashChanged();
  384. outputUpdated();
  385. window.onhashchange = hashChanged;
  386. style.onkeyup = style.onpaste = function changed(){
  387. outputUpdated();
  388. };
  389. style.onchange = function updateLocation(){
  390. location.hash = "css=" + encodeURIComponent(style.value);
  391. };
  392. </script>
  393. </body>
  394. </html>