Spaces:
Running
Running
| //.CommonJS | |
| var CSSOM = { | |
| CSSValue: require('./CSSValue').CSSValue | |
| }; | |
| ///CommonJS | |
| /** | |
| * @constructor | |
| * @see http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx | |
| * | |
| */ | |
| CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) { | |
| this._token = token; | |
| this._idx = idx; | |
| }; | |
| CSSOM.CSSValueExpression.prototype = new CSSOM.CSSValue(); | |
| CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression; | |
| /** | |
| * parse css expression() value | |
| * | |
| * @return {Object} | |
| * - error: | |
| * or | |
| * - idx: | |
| * - expression: | |
| * | |
| * Example: | |
| * | |
| * .selector { | |
| * zoom: expression(documentElement.clientWidth > 1000 ? '1000px' : 'auto'); | |
| * } | |
| */ | |
| CSSOM.CSSValueExpression.prototype.parse = function() { | |
| var token = this._token, | |
| idx = this._idx; | |
| var character = '', | |
| expression = '', | |
| error = '', | |
| info, | |
| paren = []; | |
| for (; ; ++idx) { | |
| character = token.charAt(idx); | |
| // end of token | |
| if (character === '') { | |
| error = 'css expression error: unfinished expression!'; | |
| break; | |
| } | |
| switch(character) { | |
| case '(': | |
| paren.push(character); | |
| expression += character; | |
| break; | |
| case ')': | |
| paren.pop(character); | |
| expression += character; | |
| break; | |
| case '/': | |
| if ((info = this._parseJSComment(token, idx))) { // comment? | |
| if (info.error) { | |
| error = 'css expression error: unfinished comment in expression!'; | |
| } else { | |
| idx = info.idx; | |
| // ignore the comment | |
| } | |
| } else if ((info = this._parseJSRexExp(token, idx))) { // regexp | |
| idx = info.idx; | |
| expression += info.text; | |
| } else { // other | |
| expression += character; | |
| } | |
| break; | |
| case "'": | |
| case '"': | |
| info = this._parseJSString(token, idx, character); | |
| if (info) { // string | |
| idx = info.idx; | |
| expression += info.text; | |
| } else { | |
| expression += character; | |
| } | |
| break; | |
| default: | |
| expression += character; | |
| break; | |
| } | |
| if (error) { | |
| break; | |
| } | |
| // end of expression | |
| if (paren.length === 0) { | |
| break; | |
| } | |
| } | |
| var ret; | |
| if (error) { | |
| ret = { | |
| error: error | |
| }; | |
| } else { | |
| ret = { | |
| idx: idx, | |
| expression: expression | |
| }; | |
| } | |
| return ret; | |
| }; | |
| /** | |
| * | |
| * @return {Object|false} | |
| * - idx: | |
| * - text: | |
| * or | |
| * - error: | |
| * or | |
| * false | |
| * | |
| */ | |
| CSSOM.CSSValueExpression.prototype._parseJSComment = function(token, idx) { | |
| var nextChar = token.charAt(idx + 1), | |
| text; | |
| if (nextChar === '/' || nextChar === '*') { | |
| var startIdx = idx, | |
| endIdx, | |
| commentEndChar; | |
| if (nextChar === '/') { // line comment | |
| commentEndChar = '\n'; | |
| } else if (nextChar === '*') { // block comment | |
| commentEndChar = '*/'; | |
| } | |
| endIdx = token.indexOf(commentEndChar, startIdx + 1 + 1); | |
| if (endIdx !== -1) { | |
| endIdx = endIdx + commentEndChar.length - 1; | |
| text = token.substring(idx, endIdx + 1); | |
| return { | |
| idx: endIdx, | |
| text: text | |
| }; | |
| } else { | |
| var error = 'css expression error: unfinished comment in expression!'; | |
| return { | |
| error: error | |
| }; | |
| } | |
| } else { | |
| return false; | |
| } | |
| }; | |
| /** | |
| * | |
| * @return {Object|false} | |
| * - idx: | |
| * - text: | |
| * or | |
| * false | |
| * | |
| */ | |
| CSSOM.CSSValueExpression.prototype._parseJSString = function(token, idx, sep) { | |
| var endIdx = this._findMatchedIdx(token, idx, sep), | |
| text; | |
| if (endIdx === -1) { | |
| return false; | |
| } else { | |
| text = token.substring(idx, endIdx + sep.length); | |
| return { | |
| idx: endIdx, | |
| text: text | |
| }; | |
| } | |
| }; | |
| /** | |
| * parse regexp in css expression | |
| * | |
| * @return {Object|false} | |
| * - idx: | |
| * - regExp: | |
| * or | |
| * false | |
| */ | |
| /* | |
| all legal RegExp | |
| /a/ | |
| (/a/) | |
| [/a/] | |
| [12, /a/] | |
| !/a/ | |
| +/a/ | |
| -/a/ | |
| * /a/ | |
| / /a/ | |
| %/a/ | |
| ===/a/ | |
| !==/a/ | |
| ==/a/ | |
| !=/a/ | |
| >/a/ | |
| >=/a/ | |
| </a/ | |
| <=/a/ | |
| &/a/ | |
| |/a/ | |
| ^/a/ | |
| ~/a/ | |
| <</a/ | |
| >>/a/ | |
| >>>/a/ | |
| &&/a/ | |
| ||/a/ | |
| ?/a/ | |
| =/a/ | |
| ,/a/ | |
| delete /a/ | |
| in /a/ | |
| instanceof /a/ | |
| new /a/ | |
| typeof /a/ | |
| void /a/ | |
| */ | |
| CSSOM.CSSValueExpression.prototype._parseJSRexExp = function(token, idx) { | |
| var before = token.substring(0, idx).replace(/\s+$/, ""), | |
| legalRegx = [ | |
| /^$/, | |
| /\($/, | |
| /\[$/, | |
| /\!$/, | |
| /\+$/, | |
| /\-$/, | |
| /\*$/, | |
| /\/\s+/, | |
| /\%$/, | |
| /\=$/, | |
| /\>$/, | |
| /<$/, | |
| /\&$/, | |
| /\|$/, | |
| /\^$/, | |
| /\~$/, | |
| /\?$/, | |
| /\,$/, | |
| /delete$/, | |
| /in$/, | |
| /instanceof$/, | |
| /new$/, | |
| /typeof$/, | |
| /void$/ | |
| ]; | |
| var isLegal = legalRegx.some(function(reg) { | |
| return reg.test(before); | |
| }); | |
| if (!isLegal) { | |
| return false; | |
| } else { | |
| var sep = '/'; | |
| // same logic as string | |
| return this._parseJSString(token, idx, sep); | |
| } | |
| }; | |
| /** | |
| * | |
| * find next sep(same line) index in `token` | |
| * | |
| * @return {Number} | |
| * | |
| */ | |
| CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep) { | |
| var startIdx = idx, | |
| endIdx; | |
| var NOT_FOUND = -1; | |
| while(true) { | |
| endIdx = token.indexOf(sep, startIdx + 1); | |
| if (endIdx === -1) { // not found | |
| endIdx = NOT_FOUND; | |
| break; | |
| } else { | |
| var text = token.substring(idx + 1, endIdx), | |
| matched = text.match(/\\+$/); | |
| if (!matched || matched[0] % 2 === 0) { // not escaped | |
| break; | |
| } else { | |
| startIdx = endIdx; | |
| } | |
| } | |
| } | |
| // boundary must be in the same line(js sting or regexp) | |
| var nextNewLineIdx = token.indexOf('\n', idx + 1); | |
| if (nextNewLineIdx < endIdx) { | |
| endIdx = NOT_FOUND; | |
| } | |
| return endIdx; | |
| }; | |
| //.CommonJS | |
| exports.CSSValueExpression = CSSOM.CSSValueExpression; | |
| ///CommonJS | |