465 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			465 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| //.CommonJS
 | |
| var CSSOM = {};
 | |
| ///CommonJS
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @param {string} token
 | |
|  */
 | |
| CSSOM.parse = function parse(token) {
 | |
| 
 | |
| 	var i = 0;
 | |
| 
 | |
| 	/**
 | |
| 		"before-selector" or
 | |
| 		"selector" or
 | |
| 		"atRule" or
 | |
| 		"atBlock" or
 | |
| 		"conditionBlock" or
 | |
| 		"before-name" or
 | |
| 		"name" or
 | |
| 		"before-value" or
 | |
| 		"value"
 | |
| 	*/
 | |
| 	var state = "before-selector";
 | |
| 
 | |
| 	var index;
 | |
| 	var buffer = "";
 | |
| 	var valueParenthesisDepth = 0;
 | |
| 
 | |
| 	var SIGNIFICANT_WHITESPACE = {
 | |
| 		"selector": true,
 | |
| 		"value": true,
 | |
| 		"value-parenthesis": true,
 | |
| 		"atRule": true,
 | |
| 		"importRule-begin": true,
 | |
| 		"importRule": true,
 | |
| 		"atBlock": true,
 | |
| 		"conditionBlock": true,
 | |
| 		'documentRule-begin': true
 | |
| 	};
 | |
| 
 | |
| 	var styleSheet = new CSSOM.CSSStyleSheet();
 | |
| 
 | |
| 	// @type CSSStyleSheet|CSSMediaRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
 | |
| 	var currentScope = styleSheet;
 | |
| 
 | |
| 	// @type CSSMediaRule|CSSSupportsRule|CSSKeyframesRule|CSSDocumentRule
 | |
| 	var parentRule;
 | |
| 
 | |
| 	var ancestorRules = [];
 | |
| 	var hasAncestors = false;
 | |
| 	var prevScope;
 | |
| 
 | |
| 	var name, priority="", styleRule, mediaRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule;
 | |
| 
 | |
| 	var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g;
 | |
| 
 | |
| 	var parseError = function(message) {
 | |
| 		var lines = token.substring(0, i).split('\n');
 | |
| 		var lineCount = lines.length;
 | |
| 		var charCount = lines.pop().length + 1;
 | |
| 		var error = new Error(message + ' (line ' + lineCount + ', char ' + charCount + ')');
 | |
| 		error.line = lineCount;
 | |
| 		/* jshint sub : true */
 | |
| 		error['char'] = charCount;
 | |
| 		error.styleSheet = styleSheet;
 | |
| 		throw error;
 | |
| 	};
 | |
| 
 | |
| 	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 '"':
 | |
| 			index = i + 1;
 | |
| 			do {
 | |
| 				index = token.indexOf('"', index) + 1;
 | |
| 				if (!index) {
 | |
| 					parseError('Unmatched "');
 | |
| 				}
 | |
| 			} while (token[index - 2] === '\\');
 | |
| 			buffer += token.slice(i, index);
 | |
| 			i = index - 1;
 | |
| 			switch (state) {
 | |
| 				case 'before-value':
 | |
| 					state = 'value';
 | |
| 					break;
 | |
| 				case 'importRule-begin':
 | |
| 					state = 'importRule';
 | |
| 					break;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case "'":
 | |
| 			index = i + 1;
 | |
| 			do {
 | |
| 				index = token.indexOf("'", index) + 1;
 | |
| 				if (!index) {
 | |
| 					parseError("Unmatched '");
 | |
| 				}
 | |
| 			} while (token[index - 2] === '\\');
 | |
| 			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) {
 | |
| 					parseError("Missing */");
 | |
| 				} else {
 | |
| 					i = index + 1;
 | |
| 				}
 | |
| 			} else {
 | |
| 				buffer += character;
 | |
| 			}
 | |
| 			if (state === "importRule-begin") {
 | |
| 				buffer += " ";
 | |
| 				state = "importRule";
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		// At-rule
 | |
| 		case "@":
 | |
| 			if (token.indexOf("@-moz-document", i) === i) {
 | |
| 				state = "documentRule-begin";
 | |
| 				documentRule = new CSSOM.CSSDocumentRule();
 | |
| 				documentRule.__starts = i;
 | |
| 				i += "-moz-document".length;
 | |
| 				buffer = "";
 | |
| 				break;
 | |
| 			} else if (token.indexOf("@media", i) === i) {
 | |
| 				state = "atBlock";
 | |
| 				mediaRule = new CSSOM.CSSMediaRule();
 | |
| 				mediaRule.__starts = i;
 | |
| 				i += "media".length;
 | |
| 				buffer = "";
 | |
| 				break;
 | |
| 			} else if (token.indexOf("@supports", i) === i) {
 | |
| 				state = "conditionBlock";
 | |
| 				supportsRule = new CSSOM.CSSSupportsRule();
 | |
| 				supportsRule.__starts = i;
 | |
| 				i += "supports".length;
 | |
| 				buffer = "";
 | |
| 				break;
 | |
| 			} else if (token.indexOf("@host", i) === i) {
 | |
| 				state = "hostRule-begin";
 | |
| 				i += "host".length;
 | |
| 				hostRule = new CSSOM.CSSHostRule();
 | |
| 				hostRule.__starts = i;
 | |
| 				buffer = "";
 | |
| 				break;
 | |
| 			} else if (token.indexOf("@import", i) === i) {
 | |
| 				state = "importRule-begin";
 | |
| 				i += "import".length;
 | |
| 				buffer += "@import";
 | |
| 				break;
 | |
| 			} else if (token.indexOf("@font-face", i) === i) {
 | |
| 				state = "fontFaceRule-begin";
 | |
| 				i += "font-face".length;
 | |
| 				fontFaceRule = new CSSOM.CSSFontFaceRule();
 | |
| 				fontFaceRule.__starts = i;
 | |
| 				buffer = "";
 | |
| 				break;
 | |
| 			} else {
 | |
| 				atKeyframesRegExp.lastIndex = i;
 | |
| 				var matchKeyframes = atKeyframesRegExp.exec(token);
 | |
| 				if (matchKeyframes && matchKeyframes.index === i) {
 | |
| 					state = "keyframesRule-begin";
 | |
| 					keyframesRule = new CSSOM.CSSKeyframesRule();
 | |
| 					keyframesRule.__starts = i;
 | |
| 					keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
 | |
| 					i += matchKeyframes[0].length - 1;
 | |
| 					buffer = "";
 | |
| 					break;
 | |
| 				} else if (state === "selector") {
 | |
| 					state = "atRule";
 | |
| 				}
 | |
| 			}
 | |
| 			buffer += character;
 | |
| 			break;
 | |
| 
 | |
| 		case "{":
 | |
| 			if (state === "selector" || state === "atRule") {
 | |
| 				styleRule.selectorText = buffer.trim();
 | |
| 				styleRule.style.__starts = i;
 | |
| 				buffer = "";
 | |
| 				state = "before-name";
 | |
| 			} else if (state === "atBlock") {
 | |
| 				mediaRule.media.mediaText = buffer.trim();
 | |
| 
 | |
| 				if (parentRule) {
 | |
| 					ancestorRules.push(parentRule);
 | |
| 				}
 | |
| 
 | |
| 				currentScope = parentRule = mediaRule;
 | |
| 				mediaRule.parentStyleSheet = styleSheet;
 | |
| 				buffer = "";
 | |
| 				state = "before-selector";
 | |
| 			} else if (state === "conditionBlock") {
 | |
| 				supportsRule.conditionText = buffer.trim();
 | |
| 
 | |
| 				if (parentRule) {
 | |
| 					ancestorRules.push(parentRule);
 | |
| 				}
 | |
| 
 | |
| 				currentScope = parentRule = supportsRule;
 | |
| 				supportsRule.parentStyleSheet = styleSheet;
 | |
| 				buffer = "";
 | |
| 				state = "before-selector";
 | |
| 			} else if (state === "hostRule-begin") {
 | |
| 				if (parentRule) {
 | |
| 					ancestorRules.push(parentRule);
 | |
| 				}
 | |
| 
 | |
| 				currentScope = parentRule = hostRule;
 | |
| 				hostRule.parentStyleSheet = styleSheet;
 | |
| 				buffer = "";
 | |
| 				state = "before-selector";
 | |
| 			} else if (state === "fontFaceRule-begin") {
 | |
| 				if (parentRule) {
 | |
| 					ancestorRules.push(parentRule);
 | |
| 					fontFaceRule.parentRule = parentRule;
 | |
| 				}
 | |
| 				fontFaceRule.parentStyleSheet = styleSheet;
 | |
| 				styleRule = fontFaceRule;
 | |
| 				buffer = "";
 | |
| 				state = "before-name";
 | |
| 			} else if (state === "keyframesRule-begin") {
 | |
| 				keyframesRule.name = buffer.trim();
 | |
| 				if (parentRule) {
 | |
| 					ancestorRules.push(parentRule);
 | |
| 					keyframesRule.parentRule = parentRule;
 | |
| 				}
 | |
| 				keyframesRule.parentStyleSheet = styleSheet;
 | |
| 				currentScope = parentRule = keyframesRule;
 | |
| 				buffer = "";
 | |
| 				state = "keyframeRule-begin";
 | |
| 			} else if (state === "keyframeRule-begin") {
 | |
| 				styleRule = new CSSOM.CSSKeyframeRule();
 | |
| 				styleRule.keyText = buffer.trim();
 | |
| 				styleRule.__starts = i;
 | |
| 				buffer = "";
 | |
| 				state = "before-name";
 | |
| 			} else if (state === "documentRule-begin") {
 | |
| 				// FIXME: what if this '{' is in the url text of the match function?
 | |
| 				documentRule.matcher.matcherText = buffer.trim();
 | |
| 				if (parentRule) {
 | |
| 					ancestorRules.push(parentRule);
 | |
| 					documentRule.parentRule = parentRule;
 | |
| 				}
 | |
| 				currentScope = parentRule = documentRule;
 | |
| 				documentRule.parentStyleSheet = styleSheet;
 | |
| 				buffer = "";
 | |
| 				state = "before-selector";
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case ":":
 | |
| 			if (state === "name") {
 | |
| 				name = buffer.trim();
 | |
| 				buffer = "";
 | |
| 				state = "before-value";
 | |
| 			} else {
 | |
| 				buffer += character;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case "(":
 | |
| 			if (state === 'value') {
 | |
| 				// ie css expression mode
 | |
| 				if (buffer.trim() === 'expression') {
 | |
| 					var info = (new CSSOM.CSSValueExpression(token, i)).parse();
 | |
| 
 | |
| 					if (info.error) {
 | |
| 						parseError(info.error);
 | |
| 					} else {
 | |
| 						buffer += info.expression;
 | |
| 						i = info.idx;
 | |
| 					}
 | |
| 				} else {
 | |
| 					state = 'value-parenthesis';
 | |
| 					//always ensure this is reset to 1 on transition
 | |
| 					//from value to value-parenthesis
 | |
| 					valueParenthesisDepth = 1;
 | |
| 					buffer += character;
 | |
| 				}
 | |
| 			} else if (state === 'value-parenthesis') {
 | |
| 				valueParenthesisDepth++;
 | |
| 				buffer += character;
 | |
| 			} else {
 | |
| 				buffer += character;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case ")":
 | |
| 			if (state === 'value-parenthesis') {
 | |
| 				valueParenthesisDepth--;
 | |
| 				if (valueParenthesisDepth === 0) state = 'value';
 | |
| 			}
 | |
| 			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":
 | |
| 					styleRule.style.setProperty(name, buffer.trim(), priority);
 | |
| 					priority = "";
 | |
| 					buffer = "";
 | |
| 					state = "before-name";
 | |
| 					break;
 | |
| 				case "atRule":
 | |
| 					buffer = "";
 | |
| 					state = "before-selector";
 | |
| 					break;
 | |
| 				case "importRule":
 | |
| 					importRule = new CSSOM.CSSImportRule();
 | |
| 					importRule.parentStyleSheet = importRule.styleSheet.parentStyleSheet = styleSheet;
 | |
| 					importRule.cssText = buffer + character;
 | |
| 					styleSheet.cssRules.push(importRule);
 | |
| 					buffer = "";
 | |
| 					state = "before-selector";
 | |
| 					break;
 | |
| 				default:
 | |
| 					buffer += character;
 | |
| 					break;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case "}":
 | |
| 			switch (state) {
 | |
| 				case "value":
 | |
| 					styleRule.style.setProperty(name, buffer.trim(), priority);
 | |
| 					priority = "";
 | |
| 					/* falls through */
 | |
| 				case "before-name":
 | |
| 				case "name":
 | |
| 					styleRule.__ends = i + 1;
 | |
| 					if (parentRule) {
 | |
| 						styleRule.parentRule = parentRule;
 | |
| 					}
 | |
| 					styleRule.parentStyleSheet = styleSheet;
 | |
| 					currentScope.cssRules.push(styleRule);
 | |
| 					buffer = "";
 | |
| 					if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
 | |
| 						state = "keyframeRule-begin";
 | |
| 					} else {
 | |
| 						state = "before-selector";
 | |
| 					}
 | |
| 					break;
 | |
| 				case "keyframeRule-begin":
 | |
| 				case "before-selector":
 | |
| 				case "selector":
 | |
| 					// End of media/supports/document rule.
 | |
| 					if (!parentRule) {
 | |
| 						parseError("Unexpected }");
 | |
| 					}
 | |
| 
 | |
| 					// Handle rules nested in @media or @supports
 | |
| 					hasAncestors = ancestorRules.length > 0;
 | |
| 
 | |
| 					while (ancestorRules.length > 0) {
 | |
| 						parentRule = ancestorRules.pop();
 | |
| 
 | |
| 						if (
 | |
| 							parentRule.constructor.name === "CSSMediaRule"
 | |
| 							|| parentRule.constructor.name === "CSSSupportsRule"
 | |
| 						) {
 | |
| 							prevScope = currentScope;
 | |
| 							currentScope = parentRule;
 | |
| 							currentScope.cssRules.push(prevScope);
 | |
| 							break;
 | |
| 						}
 | |
| 
 | |
| 						if (ancestorRules.length === 0) {
 | |
| 							hasAncestors = false;
 | |
| 						}
 | |
| 					}
 | |
| 					
 | |
| 					if (!hasAncestors) {
 | |
| 						currentScope.__ends = i + 1;
 | |
| 						styleSheet.cssRules.push(currentScope);
 | |
| 						currentScope = styleSheet;
 | |
| 						parentRule = null;
 | |
| 					}
 | |
| 
 | |
| 					buffer = "";
 | |
| 					state = "before-selector";
 | |
| 					break;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			switch (state) {
 | |
| 				case "before-selector":
 | |
| 					state = "selector";
 | |
| 					styleRule = new CSSOM.CSSStyleRule();
 | |
| 					styleRule.__starts = i;
 | |
| 					break;
 | |
| 				case "before-name":
 | |
| 					state = "name";
 | |
| 					break;
 | |
| 				case "before-value":
 | |
| 					state = "value";
 | |
| 					break;
 | |
| 				case "importRule-begin":
 | |
| 					state = "importRule";
 | |
| 					break;
 | |
| 			}
 | |
| 			buffer += character;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return styleSheet;
 | |
| };
 | |
| 
 | |
| 
 | |
| //.CommonJS
 | |
| exports.parse = CSSOM.parse;
 | |
| // The following modules cannot be included sooner due to the mutual dependency with parse.js
 | |
| CSSOM.CSSStyleSheet = require("./CSSStyleSheet").CSSStyleSheet;
 | |
| CSSOM.CSSStyleRule = require("./CSSStyleRule").CSSStyleRule;
 | |
| CSSOM.CSSImportRule = require("./CSSImportRule").CSSImportRule;
 | |
| CSSOM.CSSMediaRule = require("./CSSMediaRule").CSSMediaRule;
 | |
| CSSOM.CSSSupportsRule = require("./CSSSupportsRule").CSSSupportsRule;
 | |
| CSSOM.CSSFontFaceRule = require("./CSSFontFaceRule").CSSFontFaceRule;
 | |
| CSSOM.CSSHostRule = require("./CSSHostRule").CSSHostRule;
 | |
| CSSOM.CSSStyleDeclaration = require('./CSSStyleDeclaration').CSSStyleDeclaration;
 | |
| CSSOM.CSSKeyframeRule = require('./CSSKeyframeRule').CSSKeyframeRule;
 | |
| CSSOM.CSSKeyframesRule = require('./CSSKeyframesRule').CSSKeyframesRule;
 | |
| CSSOM.CSSValueExpression = require('./CSSValueExpression').CSSValueExpression;
 | |
| CSSOM.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
 | |
| ///CommonJS
 |