Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81143 views
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
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
345
346