@@ -38,15 +38,9 @@ CSSOM.CSSValueExpression.prototype.parse = function() {
3838 idx = this . _idx ;
3939
4040 var character = '' ,
41- STATES = {
42- LITERAL : 0 ,
43- STRING : 1 ,
44- REGEXP : 2
45- } ,
46- state = STATES . LITERAL ,
47- string_sep = '' ,
4841 expression = '' ,
4942 error = '' ,
43+ info ,
5044 paren = [ ] ;
5145
5246
@@ -61,66 +55,40 @@ CSSOM.CSSValueExpression.prototype.parse = function() {
6155
6256 switch ( character ) {
6357 case '(' :
64- if ( state == STATES . LITERAL ) {
65- paren . push ( character ) ;
66- }
58+ paren . push ( character ) ;
6759 expression += character ;
6860 break ;
6961
7062 case ')' :
71- if ( state == STATES . LITERAL ) {
72- paren . pop ( character ) ;
73- }
63+ paren . pop ( character ) ;
7464 expression += character ;
7565 break ;
7666
7767 case '/' :
78- if ( state == STATES . LITERAL ) {
79- var nextChar = token . charAt ( idx + 1 ) ,
80- regExp ;
81- if ( nextChar == '/' || nextChar == '*' ) { // comment
82- var commentEndChar ,
83- commentEndIdx ;
84-
85- if ( nextChar == '/' ) { // line comment
86- commentEndChar = '\n' ;
87- } else if ( nextChar == '*' ) { // block comment
88- commentEndChar = '*/' ;
89- }
90-
91- commentEndIdx = token . indexOf ( commentEndChar , idx + 1 + 1 ) ;
92- if ( commentEndIdx !== - 1 ) {
93- idx = commentEndIdx + commentEndChar . length - 1 ;
94- } else {
95- error = 'css expression error: unfinished comment in expression!' ;
96- }
97- } else if ( regExp = parseJSRexExp ( token , idx ) ) { // regexp?
98- idx = regExp . idx ;
99- expression += regExp . regExp ;
68+ if ( info = this . _parseJSComment ( token , idx ) ) { // comment?
69+ if ( info . error ) {
70+ error = 'css expression error: unfinished comment in expression!' ;
10071 } else {
101- expression += character ;
72+ idx = info . idx ;
73+ // ignore the comment
10274 }
103- } else {
75+ } else if ( info = this . _parseJSRexExp ( token , idx ) ) { // regexp
76+ idx = info . idx ;
77+ expression += info . text ;
78+ } else { // other
10479 expression += character ;
10580 }
10681 break ;
10782
108- // TODO: string_sep in regexp
10983 case "'" :
11084 case '"' :
111- if ( state == STATES . LITERAL ) {
112- state = STATES . STRING ;
113- string_sep = character ;
114- } else if ( state == STATES . STRING ) {
115- if ( string_sep == character ) {
116- var matched = expression . match ( / \\ + $ / ) ;
117- if ( ! matched || matched [ 0 ] . length % 2 == 0 ) {
118- state = STATES . LITERAL ;
119- string_sep = '' ;
120- }
121- }
85+ info = this . _parseJSString ( token , idx , character ) ;
86+ if ( info ) { // string
87+ idx = info . idx ;
88+ expression += info . text ;
89+ } else {
90+ expression += character ;
12291 }
123- expression += character ;
12492 break ;
12593
12694 default :
@@ -154,6 +122,79 @@ CSSOM.CSSValueExpression.prototype.parse = function() {
154122} ;
155123
156124
125+ /**
126+ *
127+ * @return {Object|false }
128+ * - idx:
129+ * - text:
130+ * or
131+ * - error:
132+ * or
133+ * false
134+ *
135+ */
136+ CSSOM . CSSValueExpression . prototype . _parseJSComment = function ( token , idx ) {
137+ var nextChar = token . charAt ( idx + 1 ) ,
138+ text ;
139+
140+ if ( nextChar == '/' || nextChar == '*' ) {
141+ var startIdx = idx ,
142+ endIdx ,
143+ commentEndChar ;
144+
145+ if ( nextChar == '/' ) { // line comment
146+ commentEndChar = '\n' ;
147+ } else if ( nextChar == '*' ) { // block comment
148+ commentEndChar = '*/' ;
149+ }
150+
151+ endIdx = token . indexOf ( commentEndChar , startIdx + 1 + 1 ) ;
152+ if ( endIdx !== - 1 ) {
153+ endIdx = endIdx + commentEndChar . length - 1 ;
154+ text = token . substring ( idx , endIdx + 1 ) ;
155+ return {
156+ idx : endIdx ,
157+ text : text
158+ }
159+ } else {
160+ error = 'css expression error: unfinished comment in expression!' ;
161+ return {
162+ error : error
163+ }
164+ }
165+ } else {
166+ return false ;
167+ }
168+ } ;
169+
170+
171+ /**
172+ *
173+ * @return {Object|false }
174+ * - idx:
175+ * - text:
176+ * or
177+ * false
178+ *
179+ */
180+ CSSOM . CSSValueExpression . prototype . _parseJSString = function ( token , idx , sep ) {
181+ var endIdx = this . _findMatchedIdx ( token , idx , sep ) ,
182+ text ;
183+
184+ if ( endIdx === - 1 ) {
185+ return false ;
186+ } else {
187+ endIdx = endIdx + sep . length ;
188+ text = token . substring ( idx , endIdx ) ;
189+
190+ return {
191+ idx : endIdx ,
192+ text : text
193+ }
194+ }
195+ } ;
196+
197+
157198/**
158199 * parse regexp in css expression
159200 *
@@ -212,7 +253,7 @@ instanceof /a/
212253 void /a/
213254
214255*/
215- function parseJSRexExp ( token , idx ) {
256+ CSSOM . CSSValueExpression . prototype . _parseJSRexExp = function ( token , idx ) {
216257 var before = token . substring ( 0 , idx ) . trimRight ( ) ,
217258 legalRegx = [
218259 / ^ $ / ,
@@ -248,39 +289,62 @@ function parseJSRexExp(token, idx) {
248289 if ( ! isLegal ) {
249290 return false ;
250291 } else {
251- var startIdx = idx ,
252- regexp ;
292+ var sep = '/' ,
293+ endIdx = this . _findMatchedIdx ( token , idx , sep ) ,
294+ text ;
295+ if ( endIdx === - 1 ) {
296+ return false ;
297+ } else {
298+ endIdx = endIdx + sep . length ;
299+ text = token . substring ( idx , endIdx ) ;
300+
301+ return {
302+ idx : endIdx ,
303+ text : text
304+ }
305+ }
306+ }
307+ } ;
308+
309+
310+ /**
311+ *
312+ * find next sep(same line) index in `token`
313+ *
314+ * @return {Number }
315+ *
316+ */
317+ CSSOM . CSSValueExpression . prototype . _findMatchedIdx = function ( token , idx , sep ) {
318+ var startIdx = idx ,
319+ endIdx ;
320+
321+ var NOT_FOUND = - 1 ;
253322
254- while ( true ) {
255- var regEndIdx = token . indexOf ( '/' , startIdx + 1 ) ;
323+ while ( true ) {
324+ endIdx = token . indexOf ( sep , startIdx + 1 ) ;
256325
257- if ( regEndIdx === - 1 ) {
258- return false ;
326+ if ( endIdx === - 1 ) { // not found
327+ endIdx = NOT_FOUND ;
328+ break ;
329+ } else {
330+ var text = token . substring ( idx + 1 , endIdx ) ,
331+ matched = text . match ( / \\ + $ / ) ;
332+ if ( ! matched || matched [ 0 ] % 2 == 0 ) { // not escaped
333+ break ;
259334 } else {
260- regexp = token . substring ( idx + 1 , regEndIdx ) ;
261- var matched = regexp . match ( / \\ + $ / ) ;
262- if ( ! matched || matched [ 0 ] % 2 == 0 ) {
263- regexp = '/' + regexp + '/' ;
264- break ;
265- } else {
266- startIdx = regEndIdx ;
267- }
335+ startIdx = endIdx ;
268336 }
269337 }
270338 }
271339
272- // validate
273- // RegExp boundary(/) must be in the same line
340+ // boundary must be in the same line(js sting or regexp)
274341 var nextNewLineIdx = token . indexOf ( '\n' , idx + 1 ) ;
275- if ( nextNewLineIdx < regEndIdx ) {
276- return false ;
342+ if ( nextNewLineIdx < endIdx ) {
343+ endIdx = NOT_FOUND ;
277344 }
278345
279346
280- return {
281- idx : regEndIdx ,
282- regExp : regexp
283- } ;
347+ return endIdx ;
284348}
285349
286350
0 commit comments