195 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
| ---
 | |
| name    : SheetParser.CSS
 | |
| 
 | |
| authors   : Thomas Aylott
 | |
| copyright : © 2010 Thomas Aylott
 | |
| license   : MIT
 | |
| 
 | |
| provides : SheetParser.CSS
 | |
| requires : combineRegExp
 | |
| ...
 | |
| */
 | |
| ;(function(exports){
 | |
| 	
 | |
| 
 | |
| /*<depend>*/
 | |
| var UNDEF = {undefined:1}
 | |
| if (!exports.SheetParser) exports.SheetParser = {}
 | |
| 
 | |
| /*<CommonJS>*/
 | |
| var combineRegExp = UNDEF[typeof require]
 | |
| 	?	exports.combineRegExp
 | |
| 	:	require('./sg-regex-tools').combineRegExp
 | |
| var SheetParser = exports.SheetParser
 | |
| /*</CommonJS>*/
 | |
| 
 | |
| /*<debug>*/;if (UNDEF[typeof combineRegExp]) throw new Error('Missing required function: "combineRegExp"');/*</debug>*/
 | |
| /*</depend>*/
 | |
| 
 | |
| 
 | |
| var CSS = SheetParser.CSS = {version: '1.0.2 dev'}
 | |
| 
 | |
| CSS.trim = trim
 | |
| function trim(str){
 | |
| 	// http://blog.stevenlevithan.com/archives/faster-trim-javascript
 | |
| 	var	str = (''+str).replace(/^\s\s*/, ''),
 | |
| 		ws = /\s/,
 | |
| 		i = str.length;
 | |
| 	while (ws.test(str.charAt(--i)));
 | |
| 	return str.slice(0, i + 1);
 | |
| }
 | |
| 
 | |
| CSS.camelCase = function(string){
 | |
| 	return ('' + string).replace(camelCaseSearch, camelCaseReplace)
 | |
| }
 | |
| var camelCaseSearch = /-\D/g
 | |
| function camelCaseReplace(match){
 | |
| 	return match.charAt(1).toUpperCase()
 | |
| }
 | |
| 
 | |
| CSS.parse = function(cssText){
 | |
| 	var	found
 | |
| 	,	rule
 | |
| 	,	rules = {length:0}
 | |
| 	,	keyIndex = -1
 | |
| 	,	regex = this.parser
 | |
| 	,	names = CSS.parser.names
 | |
| 	,	i,r,l
 | |
| 	,	ruleCount
 | |
| 	
 | |
| 	rules.cssText = cssText = trim(cssText)
 | |
| 	
 | |
| 	// strip comments
 | |
| 	cssText = cssText.replace(CSS.comment, '');
 | |
| 	
 | |
| 	regex.lastIndex = 0
 | |
| 	while ((found = regex.exec(cssText))){
 | |
| 		// avoid an infinite loop on zero-length keys
 | |
| 		if (regex.lastIndex == found.index) ++ regex.lastIndex
 | |
| 		
 | |
| 		// key:value
 | |
| 		if (found[names._key]){
 | |
| 			rules[rules.length ++] = found[names._key]
 | |
| 			rules[found[names._key]] = found[names._value]
 | |
| 			rules[CSS.camelCase(found[names._key])] = found[names._value]
 | |
| 			continue
 | |
| 		}
 | |
| 		
 | |
| 		rules[rules.length++] = rule = {}
 | |
| 		for (i = 0, l = names.length; i < l; ++i){
 | |
| 			if (!(names[i-1] && found[i])) continue
 | |
| 			rule[names[i-1]] = trim(found[i])
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	var atKey, atRule, atList, atI
 | |
| 	for (i = 0, l = rules.length; i < l; ++i){
 | |
| 		if (!rules[i]) continue
 | |
| 		
 | |
| 		if (rules[i]._style_cssText){
 | |
| 			rules[i].style = CSS.parse(rules[i]._style_cssText)
 | |
| 			delete rules[i]._style_cssText
 | |
| 		}
 | |
| 		
 | |
| 		// _atKey/_atValue
 | |
| 		if (atKey = rules[i]._atKey){
 | |
| 			atKey = CSS.camelCase(atKey)
 | |
| 			atRule = {length:0}
 | |
| 			rules[i][atKey] = atRule
 | |
| 			atRule["_source"] =
 | |
| 			atRule[atKey + "Text"] = rules[i]._atValue
 | |
| 			atList = ('' + rules[i]._atValue).split(/,\s*/)
 | |
| 			for (atI = 0; atI < atList.length; ++atI){
 | |
| 				atRule[atRule.length ++] = atList[atI]
 | |
| 			}
 | |
| 			rules[i].length = 1
 | |
| 			rules[i][0] = atKey
 | |
| 			delete rules[i]._atKey
 | |
| 			delete rules[i]._atValue
 | |
| 		}
 | |
| 		
 | |
| 		if (rules[i].style)
 | |
| 		for (ruleCount = -1, r = -1, rule; rule = rules[i].style[++r];){
 | |
| 			if (typeof rule == 'string') continue
 | |
| 			rules[i][r] = (rules[i].cssRules || (rules[i].cssRules = {}))[++ ruleCount]  = rule
 | |
| 			rules[i].cssRules.length = ruleCount + 1
 | |
| 			rules[i].rules = rules[i].cssRules
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	return rules
 | |
| }
 | |
| 
 | |
| var x = combineRegExp
 | |
| var OR = '|'
 | |
| 
 | |
| ;(CSS.at = x(/\s*@([-a-zA-Z0-9]+)\s+(([\w-]+)?[^;{]*)/))
 | |
| .names=[         '_atKey',           '_atValue', 'name']
 | |
| 
 | |
| CSS.atRule = x([CSS.at, ';'])
 | |
| 
 | |
| ;(CSS.keyValue_key = x(/([-a-zA-Z0-9]+)/))
 | |
| .names=[                '_key']
 | |
| 
 | |
| ;(CSS.keyValue_value_end = x(/(?:;|(?=\})|$)/))
 | |
| 
 | |
| ;(CSS.notString = x(/[^"']+/))
 | |
| ;(CSS.stringSingle = x(/"(?:[^"]|\\")*"/))
 | |
| ;(CSS.stringDouble = x(/'(?:[^']|\\')*'/))
 | |
| ;(CSS.string = x(['(?:',CSS.stringSingle ,OR, CSS.stringDouble,')']))
 | |
| ;(CSS.propertyValue = x([/[^;}]+/, CSS.keyValue_value_end]))
 | |
| 
 | |
| var rRound = "(?:[^()]|\\((?:[^()]|\\((?:[^()]|\\((?:[^()]|\\([^()]*\\))*\\))*\\))*\\))"
 | |
| 
 | |
| ;(CSS.keyValue_value = x(
 | |
| [
 | |
| 	x(['((?:'
 | |
| 	,	CSS.stringSingle
 | |
| 	,	OR
 | |
| 	,	CSS.stringDouble
 | |
| 	,	OR
 | |
| 	,	"\\("+rRound+"*\\)"
 | |
| 	,	OR
 | |
| 	,	/[^;}()]/ // not a keyValue_value terminator
 | |
| 	,	')*)'
 | |
| 	])
 | |
| ,	CSS.keyValue_value_end
 | |
| ])).names = ['_value']
 | |
| 
 | |
| ;(CSS.keyValue = x([CSS.keyValue_key ,/\s*:\s*/, CSS.keyValue_value]))
 | |
| 
 | |
| ;(CSS.comment = x(/\/\*\s*((?:[^*]|\*(?!\/))*)\s*\*\//))
 | |
| .names=[                   'comment']
 | |
| 
 | |
| ;(CSS.selector = x(['(',/\s*(\d+%)\s*/,OR,'(?:',/[^{}'"()]|\([^)]*\)|\[[^\]]*\]/,')+',')']))
 | |
| .names=[    'selectorText','keyText']
 | |
| 
 | |
| var rCurly = "(?:[^{}]|\\{(?:[^{}]|\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\})*\\})"
 | |
| var rCurlyRound = "(?:[^{}()]+|\\{(?:[^{}()]+|\\{(?:[^{}()]+|\\{(?:[^{}()]+|\\{[^{}()]*\\})*\\})*\\})*\\})"
 | |
| 
 | |
| ;(CSS.block = x("\\{\\s*((?:"+"\\("+rRound+"*\\)|"+rCurly+")*)\\s*\\}"))
 | |
| .names=[              '_style_cssText']
 | |
| 
 | |
| CSS.selectorBlock = x([CSS.selector, CSS.block])
 | |
| 
 | |
| CSS.atBlock = x([CSS.at, CSS.block])
 | |
| 
 | |
| CSS.parser = x
 | |
| (
 | |
| 	[	x(CSS.comment)
 | |
| 	,	OR
 | |
| 	,	x(CSS.atBlock)
 | |
| 	,	OR
 | |
| 	,	x(CSS.atRule)
 | |
| 	,	OR
 | |
| 	,	x(CSS.selectorBlock)
 | |
| 	,	OR
 | |
| 	,	x(CSS.keyValue)
 | |
| 	]
 | |
| ,	'cssText'
 | |
| )
 | |
| 
 | |
| 
 | |
| })(typeof exports != 'undefined' ? exports : this);
 | 
