4 description: Standalone CSS3 Selector parser
19 var parse = function(expression, isReversed){
20 if (!expression) 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];
26 parsed = {Slick: true, expressions: [], raw: expression, reverse: function(){
27 return parse(this.raw, true);
30 while (expression != (expression = expression.replace(regexp, parser)));
31 parsed.length = parsed.expressions.length;
32 return currentCache[expression] = (reversed) ? reverse(parsed) : parsed;
35 var reverseCombinator = function(combinator){
36 if (combinator === '!') return ' ';
37 else if (combinator === ' ') return '!';
38 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
39 else return '!' + combinator;
42 var reverse = function(expression){
43 var expressions = expression.expressions;
44 for (var i = 0; i < expressions.length; i++){
45 var exp = expressions[i];
46 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
48 for (var j = 0; j < exp.length; j++){
50 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
51 cexp.combinator = cexp.reverseCombinator;
52 delete cexp.reverseCombinator;
55 exp.reverse().push(last);
60 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
61 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, "\\$&");
64 var regexp = new RegExp(
67 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
70 \\s* ( , ) \\s* # Separator \n\
71 | \\s* ( <combinator>+ ) \\s* # Combinator \n\
72 | ( \\s+ ) # CombinatorChildren \n\
73 | ( <unicode>+ | \\* ) # Tag \n\
74 | \\# ( <unicode>+ ) # ID \n\
75 | \\. ( <unicode>+ ) # ClassName \n\
78 \\s* (<unicode1>+) (?: \
79 \\s* ([*^$!~|]?=) (?: \
86 | :+ ( <unicode>+ )(?:\
88 ([\"']?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\12\
93 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|:+(<unicode>+)(?:\\((?:([\"']?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\12)\\))?)"
94 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
95 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
96 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
119 if (separator || separatorIndex === -1){
120 parsed.expressions[++separatorIndex] = [];
121 combinatorIndex = -1;
122 if (separator) return '';
125 if (combinator || combinatorChildren || combinatorIndex === -1){
126 combinator = combinator || ' ';
127 var currentSeparator = parsed.expressions[separatorIndex];
128 if (reversed && currentSeparator[combinatorIndex])
129 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
130 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
133 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
136 currentParsed.tag = tagName.replace(reUnescape, '');
139 currentParsed.id = id.replace(reUnescape, '');
141 } else if (className){
142 className = className.replace(reUnescape, '');
144 if (!currentParsed.classList) currentParsed.classList = [];
145 if (!currentParsed.classes) currentParsed.classes = [];
146 currentParsed.classList.push(className);
147 currentParsed.classes.push({
149 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
152 } else if (pseudoClass){
153 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
155 if (!currentParsed.pseudos) currentParsed.pseudos = [];
156 currentParsed.pseudos.push({
157 key: pseudoClass.replace(reUnescape, ''),
158 value: pseudoClassValue
161 } else if (attributeKey){
162 attributeKey = attributeKey.replace(reUnescape, '');
163 attributeValue = (attributeValue || '').replace(reUnescape, '');
167 switch (attributeOperator){
168 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
169 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
170 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
171 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
172 case '=' : test = function(value){
173 return attributeValue == value;
175 case '*=' : test = function(value){
176 return value && value.indexOf(attributeValue) > -1;
178 case '!=' : test = function(value){
179 return attributeValue != value;
181 default : test = function(value){
186 if (!test) test = function(value){
187 return value && regexp.test(value);
190 if (!currentParsed.attributes) currentParsed.attributes = [];
191 currentParsed.attributes.push({
193 operator: attributeOperator,
194 value: attributeValue,
205 var Slick = (this.Slick || {});
207 Slick.parse = function(expression){
208 return parse(expression);
211 Slick.escapeRegExp = escapeRegExp;
213 if (!this.Slick) this.Slick = Slick;
215 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);