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);
|