parse.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. //.CommonJS
  2. var CSSOM = {
  3. CSSStyleSheet: require("./CSSStyleSheet").CSSStyleSheet,
  4. CSSStyleRule: require("./CSSStyleRule").CSSStyleRule,
  5. CSSMediaRule: require("./CSSMediaRule").CSSMediaRule
  6. };
  7. ///CommonJS
  8. /**
  9. * @param {string} token
  10. * @param {Object} [options]
  11. */
  12. CSSOM.parse = function parse(token, options) {
  13. options = options || {};
  14. var i = options.startIndex || 0;
  15. var state = options.state || "selector";
  16. var index;
  17. var j = i;
  18. var buffer = "";
  19. var SIGNIFICANT_WHITESPACE = {
  20. "selector": true,
  21. "value": true,
  22. "atRule": true,
  23. "atBlock": true
  24. };
  25. var styleSheet = new CSSOM.CSSStyleSheet;
  26. // @type CSSStyleSheet|CSSMediaRule
  27. var currentScope = styleSheet;
  28. var selector, name, value, priority="", styleRule, mediaRule;
  29. for (var character; character = token.charAt(i); i++) {
  30. switch (character) {
  31. case " ":
  32. case "\t":
  33. case "\r":
  34. case "\n":
  35. case "\f":
  36. if (SIGNIFICANT_WHITESPACE[state]) {
  37. // Squash 2 or more white-spaces in the row into 1
  38. switch (token.charAt(i - 1)) {
  39. case " ":
  40. case "\t":
  41. case "\r":
  42. case "\n":
  43. case "\f":
  44. break;
  45. default:
  46. buffer += " ";
  47. break;
  48. }
  49. }
  50. break;
  51. // String
  52. case '"':
  53. j = i + 1;
  54. index = token.indexOf('"', j) + 1;
  55. if (!index) {
  56. throw '" is missing';
  57. }
  58. buffer += token.slice(i, index);
  59. i = index - 1;
  60. break;
  61. case "'":
  62. j = i + 1;
  63. index = token.indexOf("'", j) + 1;
  64. if (!index) {
  65. throw "' is missing";
  66. }
  67. buffer += token.slice(i, index);
  68. i = index - 1;
  69. break;
  70. // Comment
  71. case "/":
  72. if (token.charAt(i + 1) == "*") {
  73. i += 2;
  74. index = token.indexOf("*/", i);
  75. if (index == -1) {
  76. throw SyntaxError("Missing */");
  77. } else {
  78. i = index + 1;
  79. }
  80. } else {
  81. buffer += character;
  82. }
  83. break;
  84. // At-rule
  85. case "@":
  86. if (token.indexOf("@media", i) == i) {
  87. state = "atBlock";
  88. i += "media".length;
  89. buffer = "";
  90. break;
  91. } else if (state == "selector") {
  92. state = "atRule";
  93. }
  94. buffer += character;
  95. break;
  96. case "{":
  97. if (state == "selector" || state == "atRule") {
  98. styleRule = new CSSOM.CSSStyleRule;
  99. styleRule.selectorText = buffer.trim();
  100. buffer = "";
  101. state = "name";
  102. } else if (state == "atBlock") {
  103. mediaRule = new CSSOM.CSSMediaRule;
  104. mediaRule.media.mediaText = buffer.trim();
  105. currentScope = mediaRule;
  106. buffer = "";
  107. state = "selector";
  108. }
  109. break;
  110. case ":":
  111. if (state == "name") {
  112. name = buffer.trim();
  113. buffer = "";
  114. state = "value";
  115. } else {
  116. buffer += character;
  117. }
  118. break;
  119. case "!":
  120. if (state == "value" && token.indexOf("!important", i) === i) {
  121. priority = "important";
  122. i += "important".length;
  123. } else {
  124. buffer += character;
  125. }
  126. break;
  127. case ";":
  128. if (state == "value") {
  129. styleRule.style.setProperty(name, buffer.trim(), priority);
  130. priority = "";
  131. buffer = "";
  132. state = "name";
  133. } else if (state == "atRule") {
  134. buffer = "";
  135. state = "selector";
  136. } else {
  137. buffer += character;
  138. }
  139. break;
  140. case "}":
  141. if (state == "value") {
  142. styleRule.style.setProperty(name, buffer.trim(), priority);
  143. priority = "";
  144. buffer = "";
  145. currentScope.cssRules.push(styleRule);
  146. } else if (state == "name") {
  147. currentScope.cssRules.push(styleRule);
  148. buffer = "";
  149. } else if (state == "selector") {
  150. // End of media rule.
  151. // Nesting of media rules isn't supported
  152. if (!mediaRule) {
  153. throw "unexpected }";
  154. }
  155. styleSheet.cssRules.push(mediaRule);
  156. currentScope = styleSheet;
  157. buffer = "";
  158. }
  159. state = "selector";
  160. break;
  161. default:
  162. buffer += character;
  163. break;
  164. }
  165. }
  166. return styleSheet;
  167. };
  168. //.CommonJS
  169. exports.parse = CSSOM.parse;
  170. ///CommonJS