/* --- name : SheetParser.CSS authors : Thomas Aylott copyright : © 2010 Thomas Aylott license : MIT provides : SheetParser.CSS requires : combineRegExp ... */ ;(function(exports){ /**/ var UNDEF = {undefined:1} if (!exports.SheetParser) exports.SheetParser = {} /**/ var combineRegExp = (UNDEF[typeof module] || !module.exports) ? exports.combineRegExp : require('./sg-regex-tools').combineRegExp var SheetParser = exports.SheetParser /**/ /**/;if (UNDEF[typeof combineRegExp]) throw new Error('Missing required function: "combineRegExp"');/**/ /**/ 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);