/ cloudformation-templates / node_modules / cssom / lib / CSSValueExpression.js
CSSValueExpression.js
  1  //.CommonJS
  2  var CSSOM = {
  3  	CSSValue: require('./CSSValue').CSSValue
  4  };
  5  ///CommonJS
  6  
  7  
  8  /**
  9   * @constructor
 10   * @see http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx
 11   *
 12   */
 13  CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
 14  	this._token = token;
 15  	this._idx = idx;
 16  };
 17  
 18  CSSOM.CSSValueExpression.prototype = new CSSOM.CSSValue();
 19  CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
 20  
 21  /**
 22   * parse css expression() value
 23   *
 24   * @return {Object}
 25   *         - error:
 26   *         or
 27   *         - idx:
 28   *         - expression:
 29   *
 30   * Example:
 31   *
 32   * .selector {
 33   *		zoom: expression(documentElement.clientWidth > 1000 ? '1000px' : 'auto');
 34   * }
 35   */
 36  CSSOM.CSSValueExpression.prototype.parse = function() {
 37  	var token = this._token,
 38  			idx = this._idx;
 39  
 40  	var character = '',
 41  			expression = '',
 42  			error = '',
 43  			info,
 44  			paren = [];
 45  
 46  
 47  	for (; ; ++idx) {
 48  		character = token.charAt(idx);
 49  
 50  		// end of token
 51  		if (character === '') {
 52  			error = 'css expression error: unfinished expression!';
 53  			break;
 54  		}
 55  
 56  		switch(character) {
 57  			case '(':
 58  				paren.push(character);
 59  				expression += character;
 60  				break;
 61  
 62  			case ')':
 63  				paren.pop(character);
 64  				expression += character;
 65  				break;
 66  
 67  			case '/':
 68  				if ((info = this._parseJSComment(token, idx))) { // comment?
 69  					if (info.error) {
 70  						error = 'css expression error: unfinished comment in expression!';
 71  					} else {
 72  						idx = info.idx;
 73  						// ignore the comment
 74  					}
 75  				} else if ((info = this._parseJSRexExp(token, idx))) { // regexp
 76  					idx = info.idx;
 77  					expression += info.text;
 78  				} else { // other
 79  					expression += character;
 80  				}
 81  				break;
 82  
 83  			case "'":
 84  			case '"':
 85  				info = this._parseJSString(token, idx, character);
 86  				if (info) { // string
 87  					idx = info.idx;
 88  					expression += info.text;
 89  				} else {
 90  					expression += character;
 91  				}
 92  				break;
 93  
 94  			default:
 95  				expression += character;
 96  				break;
 97  		}
 98  
 99  		if (error) {
100  			break;
101  		}
102  
103  		// end of expression
104  		if (paren.length === 0) {
105  			break;
106  		}
107  	}
108  
109  	var ret;
110  	if (error) {
111  		ret = {
112  			error: error
113  		};
114  	} else {
115  		ret = {
116  			idx: idx,
117  			expression: expression
118  		};
119  	}
120  
121  	return ret;
122  };
123  
124  
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  			var 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  		text = token.substring(idx, endIdx + sep.length);
188  
189  		return {
190  			idx: endIdx,
191  			text: text
192  		};
193  	}
194  };
195  
196  
197  /**
198   * parse regexp in css expression
199   *
200   * @return {Object|false}
201   *				- idx:
202   *				- regExp:
203   *				or 
204   *				false
205   */
206  
207  /*
208  
209  all legal RegExp
210   
211  /a/
212  (/a/)
213  [/a/]
214  [12, /a/]
215  
216  !/a/
217  
218  +/a/
219  -/a/
220  * /a/
221  / /a/
222  %/a/
223  
224  ===/a/
225  !==/a/
226  ==/a/
227  !=/a/
228  >/a/
229  >=/a/
230  </a/
231  <=/a/
232  
233  &/a/
234  |/a/
235  ^/a/
236  ~/a/
237  <</a/
238  >>/a/
239  >>>/a/
240  
241  &&/a/
242  ||/a/
243  ?/a/
244  =/a/
245  ,/a/
246  
247  		delete /a/
248  				in /a/
249  instanceof /a/
250  				new /a/
251  		typeof /a/
252  			void /a/
253  
254  */
255  CSSOM.CSSValueExpression.prototype._parseJSRexExp = function(token, idx) {
256  	var before = token.substring(0, idx).replace(/\s+$/, ""),
257  			legalRegx = [
258  				/^$/,
259  				/\($/,
260  				/\[$/,
261  				/\!$/,
262  				/\+$/,
263  				/\-$/,
264  				/\*$/,
265  				/\/\s+/,
266  				/\%$/,
267  				/\=$/,
268  				/\>$/,
269  				/<$/,
270  				/\&$/,
271  				/\|$/,
272  				/\^$/,
273  				/\~$/,
274  				/\?$/,
275  				/\,$/,
276  				/delete$/,
277  				/in$/,
278  				/instanceof$/,
279  				/new$/,
280  				/typeof$/,
281  				/void$/
282  			];
283  
284  	var isLegal = legalRegx.some(function(reg) {
285  		return reg.test(before);
286  	});
287  
288  	if (!isLegal) {
289  		return false;
290  	} else {
291  		var sep = '/';
292  
293  		// same logic as string
294  		return this._parseJSString(token, idx, sep);
295  	}
296  };
297  
298  
299  /**
300   *
301   * find next sep(same line) index in `token`
302   *
303   * @return {Number}
304   *
305   */
306  CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep) {
307  	var startIdx = idx,
308  			endIdx;
309  
310  	var NOT_FOUND = -1;
311  
312  	while(true) {
313  		endIdx = token.indexOf(sep, startIdx + 1);
314  
315  		if (endIdx === -1) { // not found
316  			endIdx = NOT_FOUND;
317  			break;
318  		} else {
319  			var text = token.substring(idx + 1, endIdx),
320  					matched = text.match(/\\+$/);
321  			if (!matched || matched[0] % 2 === 0) { // not escaped
322  				break;
323  			} else {
324  				startIdx = endIdx;
325  			}
326  		}
327  	}
328  
329  	// boundary must be in the same line(js sting or regexp)
330  	var nextNewLineIdx = token.indexOf('\n', idx + 1);
331  	if (nextNewLineIdx < endIdx) {
332  		endIdx = NOT_FOUND;
333  	}
334  
335  
336  	return endIdx;
337  };
338  
339  
340  
341  
342  //.CommonJS
343  exports.CSSValueExpression = CSSOM.CSSValueExpression;
344  ///CommonJS