123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- //.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
|