4 description: Standalone CSS3 Selector parser
19 var parse = function(expression, isReversed){
20 if (expression == null) return null;
21 if (expression.Slick === true) return expression;
22 expression = ('' + expression).replace(/^\s+|\s+$/g, '');
23 reversed = !!isReversed;
24 var currentCache = (reversed) ? reverseCache : cache;
25 if (currentCache[expression]) return currentCache[expression];
31 return parse(this.raw, true);
35 while (expression != (expression = expression.replace(regexp, parser)));
36 parsed.length = parsed.expressions.length;
37 return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
40 var reverseCombinator = function(combinator){
41 if (combinator === '!') return ' ';
42 else if (combinator === ' ') return '!';
43 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
44 else return '!' + combinator;
47 var reverse = function(expression){
48 var expressions = expression.expressions;
49 for (var i = 0; i < expressions.length; i++){
50 var exp = expressions[i];
51 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
53 for (var j = 0; j < exp.length; j++){
55 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
56 cexp.combinator = cexp.reverseCombinator;
57 delete cexp.reverseCombinator;
60 exp.reverse().push(last);
65 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
66 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
71 var regexp = new RegExp(
74 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
77 \\s* ( , ) \\s* # Separator \n\
78 | \\s* ( <combinator>+ ) \\s* # Combinator \n\
79 | ( \\s+ ) # CombinatorChildren \n\
80 | ( <unicode>+ | \\* ) # Tag \n\
81 | \\# ( <unicode>+ ) # ID \n\
82 | \\. ( <unicode>+ ) # ClassName \n\
85 \\s* (<unicode1>+) (?: \
86 \\s* ([*^$!~|]?=) (?: \
93 | :+ ( <unicode>+ )(?:\
95 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
100 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
101 .replace(/<combinator>/, '[' + escapeRegExp('>+~`!@$%^&={}\\;</') + ']')
102 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
103 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
125 pseudoClassQuotedValue,
128 if (separator || separatorIndex === -1){
129 parsed.expressions[++separatorIndex] = [];
130 combinatorIndex = -1;
131 if (separator) return '';
134 if (combinator || combinatorChildren || combinatorIndex === -1){
135 combinator = combinator || ' ';
136 var currentSeparator = parsed.expressions[separatorIndex];
137 if (reversed && currentSeparator[combinatorIndex])
138 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
139 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
142 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
145 currentParsed.tag = tagName.replace(reUnescape, '');
148 currentParsed.id = id.replace(reUnescape, '');
150 } else if (className){
151 className = className.replace(reUnescape, '');
153 if (!currentParsed.classList) currentParsed.classList = [];
154 if (!currentParsed.classes) currentParsed.classes = [];
155 currentParsed.classList.push(className);
156 currentParsed.classes.push({
158 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
161 } else if (pseudoClass){
162 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
163 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
165 if (!currentParsed.pseudos) currentParsed.pseudos = [];
166 currentParsed.pseudos.push({
167 key: pseudoClass.replace(reUnescape, ''),
168 value: pseudoClassValue,
169 type: pseudoMarker.length == 1 ? 'class' : 'element'
172 } else if (attributeKey){
173 attributeKey = attributeKey.replace(reUnescape, '');
174 attributeValue = (attributeValue || '').replace(reUnescape, '');
178 switch (attributeOperator){
179 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
180 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
181 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
182 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
183 case '=' : test = function(value){
184 return attributeValue == value;
186 case '*=' : test = function(value){
187 return value && value.indexOf(attributeValue) > -1;
189 case '!=' : test = function(value){
190 return attributeValue != value;
192 default : test = function(value){
197 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
201 if (!test) test = function(value){
202 return value && regexp.test(value);
205 if (!currentParsed.attributes) currentParsed.attributes = [];
206 currentParsed.attributes.push({
208 operator: attributeOperator,
209 value: attributeValue,
220 var Slick = (this.Slick || {});
222 Slick.parse = function(expression){
223 return parse(expression);
226 Slick.escapeRegExp = escapeRegExp;
228 if (!this.Slick) this.Slick = Slick;
230 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);