//.CommonJS var CSSOM = { CSSStyleSheet: require("./CSSStyleSheet").CSSStyleSheet, CSSStyleRule: require("./CSSStyleRule").CSSStyleRule, CSSImportRule: require("./CSSImportRule").CSSImportRule, CSSMediaRule: require("./CSSMediaRule").CSSMediaRule }; ///CommonJS CSSOM.Parser = function Parser() {}; /** * @param {string} cssText * @param {Object} options */ CSSOM.Parser.prototype.parseStyleSheet = function(cssText, options) { options = options || {}; var i = options.startIndex || 0; for (var character; character = token.charAt(i); i++) { switch (character) { case " ": case "\t": case "\r": case "\n": case "\f": if (SIGNIFICANT_WHITESPACE[state]) { buffer += character; } break; } }; CSSOM.Parser.prototype.parse = function(token, options) { options = options || {}; var i = options.startIndex || 0; this.styleSheetStart(i); /** "before-selector" or "selector" or "atRule" or "atBlock" or "before-name" or "name" or "before-value" or "value" */ var state = options.state || "before-selector"; var index; var j = i; var buffer = ""; var SIGNIFICANT_WHITESPACE = { "selector": true, "value": true, "atRule": true, "importRule-begin": true, "importRule": true, "atBlock": true }; var styleSheet = new CSSOM.CSSStyleSheet; // @type CSSStyleSheet|CSSMediaRule var currentScope = styleSheet; var selector, name, value, priority="", styleRule, mediaRule, importRule; var declarationStarts; var declarationEnds; for (var character; character = token.charAt(i); i++) { switch (character) { case " ": case "\t": case "\r": case "\n": case "\f": if (SIGNIFICANT_WHITESPACE[state]) { buffer += character; } break; // String case '"': j = i + 1; index = token.indexOf('"', j) + 1; if (!index) { throw '" is missing'; } buffer += token.slice(i, index); i = index - 1; if (state == 'before-value') { state = 'value'; } break; case "'": j = i + 1; index = token.indexOf("'", j) + 1; if (!index) { throw "' is missing"; } buffer += token.slice(i, index); i = index - 1; switch (state) { case 'before-value': state = 'value'; break; case 'importRule-begin': state = 'importRule'; break; } break; // Comment case "/": if (token.charAt(i + 1) == "*") { i += 2; index = token.indexOf("*/", i); if (index == -1) { throw SyntaxError("Missing */"); } else { i = index + 1; } } else { buffer += character; } if (state == "importRule-begin") { buffer += " "; state = "importRule"; } break; // At-rule case "@": if (token.indexOf("@media", i) == i) { state = "atBlock"; mediaRule = new CSSOM.CSSMediaRule; mediaRule.__starts = i; i += "media".length; buffer = ""; break; } else if (token.indexOf("@import", i) == i) { state = "importRule-begin"; i += "import".length; buffer += "@import"; break; } else if (state == "selector") { state = "atRule"; } buffer += character; break; case "{": if (state == "selector" || state == "atRule") { this.selectorEnd(i, buffer); buffer = ""; state = "before-name"; } else if (state == "atBlock") { mediaRule.media.mediaText = buffer.trim(); currentScope = mediaRule; buffer = ""; state = "before-selector"; } break; case ":": if (state == "name") { name = buffer; buffer = ""; state = "before-value"; } else { buffer += character; } break; case '(': if (state == 'value') { index = token.indexOf(')', i + 1); if (index == -1) { throw i + ': unclosed "("'; } buffer += token.slice(i, index + 1); i = index; } else { buffer += character; } break; case "!": if (state == "value" && token.indexOf("!important", i) === i) { priority = "important"; i += "important".length; } else { buffer += character; } break; case ";": switch (state) { case "value": this.declarationEnd(i, name, buffer, priority); priority = ""; buffer = ""; state = "before-name"; break; case "atRule": buffer = ""; state = "before-selector"; break; case "importRule": importRule = new CSSOM.CSSImportRule; importRule.cssText = buffer + character; currentScope.cssRules.push(importRule); buffer = ""; state = "before-selector"; break; default: buffer += character; break; } break; case "}": switch (state) { case "value": this.declarationEnd(i, name, buffer, priority); // fall down case "before-name": this.styleRuleEnd(i); buffer = ""; break; case "name": throw i + ": Oops"; break; case "before-selector": case "selector": // End of media rule. // Nesting rules aren't supported yet if (!mediaRule) { throw "unexpected }"; } mediaRule.__ends = i + 1; styleSheet.cssRules.push(mediaRule); currentScope = styleSheet; buffer = ""; break; } state = "before-selector"; break; default: switch (state) { case "before-selector": this.styleRuleStart(i); state = "selector"; break; case "before-name": state = "name"; break; case "before-value": state = "value"; break; case "importRule-begin": state = "importRule"; break; } buffer += character; break; } } return styleSheet; }; CSSOM.Parser.prototype.compile = function() { var handlers = { styleSheetStart: this.styleSheetStart, styleRuleStart: this.styleRuleStart, selectorEnd: this.selectorEnd, declarationEnd: this.declarationEnd, styleRuleEnd: this.styleRuleEnd, styleSheetEnd: this.styleSheetEnd }; var parser = this.parse.toString(); for (var key in handlers) { if (!handlers.hasOwnProperty(key)) { continue; } parser = parser.replace(new RegExp('^.*' + key + '.*$', 'gm'), handlers[key].toString() .replace(/^function.+$/m, '') .replace(/^}/m, '')) .replace(/this\.?/g, ''); } return parser; }; CSSOM.Parser.prototype.styleSheetStart = function(i) { console.log('styleSheetStart', i); this.styleSheet = new CSSOM.CSSStyleSheet; this.scopeRules = this.styleSheet.cssRules; }; CSSOM.Parser.prototype.styleRuleStart = function(i) { console.log('styleRuleStart', i); this.styleRule = new CSSOM.CSSStyleRule; this.styleRule._start = i; }; CSSOM.Parser.prototype.selectorEnd = function(i, buffer) { this.styleRule.selectorText = buffer.trimRight(); this.styleRule.style._start = i; }; CSSOM.Parser.prototype.declarationEnd = function(name, value, priority, startIndex, endIndex) { console.log('declarationEnd', name, value, priority, startIndex, endIndex); }; CSSOM.Parser.prototype.styleRuleEnd = function(i) { this.styleRule._end = i; this.scopeRules.push(this.styleRule); }; CSSOM.Parser.prototype.styleSheetEnd = function(i) { return this.styleSheet; }; /* Parser.prototype.nameStart = function(i) { this.nameStartIndex = i; }; Parser.prototype.nameEnd = function(i, buffer) { this.name = buffer.trimRight(); this.nameEndIndex = this.nameStartIndex + this.name.length; }; Parser.prototype.valueStart = function(i) { this.valueStartIndex = i; }; Parser.prototype.valueEnd = function(i, buffer) { var value = buffer.trimRight(); this.styleRule.style.add(this.name, value, this.nameStartIndex, this.nameEndIndex, this.valueStartIndex, this.valueStartIndex + value.length); }; */ //.CommonJS exports.Parser = CSSOM.Parser; ///CommonJS