less 2.0.7 → 2.0.8beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.travis.yml +4 -1
  2. data/less.gemspec +2 -1
  3. data/lib/less/js/Makefile +13 -0
  4. data/lib/less/js/benchmark/less-benchmark.js +1 -3
  5. data/lib/less/js/bin/lessc +30 -7
  6. data/lib/less/js/build/require-rhino.js +7 -0
  7. data/lib/less/js/dist/less-1.1.5.js +2805 -0
  8. data/lib/less/js/dist/less-1.1.5.min.js +16 -0
  9. data/lib/less/js/dist/less-rhino-1.1.3.js +2460 -0
  10. data/lib/less/js/dist/less-rhino-1.1.5.js +2481 -0
  11. data/lib/less/js/lib/less/browser.js +8 -2
  12. data/lib/less/js/lib/less/functions.js +12 -1
  13. data/lib/less/js/lib/less/index.js +19 -18
  14. data/lib/less/js/lib/less/parser.js +41 -22
  15. data/lib/less/js/lib/less/rhino.js +60 -0
  16. data/lib/less/js/lib/less/tree/alpha.js +1 -1
  17. data/lib/less/js/lib/less/tree/anonymous.js +1 -1
  18. data/lib/less/js/lib/less/tree/assignment.js +17 -0
  19. data/lib/less/js/lib/less/tree/call.js +1 -1
  20. data/lib/less/js/lib/less/tree/color.js +9 -6
  21. data/lib/less/js/lib/less/tree/comment.js +1 -1
  22. data/lib/less/js/lib/less/tree/dimension.js +1 -1
  23. data/lib/less/js/lib/less/tree/directive.js +1 -1
  24. data/lib/less/js/lib/less/tree/element.js +3 -2
  25. data/lib/less/js/lib/less/tree/expression.js +1 -1
  26. data/lib/less/js/lib/less/tree/import.js +3 -3
  27. data/lib/less/js/lib/less/tree/javascript.js +1 -1
  28. data/lib/less/js/lib/less/tree/keyword.js +1 -1
  29. data/lib/less/js/lib/less/tree/mixin.js +1 -1
  30. data/lib/less/js/lib/less/tree/operation.js +1 -1
  31. data/lib/less/js/lib/less/tree/quoted.js +1 -1
  32. data/lib/less/js/lib/less/tree/rule.js +1 -1
  33. data/lib/less/js/lib/less/tree/ruleset.js +3 -3
  34. data/lib/less/js/lib/less/tree/selector.js +13 -4
  35. data/lib/less/js/lib/less/tree/url.js +2 -2
  36. data/lib/less/js/lib/less/tree/value.js +1 -1
  37. data/lib/less/js/lib/less/tree/variable.js +1 -1
  38. data/lib/less/js/lib/less/tree.js +2 -2
  39. data/lib/less/js/package.json +1 -1
  40. data/lib/less/js/test/css/colors.css +6 -0
  41. data/lib/less/js/test/css/css-3.css +14 -0
  42. data/lib/less/js/test/css/css.css +3 -0
  43. data/lib/less/js/test/css/ie-filters.css +5 -0
  44. data/lib/less/js/test/css/import.css +2 -0
  45. data/lib/less/js/test/css/mixins.css +20 -0
  46. data/lib/less/js/test/less/colors.less +6 -0
  47. data/lib/less/js/test/less/css-3.less +10 -0
  48. data/lib/less/js/test/less/css.less +4 -0
  49. data/lib/less/js/test/less/ie-filters.less +8 -0
  50. data/lib/less/js/test/less/import.less +1 -0
  51. data/lib/less/js/test/less/mixins.less +20 -0
  52. data/lib/less/js/test/less-test.js +2 -4
  53. data/lib/less/loader.rb +18 -30
  54. data/lib/less/version.rb +1 -1
  55. metadata +64 -55
@@ -0,0 +1,2805 @@
1
+ //
2
+ // LESS - Leaner CSS v1.1.5
3
+ // http://lesscss.org
4
+ //
5
+ // Copyright (c) 2009-2011, Alexis Sellier
6
+ // Licensed under the Apache 2.0 License.
7
+ //
8
+ (function (window, undefined) {
9
+ //
10
+ // Stub out `require` in the browser
11
+ //
12
+ function require(arg) {
13
+ return window.less[arg.split('/')[1]];
14
+ };
15
+
16
+
17
+ // ecma-5.js
18
+ //
19
+ // -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
20
+ // -- tlrobinson Tom Robinson
21
+ // dantman Daniel Friesen
22
+
23
+ //
24
+ // Array
25
+ //
26
+ if (!Array.isArray) {
27
+ Array.isArray = function(obj) {
28
+ return Object.prototype.toString.call(obj) === "[object Array]" ||
29
+ (obj instanceof Array);
30
+ };
31
+ }
32
+ if (!Array.prototype.forEach) {
33
+ Array.prototype.forEach = function(block, thisObject) {
34
+ var len = this.length >>> 0;
35
+ for (var i = 0; i < len; i++) {
36
+ if (i in this) {
37
+ block.call(thisObject, this[i], i, this);
38
+ }
39
+ }
40
+ };
41
+ }
42
+ if (!Array.prototype.map) {
43
+ Array.prototype.map = function(fun /*, thisp*/) {
44
+ var len = this.length >>> 0;
45
+ var res = new Array(len);
46
+ var thisp = arguments[1];
47
+
48
+ for (var i = 0; i < len; i++) {
49
+ if (i in this) {
50
+ res[i] = fun.call(thisp, this[i], i, this);
51
+ }
52
+ }
53
+ return res;
54
+ };
55
+ }
56
+ if (!Array.prototype.filter) {
57
+ Array.prototype.filter = function (block /*, thisp */) {
58
+ var values = [];
59
+ var thisp = arguments[1];
60
+ for (var i = 0; i < this.length; i++) {
61
+ if (block.call(thisp, this[i])) {
62
+ values.push(this[i]);
63
+ }
64
+ }
65
+ return values;
66
+ };
67
+ }
68
+ if (!Array.prototype.reduce) {
69
+ Array.prototype.reduce = function(fun /*, initial*/) {
70
+ var len = this.length >>> 0;
71
+ var i = 0;
72
+
73
+ // no value to return if no initial value and an empty array
74
+ if (len === 0 && arguments.length === 1) throw new TypeError();
75
+
76
+ if (arguments.length >= 2) {
77
+ var rv = arguments[1];
78
+ } else {
79
+ do {
80
+ if (i in this) {
81
+ rv = this[i++];
82
+ break;
83
+ }
84
+ // if array contains no values, no initial value to return
85
+ if (++i >= len) throw new TypeError();
86
+ } while (true);
87
+ }
88
+ for (; i < len; i++) {
89
+ if (i in this) {
90
+ rv = fun.call(null, rv, this[i], i, this);
91
+ }
92
+ }
93
+ return rv;
94
+ };
95
+ }
96
+ if (!Array.prototype.indexOf) {
97
+ Array.prototype.indexOf = function (value /*, fromIndex */ ) {
98
+ var length = this.length;
99
+ var i = arguments[1] || 0;
100
+
101
+ if (!length) return -1;
102
+ if (i >= length) return -1;
103
+ if (i < 0) i += length;
104
+
105
+ for (; i < length; i++) {
106
+ if (!Object.prototype.hasOwnProperty.call(this, i)) { continue }
107
+ if (value === this[i]) return i;
108
+ }
109
+ return -1;
110
+ };
111
+ }
112
+
113
+ //
114
+ // Object
115
+ //
116
+ if (!Object.keys) {
117
+ Object.keys = function (object) {
118
+ var keys = [];
119
+ for (var name in object) {
120
+ if (Object.prototype.hasOwnProperty.call(object, name)) {
121
+ keys.push(name);
122
+ }
123
+ }
124
+ return keys;
125
+ };
126
+ }
127
+
128
+ //
129
+ // String
130
+ //
131
+ if (!String.prototype.trim) {
132
+ String.prototype.trim = function () {
133
+ return String(this).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
134
+ };
135
+ }
136
+ var less, tree;
137
+
138
+ if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
139
+ // Rhino
140
+ // Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
141
+ less = {};
142
+ tree = less.tree = {};
143
+ less.mode = 'rhino';
144
+ } else if (typeof(window) === 'undefined') {
145
+ // Node.js
146
+ less = exports,
147
+ tree = require('./tree');
148
+ less.mode = 'node';
149
+ } else {
150
+ // Browser
151
+ if (typeof(window.less) === 'undefined') { window.less = {} }
152
+ less = window.less,
153
+ tree = window.less.tree = {};
154
+ less.mode = 'browser';
155
+ }
156
+ //
157
+ // less.js - parser
158
+ //
159
+ // A relatively straight-forward predictive parser.
160
+ // There is no tokenization/lexing stage, the input is parsed
161
+ // in one sweep.
162
+ //
163
+ // To make the parser fast enough to run in the browser, several
164
+ // optimization had to be made:
165
+ //
166
+ // - Matching and slicing on a huge input is often cause of slowdowns.
167
+ // The solution is to chunkify the input into smaller strings.
168
+ // The chunks are stored in the `chunks` var,
169
+ // `j` holds the current chunk index, and `current` holds
170
+ // the index of the current chunk in relation to `input`.
171
+ // This gives us an almost 4x speed-up.
172
+ //
173
+ // - In many cases, we don't need to match individual tokens;
174
+ // for example, if a value doesn't hold any variables, operations
175
+ // or dynamic references, the parser can effectively 'skip' it,
176
+ // treating it as a literal.
177
+ // An example would be '1px solid #000' - which evaluates to itself,
178
+ // we don't need to know what the individual components are.
179
+ // The drawback, of course is that you don't get the benefits of
180
+ // syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
181
+ // and a smaller speed-up in the code-gen.
182
+ //
183
+ //
184
+ // Token matching is done with the `$` function, which either takes
185
+ // a terminal string or regexp, or a non-terminal function to call.
186
+ // It also takes care of moving all the indices forwards.
187
+ //
188
+ //
189
+ less.Parser = function Parser(env) {
190
+ var input, // LeSS input string
191
+ i, // current index in `input`
192
+ j, // current chunk
193
+ temp, // temporarily holds a chunk's state, for backtracking
194
+ memo, // temporarily holds `i`, when backtracking
195
+ furthest, // furthest index the parser has gone to
196
+ chunks, // chunkified input
197
+ current, // index of current chunk, in `input`
198
+ parser;
199
+
200
+ var that = this;
201
+
202
+ // This function is called after all files
203
+ // have been imported through `@import`.
204
+ var finish = function () {};
205
+
206
+ var imports = this.imports = {
207
+ paths: env && env.paths || [], // Search paths, when importing
208
+ queue: [], // Files which haven't been imported yet
209
+ files: {}, // Holds the imported parse trees
210
+ mime: env && env.mime, // MIME type of .less files
211
+ push: function (path, callback) {
212
+ var that = this;
213
+ this.queue.push(path);
214
+
215
+ //
216
+ // Import a file asynchronously
217
+ //
218
+ less.Parser.importer(path, this.paths, function (root) {
219
+ that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
220
+ that.files[path] = root; // Store the root
221
+
222
+ callback(root);
223
+
224
+ if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
225
+ }, env);
226
+ }
227
+ };
228
+
229
+ function save() { temp = chunks[j], memo = i, current = i }
230
+ function restore() { chunks[j] = temp, i = memo, current = i }
231
+
232
+ function sync() {
233
+ if (i > current) {
234
+ chunks[j] = chunks[j].slice(i - current);
235
+ current = i;
236
+ }
237
+ }
238
+ //
239
+ // Parse from a token, regexp or string, and move forward if match
240
+ //
241
+ function $(tok) {
242
+ var match, args, length, c, index, endIndex, k, mem;
243
+
244
+ //
245
+ // Non-terminal
246
+ //
247
+ if (tok instanceof Function) {
248
+ return tok.call(parser.parsers);
249
+ //
250
+ // Terminal
251
+ //
252
+ // Either match a single character in the input,
253
+ // or match a regexp in the current chunk (chunk[j]).
254
+ //
255
+ } else if (typeof(tok) === 'string') {
256
+ match = input.charAt(i) === tok ? tok : null;
257
+ length = 1;
258
+ sync ();
259
+ } else {
260
+ sync ();
261
+
262
+ if (match = tok.exec(chunks[j])) {
263
+ length = match[0].length;
264
+ } else {
265
+ return null;
266
+ }
267
+ }
268
+
269
+ // The match is confirmed, add the match length to `i`,
270
+ // and consume any extra white-space characters (' ' || '\n')
271
+ // which come after that. The reason for this is that LeSS's
272
+ // grammar is mostly white-space insensitive.
273
+ //
274
+ if (match) {
275
+ mem = i += length;
276
+ endIndex = i + chunks[j].length - length;
277
+
278
+ while (i < endIndex) {
279
+ c = input.charCodeAt(i);
280
+ if (! (c === 32 || c === 10 || c === 9)) { break }
281
+ i++;
282
+ }
283
+ chunks[j] = chunks[j].slice(length + (i - mem));
284
+ current = i;
285
+
286
+ if (chunks[j].length === 0 && j < chunks.length - 1) { j++ }
287
+
288
+ if(typeof(match) === 'string') {
289
+ return match;
290
+ } else {
291
+ return match.length === 1 ? match[0] : match;
292
+ }
293
+ }
294
+ }
295
+
296
+ // Same as $(), but don't change the state of the parser,
297
+ // just return the match.
298
+ function peek(tok) {
299
+ if (typeof(tok) === 'string') {
300
+ return input.charAt(i) === tok;
301
+ } else {
302
+ if (tok.test(chunks[j])) {
303
+ return true;
304
+ } else {
305
+ return false;
306
+ }
307
+ }
308
+ }
309
+
310
+ this.env = env = env || {};
311
+
312
+ // The optimization level dictates the thoroughness of the parser,
313
+ // the lower the number, the less nodes it will create in the tree.
314
+ // This could matter for debugging, or if you want to access
315
+ // the individual nodes in the tree.
316
+ this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
317
+
318
+ this.env.filename = this.env.filename || null;
319
+
320
+ //
321
+ // The Parser
322
+ //
323
+ return parser = {
324
+
325
+ imports: imports,
326
+ //
327
+ // Parse an input string into an abstract syntax tree,
328
+ // call `callback` when done.
329
+ //
330
+ parse: function (str, callback) {
331
+ var root, start, end, zone, line, lines, buff = [], c, error = null;
332
+
333
+ i = j = current = furthest = 0;
334
+ chunks = [];
335
+ input = str.replace(/\r\n/g, '\n');
336
+
337
+ // Split the input into chunks.
338
+ chunks = (function (chunks) {
339
+ var j = 0,
340
+ skip = /[^"'`\{\}\/\(\)]+/g,
341
+ comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
342
+ level = 0,
343
+ match,
344
+ chunk = chunks[0],
345
+ inParam,
346
+ inString;
347
+
348
+ for (var i = 0, c, cc; i < input.length; i++) {
349
+ skip.lastIndex = i;
350
+ if (match = skip.exec(input)) {
351
+ if (match.index === i) {
352
+ i += match[0].length;
353
+ chunk.push(match[0]);
354
+ }
355
+ }
356
+ c = input.charAt(i);
357
+ comment.lastIndex = i;
358
+
359
+ if (!inString && !inParam && c === '/') {
360
+ cc = input.charAt(i + 1);
361
+ if (cc === '/' || cc === '*') {
362
+ if (match = comment.exec(input)) {
363
+ if (match.index === i) {
364
+ i += match[0].length;
365
+ chunk.push(match[0]);
366
+ c = input.charAt(i);
367
+ }
368
+ }
369
+ }
370
+ }
371
+
372
+ if (c === '{' && !inString && !inParam) { level ++;
373
+ chunk.push(c);
374
+ } else if (c === '}' && !inString && !inParam) { level --;
375
+ chunk.push(c);
376
+ chunks[++j] = chunk = [];
377
+ } else if (c === '(' && !inString && !inParam) {
378
+ chunk.push(c);
379
+ inParam = true;
380
+ } else if (c === ')' && !inString && inParam) {
381
+ chunk.push(c);
382
+ inParam = false;
383
+ } else {
384
+ if (c === '"' || c === "'" || c === '`') {
385
+ if (! inString) {
386
+ inString = c;
387
+ } else {
388
+ inString = inString === c ? false : inString;
389
+ }
390
+ }
391
+ chunk.push(c);
392
+ }
393
+ }
394
+ if (level > 0) {
395
+ throw {
396
+ type: 'Syntax',
397
+ message: "Missing closing `}`",
398
+ filename: env.filename
399
+ };
400
+ }
401
+
402
+ return chunks.map(function (c) { return c.join('') });;
403
+ })([[]]);
404
+
405
+ // Start with the primary rule.
406
+ // The whole syntax tree is held under a Ruleset node,
407
+ // with the `root` property set to true, so no `{}` are
408
+ // output. The callback is called when the input is parsed.
409
+ root = new(tree.Ruleset)([], $(this.parsers.primary));
410
+ root.root = true;
411
+
412
+ root.toCSS = (function (evaluate) {
413
+ var line, lines, column;
414
+
415
+ return function (options, variables) {
416
+ var frames = [];
417
+
418
+ options = options || {};
419
+ //
420
+ // Allows setting variables with a hash, so:
421
+ //
422
+ // `{ color: new(tree.Color)('#f01') }` will become:
423
+ //
424
+ // new(tree.Rule)('@color',
425
+ // new(tree.Value)([
426
+ // new(tree.Expression)([
427
+ // new(tree.Color)('#f01')
428
+ // ])
429
+ // ])
430
+ // )
431
+ //
432
+ if (typeof(variables) === 'object' && !Array.isArray(variables)) {
433
+ variables = Object.keys(variables).map(function (k) {
434
+ var value = variables[k];
435
+
436
+ if (! (value instanceof tree.Value)) {
437
+ if (! (value instanceof tree.Expression)) {
438
+ value = new(tree.Expression)([value]);
439
+ }
440
+ value = new(tree.Value)([value]);
441
+ }
442
+ return new(tree.Rule)('@' + k, value, false, 0);
443
+ });
444
+ frames = [new(tree.Ruleset)(null, variables)];
445
+ }
446
+
447
+ try {
448
+ var css = evaluate.call(this, { frames: frames })
449
+ .toCSS([], { compress: options.compress || false });
450
+ } catch (e) {
451
+ lines = input.split('\n');
452
+ line = getLine(e.index);
453
+
454
+ for (var n = e.index, column = -1;
455
+ n >= 0 && input.charAt(n) !== '\n';
456
+ n--) { column++ }
457
+
458
+ throw {
459
+ type: e.type,
460
+ message: e.message,
461
+ filename: env.filename,
462
+ index: e.index,
463
+ line: typeof(line) === 'number' ? line + 1 : null,
464
+ callLine: e.call && (getLine(e.call) + 1),
465
+ callExtract: lines[getLine(e.call)],
466
+ stack: e.stack,
467
+ column: column,
468
+ extract: [
469
+ lines[line - 1],
470
+ lines[line],
471
+ lines[line + 1]
472
+ ]
473
+ };
474
+ }
475
+ if (options.compress) {
476
+ return css.replace(/(\s)+/g, "$1");
477
+ } else {
478
+ return css;
479
+ }
480
+
481
+ function getLine(index) {
482
+ return index ? (input.slice(0, index).match(/\n/g) || "").length : null;
483
+ }
484
+ };
485
+ })(root.eval);
486
+
487
+ // If `i` is smaller than the `input.length - 1`,
488
+ // it means the parser wasn't able to parse the whole
489
+ // string, so we've got a parsing error.
490
+ //
491
+ // We try to extract a \n delimited string,
492
+ // showing the line where the parse error occured.
493
+ // We split it up into two parts (the part which parsed,
494
+ // and the part which didn't), so we can color them differently.
495
+ if (i < input.length - 1) {
496
+ i = furthest;
497
+ lines = input.split('\n');
498
+ line = (input.slice(0, i).match(/\n/g) || "").length + 1;
499
+
500
+ for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
501
+
502
+ error = {
503
+ name: "ParseError",
504
+ message: "Syntax Error on line " + line,
505
+ index: i,
506
+ filename: env.filename,
507
+ line: line,
508
+ column: column,
509
+ extract: [
510
+ lines[line - 2],
511
+ lines[line - 1],
512
+ lines[line]
513
+ ]
514
+ };
515
+ }
516
+
517
+ if (this.imports.queue.length > 0) {
518
+ finish = function () { callback(error, root) };
519
+ } else {
520
+ callback(error, root);
521
+ }
522
+ },
523
+
524
+ //
525
+ // Here in, the parsing rules/functions
526
+ //
527
+ // The basic structure of the syntax tree generated is as follows:
528
+ //
529
+ // Ruleset -> Rule -> Value -> Expression -> Entity
530
+ //
531
+ // Here's some LESS code:
532
+ //
533
+ // .class {
534
+ // color: #fff;
535
+ // border: 1px solid #000;
536
+ // width: @w + 4px;
537
+ // > .child {...}
538
+ // }
539
+ //
540
+ // And here's what the parse tree might look like:
541
+ //
542
+ // Ruleset (Selector '.class', [
543
+ // Rule ("color", Value ([Expression [Color #fff]]))
544
+ // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
545
+ // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
546
+ // Ruleset (Selector [Element '>', '.child'], [...])
547
+ // ])
548
+ //
549
+ // In general, most rules will try to parse a token with the `$()` function, and if the return
550
+ // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
551
+ // first, before parsing, that's when we use `peek()`.
552
+ //
553
+ parsers: {
554
+ //
555
+ // The `primary` rule is the *entry* and *exit* point of the parser.
556
+ // The rules here can appear at any level of the parse tree.
557
+ //
558
+ // The recursive nature of the grammar is an interplay between the `block`
559
+ // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
560
+ // as represented by this simplified grammar:
561
+ //
562
+ // primary → (ruleset | rule)+
563
+ // ruleset → selector+ block
564
+ // block → '{' primary '}'
565
+ //
566
+ // Only at one point is the primary rule not called from the
567
+ // block rule: at the root level.
568
+ //
569
+ primary: function () {
570
+ var node, root = [];
571
+
572
+ while ((node = $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
573
+ $(this.mixin.call) || $(this.comment) || $(this.directive))
574
+ || $(/^[\s\n]+/)) {
575
+ node && root.push(node);
576
+ }
577
+ return root;
578
+ },
579
+
580
+ // We create a Comment node for CSS comments `/* */`,
581
+ // but keep the LeSS comments `//` silent, by just skipping
582
+ // over them.
583
+ comment: function () {
584
+ var comment;
585
+
586
+ if (input.charAt(i) !== '/') return;
587
+
588
+ if (input.charAt(i + 1) === '/') {
589
+ return new(tree.Comment)($(/^\/\/.*/), true);
590
+ } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
591
+ return new(tree.Comment)(comment);
592
+ }
593
+ },
594
+
595
+ //
596
+ // Entities are tokens which can be found inside an Expression
597
+ //
598
+ entities: {
599
+ //
600
+ // A string, which supports escaping " and '
601
+ //
602
+ // "milky way" 'he\'s the one!'
603
+ //
604
+ quoted: function () {
605
+ var str, j = i, e;
606
+
607
+ if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
608
+ if (input.charAt(j) !== '"' && input.charAt(j) !== "'") return;
609
+
610
+ e && $('~');
611
+
612
+ if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
613
+ return new(tree.Quoted)(str[0], str[1] || str[2], e);
614
+ }
615
+ },
616
+
617
+ //
618
+ // A catch-all word, such as:
619
+ //
620
+ // black border-collapse
621
+ //
622
+ keyword: function () {
623
+ var k;
624
+ if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) { return new(tree.Keyword)(k) }
625
+ },
626
+
627
+ //
628
+ // A function call
629
+ //
630
+ // rgb(255, 0, 255)
631
+ //
632
+ // We also try to catch IE's `alpha()`, but let the `alpha` parser
633
+ // deal with the details.
634
+ //
635
+ // The arguments are parsed with the `entities.arguments` parser.
636
+ //
637
+ call: function () {
638
+ var name, args, index = i;
639
+
640
+ if (! (name = /^([\w-]+|%)\(/.exec(chunks[j]))) return;
641
+
642
+ name = name[1].toLowerCase();
643
+
644
+ if (name === 'url') { return null }
645
+ else { i += name.length }
646
+
647
+ if (name === 'alpha') { return $(this.alpha) }
648
+
649
+ $('('); // Parse the '(' and consume whitespace.
650
+
651
+ args = $(this.entities.arguments);
652
+
653
+ if (! $(')')) return;
654
+
655
+ if (name) { return new(tree.Call)(name, args, index) }
656
+ },
657
+ arguments: function () {
658
+ var args = [], arg;
659
+
660
+ while (arg = $(this.expression)) {
661
+ args.push(arg);
662
+ if (! $(',')) { break }
663
+ }
664
+ return args;
665
+ },
666
+ literal: function () {
667
+ return $(this.entities.dimension) ||
668
+ $(this.entities.color) ||
669
+ $(this.entities.quoted);
670
+ },
671
+
672
+ //
673
+ // Parse url() tokens
674
+ //
675
+ // We use a specific rule for urls, because they don't really behave like
676
+ // standard function calls. The difference is that the argument doesn't have
677
+ // to be enclosed within a string, so it can't be parsed as an Expression.
678
+ //
679
+ url: function () {
680
+ var value;
681
+
682
+ if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
683
+ value = $(this.entities.quoted) || $(this.entities.variable) ||
684
+ $(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
685
+ if (! $(')')) throw new(Error)("missing closing ) for url()");
686
+
687
+ return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
688
+ ? value : new(tree.Anonymous)(value), imports.paths);
689
+ },
690
+
691
+ dataURI: function () {
692
+ var obj;
693
+
694
+ if ($(/^data:/)) {
695
+ obj = {};
696
+ obj.mime = $(/^[^\/]+\/[^,;)]+/) || '';
697
+ obj.charset = $(/^;\s*charset=[^,;)]+/) || '';
698
+ obj.base64 = $(/^;\s*base64/) || '';
699
+ obj.data = $(/^,\s*[^)]+/);
700
+
701
+ if (obj.data) { return obj }
702
+ }
703
+ },
704
+
705
+ //
706
+ // A Variable entity, such as `@fink`, in
707
+ //
708
+ // width: @fink + 2px
709
+ //
710
+ // We use a different parser for variable definitions,
711
+ // see `parsers.variable`.
712
+ //
713
+ variable: function () {
714
+ var name, index = i;
715
+
716
+ if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
717
+ return new(tree.Variable)(name, index);
718
+ }
719
+ },
720
+
721
+ //
722
+ // A Hexadecimal color
723
+ //
724
+ // #4F3C2F
725
+ //
726
+ // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
727
+ //
728
+ color: function () {
729
+ var rgb;
730
+
731
+ if (input.charAt(i) === '#' && (rgb = $(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/))) {
732
+ return new(tree.Color)(rgb[1]);
733
+ }
734
+ },
735
+
736
+ //
737
+ // A Dimension, that is, a number and a unit
738
+ //
739
+ // 0.5em 95%
740
+ //
741
+ dimension: function () {
742
+ var value, c = input.charCodeAt(i);
743
+ if ((c > 57 || c < 45) || c === 47) return;
744
+
745
+ if (value = $(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/)) {
746
+ return new(tree.Dimension)(value[1], value[2]);
747
+ }
748
+ },
749
+
750
+ //
751
+ // JavaScript code to be evaluated
752
+ //
753
+ // `window.location.href`
754
+ //
755
+ javascript: function () {
756
+ var str, j = i, e;
757
+
758
+ if (input.charAt(j) === '~') { j++, e = true } // Escaped strings
759
+ if (input.charAt(j) !== '`') { return }
760
+
761
+ e && $('~');
762
+
763
+ if (str = $(/^`([^`]*)`/)) {
764
+ return new(tree.JavaScript)(str[1], i, e);
765
+ }
766
+ }
767
+ },
768
+
769
+ //
770
+ // The variable part of a variable definition. Used in the `rule` parser
771
+ //
772
+ // @fink:
773
+ //
774
+ variable: function () {
775
+ var name;
776
+
777
+ if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1] }
778
+ },
779
+
780
+ //
781
+ // A font size/line-height shorthand
782
+ //
783
+ // small/12px
784
+ //
785
+ // We need to peek first, or we'll match on keywords and dimensions
786
+ //
787
+ shorthand: function () {
788
+ var a, b;
789
+
790
+ if (! peek(/^[@\w.%-]+\/[@\w.-]+/)) return;
791
+
792
+ if ((a = $(this.entity)) && $('/') && (b = $(this.entity))) {
793
+ return new(tree.Shorthand)(a, b);
794
+ }
795
+ },
796
+
797
+ //
798
+ // Mixins
799
+ //
800
+ mixin: {
801
+ //
802
+ // A Mixin call, with an optional argument list
803
+ //
804
+ // #mixins > .square(#fff);
805
+ // .rounded(4px, black);
806
+ // .button;
807
+ //
808
+ // The `while` loop is there because mixins can be
809
+ // namespaced, but we only support the child and descendant
810
+ // selector for now.
811
+ //
812
+ call: function () {
813
+ var elements = [], e, c, args, index = i, s = input.charAt(i);
814
+
815
+ if (s !== '.' && s !== '#') { return }
816
+
817
+ while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
818
+ elements.push(new(tree.Element)(c, e, i));
819
+ c = $('>');
820
+ }
821
+ $('(') && (args = $(this.entities.arguments)) && $(')');
822
+
823
+ if (elements.length > 0 && ($(';') || peek('}'))) {
824
+ return new(tree.mixin.Call)(elements, args, index);
825
+ }
826
+ },
827
+
828
+ //
829
+ // A Mixin definition, with a list of parameters
830
+ //
831
+ // .rounded (@radius: 2px, @color) {
832
+ // ...
833
+ // }
834
+ //
835
+ // Until we have a finer grained state-machine, we have to
836
+ // do a look-ahead, to make sure we don't have a mixin call.
837
+ // See the `rule` function for more information.
838
+ //
839
+ // We start by matching `.rounded (`, and then proceed on to
840
+ // the argument list, which has optional default values.
841
+ // We store the parameters in `params`, with a `value` key,
842
+ // if there is a value, such as in the case of `@radius`.
843
+ //
844
+ // Once we've got our params list, and a closing `)`, we parse
845
+ // the `{...}` block.
846
+ //
847
+ definition: function () {
848
+ var name, params = [], match, ruleset, param, value;
849
+
850
+ if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
851
+ peek(/^[^{]*(;|})/)) return;
852
+
853
+ if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
854
+ name = match[1];
855
+
856
+ while (param = $(this.entities.variable) || $(this.entities.literal)
857
+ || $(this.entities.keyword)) {
858
+ // Variable
859
+ if (param instanceof tree.Variable) {
860
+ if ($(':')) {
861
+ if (value = $(this.expression)) {
862
+ params.push({ name: param.name, value: value });
863
+ } else {
864
+ throw new(Error)("Expected value");
865
+ }
866
+ } else {
867
+ params.push({ name: param.name });
868
+ }
869
+ } else {
870
+ params.push({ value: param });
871
+ }
872
+ if (! $(',')) { break }
873
+ }
874
+ if (! $(')')) throw new(Error)("Expected )");
875
+
876
+ ruleset = $(this.block);
877
+
878
+ if (ruleset) {
879
+ return new(tree.mixin.Definition)(name, params, ruleset);
880
+ }
881
+ }
882
+ }
883
+ },
884
+
885
+ //
886
+ // Entities are the smallest recognized token,
887
+ // and can be found inside a rule's value.
888
+ //
889
+ entity: function () {
890
+ return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
891
+ $(this.entities.call) || $(this.entities.keyword) || $(this.entities.javascript) ||
892
+ $(this.comment);
893
+ },
894
+
895
+ //
896
+ // A Rule terminator. Note that we use `peek()` to check for '}',
897
+ // because the `block` rule will be expecting it, but we still need to make sure
898
+ // it's there, if ';' was ommitted.
899
+ //
900
+ end: function () {
901
+ return $(';') || peek('}');
902
+ },
903
+
904
+ //
905
+ // IE's alpha function
906
+ //
907
+ // alpha(opacity=88)
908
+ //
909
+ alpha: function () {
910
+ var value;
911
+
912
+ if (! $(/^\(opacity=/i)) return;
913
+ if (value = $(/^\d+/) || $(this.entities.variable)) {
914
+ if (! $(')')) throw new(Error)("missing closing ) for alpha()");
915
+ return new(tree.Alpha)(value);
916
+ }
917
+ },
918
+
919
+ //
920
+ // A Selector Element
921
+ //
922
+ // div
923
+ // + h1
924
+ // #socks
925
+ // input[type="text"]
926
+ //
927
+ // Elements are the building blocks for Selectors,
928
+ // they are made out of a `Combinator` (see combinator rule),
929
+ // and an element name, such as a tag a class, or `*`.
930
+ //
931
+ element: function () {
932
+ var e, t, c;
933
+
934
+ c = $(this.combinator);
935
+ e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
936
+ $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
937
+
938
+ if (e) { return new(tree.Element)(c, e, i) }
939
+
940
+ if (c.value && c.value.charAt(0) === '&') {
941
+ return new(tree.Element)(c, null, i);
942
+ }
943
+ },
944
+
945
+ //
946
+ // Combinators combine elements together, in a Selector.
947
+ //
948
+ // Because our parser isn't white-space sensitive, special care
949
+ // has to be taken, when parsing the descendant combinator, ` `,
950
+ // as it's an empty space. We have to check the previous character
951
+ // in the input, to see if it's a ` ` character. More info on how
952
+ // we deal with this in *combinator.js*.
953
+ //
954
+ combinator: function () {
955
+ var match, c = input.charAt(i);
956
+
957
+ if (c === '>' || c === '+' || c === '~') {
958
+ i++;
959
+ while (input.charAt(i) === ' ') { i++ }
960
+ return new(tree.Combinator)(c);
961
+ } else if (c === '&') {
962
+ match = '&';
963
+ i++;
964
+ if(input.charAt(i) === ' ') {
965
+ match = '& ';
966
+ }
967
+ while (input.charAt(i) === ' ') { i++ }
968
+ return new(tree.Combinator)(match);
969
+ } else if (c === ':' && input.charAt(i + 1) === ':') {
970
+ i += 2;
971
+ while (input.charAt(i) === ' ') { i++ }
972
+ return new(tree.Combinator)('::');
973
+ } else if (input.charAt(i - 1) === ' ') {
974
+ return new(tree.Combinator)(" ");
975
+ } else {
976
+ return new(tree.Combinator)(null);
977
+ }
978
+ },
979
+
980
+ //
981
+ // A CSS Selector
982
+ //
983
+ // .class > div + h1
984
+ // li a:hover
985
+ //
986
+ // Selectors are made out of one or more Elements, see above.
987
+ //
988
+ selector: function () {
989
+ var sel, e, elements = [], c, match;
990
+
991
+ while (e = $(this.element)) {
992
+ c = input.charAt(i);
993
+ elements.push(e)
994
+ if (c === '{' || c === '}' || c === ';' || c === ',') { break }
995
+ }
996
+
997
+ if (elements.length > 0) { return new(tree.Selector)(elements) }
998
+ },
999
+ tag: function () {
1000
+ return $(/^[a-zA-Z][a-zA-Z-]*[0-9]?/) || $('*');
1001
+ },
1002
+ attribute: function () {
1003
+ var attr = '', key, val, op;
1004
+
1005
+ if (! $('[')) return;
1006
+
1007
+ if (key = $(/^[a-zA-Z-]+/) || $(this.entities.quoted)) {
1008
+ if ((op = $(/^[|~*$^]?=/)) &&
1009
+ (val = $(this.entities.quoted) || $(/^[\w-]+/))) {
1010
+ attr = [key, op, val.toCSS ? val.toCSS() : val].join('');
1011
+ } else { attr = key }
1012
+ }
1013
+
1014
+ if (! $(']')) return;
1015
+
1016
+ if (attr) { return "[" + attr + "]" }
1017
+ },
1018
+
1019
+ //
1020
+ // The `block` rule is used by `ruleset` and `mixin.definition`.
1021
+ // It's a wrapper around the `primary` rule, with added `{}`.
1022
+ //
1023
+ block: function () {
1024
+ var content;
1025
+
1026
+ if ($('{') && (content = $(this.primary)) && $('}')) {
1027
+ return content;
1028
+ }
1029
+ },
1030
+
1031
+ //
1032
+ // div, .class, body > p {...}
1033
+ //
1034
+ ruleset: function () {
1035
+ var selectors = [], s, rules, match;
1036
+ save();
1037
+
1038
+ while (s = $(this.selector)) {
1039
+ selectors.push(s);
1040
+ $(this.comment);
1041
+ if (! $(',')) { break }
1042
+ $(this.comment);
1043
+ }
1044
+
1045
+ if (selectors.length > 0 && (rules = $(this.block))) {
1046
+ return new(tree.Ruleset)(selectors, rules);
1047
+ } else {
1048
+ // Backtrack
1049
+ furthest = i;
1050
+ restore();
1051
+ }
1052
+ },
1053
+ rule: function () {
1054
+ var name, value, c = input.charAt(i), important, match;
1055
+ save();
1056
+
1057
+ if (c === '.' || c === '#' || c === '&') { return }
1058
+
1059
+ if (name = $(this.variable) || $(this.property)) {
1060
+ if ((name.charAt(0) != '@') && (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j]))) {
1061
+ i += match[0].length - 1;
1062
+ value = new(tree.Anonymous)(match[1]);
1063
+ } else if (name === "font") {
1064
+ value = $(this.font);
1065
+ } else {
1066
+ value = $(this.value);
1067
+ }
1068
+ important = $(this.important);
1069
+
1070
+ if (value && $(this.end)) {
1071
+ return new(tree.Rule)(name, value, important, memo);
1072
+ } else {
1073
+ furthest = i;
1074
+ restore();
1075
+ }
1076
+ }
1077
+ },
1078
+
1079
+ //
1080
+ // An @import directive
1081
+ //
1082
+ // @import "lib";
1083
+ //
1084
+ // Depending on our environemnt, importing is done differently:
1085
+ // In the browser, it's an XHR request, in Node, it would be a
1086
+ // file-system operation. The function used for importing is
1087
+ // stored in `import`, which we pass to the Import constructor.
1088
+ //
1089
+ "import": function () {
1090
+ var path;
1091
+ if ($(/^@import\s+/) &&
1092
+ (path = $(this.entities.quoted) || $(this.entities.url)) &&
1093
+ $(';')) {
1094
+ return new(tree.Import)(path, imports);
1095
+ }
1096
+ },
1097
+
1098
+ //
1099
+ // A CSS Directive
1100
+ //
1101
+ // @charset "utf-8";
1102
+ //
1103
+ directive: function () {
1104
+ var name, value, rules, types;
1105
+
1106
+ if (input.charAt(i) !== '@') return;
1107
+
1108
+ if (value = $(this['import'])) {
1109
+ return value;
1110
+ } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-|-moz-)?keyframes/)) {
1111
+ types = ($(/^[^{]+/) || '').trim();
1112
+ if (rules = $(this.block)) {
1113
+ return new(tree.Directive)(name + " " + types, rules);
1114
+ }
1115
+ } else if (name = $(/^@[-a-z]+/)) {
1116
+ if (name === '@font-face') {
1117
+ if (rules = $(this.block)) {
1118
+ return new(tree.Directive)(name, rules);
1119
+ }
1120
+ } else if ((value = $(this.entity)) && $(';')) {
1121
+ return new(tree.Directive)(name, value);
1122
+ }
1123
+ }
1124
+ },
1125
+ font: function () {
1126
+ var value = [], expression = [], weight, shorthand, font, e;
1127
+
1128
+ while (e = $(this.shorthand) || $(this.entity)) {
1129
+ expression.push(e);
1130
+ }
1131
+ value.push(new(tree.Expression)(expression));
1132
+
1133
+ if ($(',')) {
1134
+ while (e = $(this.expression)) {
1135
+ value.push(e);
1136
+ if (! $(',')) { break }
1137
+ }
1138
+ }
1139
+ return new(tree.Value)(value);
1140
+ },
1141
+
1142
+ //
1143
+ // A Value is a comma-delimited list of Expressions
1144
+ //
1145
+ // font-family: Baskerville, Georgia, serif;
1146
+ //
1147
+ // In a Rule, a Value represents everything after the `:`,
1148
+ // and before the `;`.
1149
+ //
1150
+ value: function () {
1151
+ var e, expressions = [], important;
1152
+
1153
+ while (e = $(this.expression)) {
1154
+ expressions.push(e);
1155
+ if (! $(',')) { break }
1156
+ }
1157
+
1158
+ if (expressions.length > 0) {
1159
+ return new(tree.Value)(expressions);
1160
+ }
1161
+ },
1162
+ important: function () {
1163
+ if (input.charAt(i) === '!') {
1164
+ return $(/^! *important/);
1165
+ }
1166
+ },
1167
+ sub: function () {
1168
+ var e;
1169
+
1170
+ if ($('(') && (e = $(this.expression)) && $(')')) {
1171
+ return e;
1172
+ }
1173
+ },
1174
+ multiplication: function () {
1175
+ var m, a, op, operation;
1176
+ if (m = $(this.operand)) {
1177
+ while ((op = ($('/') || $('*'))) && (a = $(this.operand))) {
1178
+ operation = new(tree.Operation)(op, [operation || m, a]);
1179
+ }
1180
+ return operation || m;
1181
+ }
1182
+ },
1183
+ addition: function () {
1184
+ var m, a, op, operation;
1185
+ if (m = $(this.multiplication)) {
1186
+ while ((op = $(/^[-+]\s+/) || (input.charAt(i - 1) != ' ' && ($('+') || $('-')))) &&
1187
+ (a = $(this.multiplication))) {
1188
+ operation = new(tree.Operation)(op, [operation || m, a]);
1189
+ }
1190
+ return operation || m;
1191
+ }
1192
+ },
1193
+
1194
+ //
1195
+ // An operand is anything that can be part of an operation,
1196
+ // such as a Color, or a Variable
1197
+ //
1198
+ operand: function () {
1199
+ var negate, p = input.charAt(i + 1);
1200
+
1201
+ if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-') }
1202
+ var o = $(this.sub) || $(this.entities.dimension) ||
1203
+ $(this.entities.color) || $(this.entities.variable) ||
1204
+ $(this.entities.call);
1205
+ return negate ? new(tree.Operation)('*', [new(tree.Dimension)(-1), o])
1206
+ : o;
1207
+ },
1208
+
1209
+ //
1210
+ // Expressions either represent mathematical operations,
1211
+ // or white-space delimited Entities.
1212
+ //
1213
+ // 1px solid black
1214
+ // @var * 2
1215
+ //
1216
+ expression: function () {
1217
+ var e, delim, entities = [], d;
1218
+
1219
+ while (e = $(this.addition) || $(this.entity)) {
1220
+ entities.push(e);
1221
+ }
1222
+ if (entities.length > 0) {
1223
+ return new(tree.Expression)(entities);
1224
+ }
1225
+ },
1226
+ property: function () {
1227
+ var name;
1228
+
1229
+ if (name = $(/^(\*?-?[-a-z_0-9]+)\s*:/)) {
1230
+ return name[1];
1231
+ }
1232
+ }
1233
+ }
1234
+ };
1235
+ };
1236
+
1237
+ if (less.mode === 'browser' || less.mode === 'rhino') {
1238
+ //
1239
+ // Used by `@import` directives
1240
+ //
1241
+ less.Parser.importer = function (path, paths, callback, env) {
1242
+ if (path.charAt(0) !== '/' && paths.length > 0) {
1243
+ path = paths[0] + path;
1244
+ }
1245
+ // We pass `true` as 3rd argument, to force the reload of the import.
1246
+ // This is so we can get the syntax tree as opposed to just the CSS output,
1247
+ // as we need this to evaluate the current stylesheet.
1248
+ loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true);
1249
+ };
1250
+ }
1251
+
1252
+ (function (tree) {
1253
+
1254
+ tree.functions = {
1255
+ rgb: function (r, g, b) {
1256
+ return this.rgba(r, g, b, 1.0);
1257
+ },
1258
+ rgba: function (r, g, b, a) {
1259
+ var rgb = [r, g, b].map(function (c) { return number(c) }),
1260
+ a = number(a);
1261
+ return new(tree.Color)(rgb, a);
1262
+ },
1263
+ hsl: function (h, s, l) {
1264
+ return this.hsla(h, s, l, 1.0);
1265
+ },
1266
+ hsla: function (h, s, l, a) {
1267
+ h = (number(h) % 360) / 360;
1268
+ s = number(s); l = number(l); a = number(a);
1269
+
1270
+ var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
1271
+ var m1 = l * 2 - m2;
1272
+
1273
+ return this.rgba(hue(h + 1/3) * 255,
1274
+ hue(h) * 255,
1275
+ hue(h - 1/3) * 255,
1276
+ a);
1277
+
1278
+ function hue(h) {
1279
+ h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
1280
+ if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
1281
+ else if (h * 2 < 1) return m2;
1282
+ else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
1283
+ else return m1;
1284
+ }
1285
+ },
1286
+ hue: function (color) {
1287
+ return new(tree.Dimension)(Math.round(color.toHSL().h));
1288
+ },
1289
+ saturation: function (color) {
1290
+ return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
1291
+ },
1292
+ lightness: function (color) {
1293
+ return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
1294
+ },
1295
+ alpha: function (color) {
1296
+ return new(tree.Dimension)(color.toHSL().a);
1297
+ },
1298
+ saturate: function (color, amount) {
1299
+ var hsl = color.toHSL();
1300
+
1301
+ hsl.s += amount.value / 100;
1302
+ hsl.s = clamp(hsl.s);
1303
+ return hsla(hsl);
1304
+ },
1305
+ desaturate: function (color, amount) {
1306
+ var hsl = color.toHSL();
1307
+
1308
+ hsl.s -= amount.value / 100;
1309
+ hsl.s = clamp(hsl.s);
1310
+ return hsla(hsl);
1311
+ },
1312
+ lighten: function (color, amount) {
1313
+ var hsl = color.toHSL();
1314
+
1315
+ hsl.l += amount.value / 100;
1316
+ hsl.l = clamp(hsl.l);
1317
+ return hsla(hsl);
1318
+ },
1319
+ darken: function (color, amount) {
1320
+ var hsl = color.toHSL();
1321
+
1322
+ hsl.l -= amount.value / 100;
1323
+ hsl.l = clamp(hsl.l);
1324
+ return hsla(hsl);
1325
+ },
1326
+ fadein: function (color, amount) {
1327
+ var hsl = color.toHSL();
1328
+
1329
+ hsl.a += amount.value / 100;
1330
+ hsl.a = clamp(hsl.a);
1331
+ return hsla(hsl);
1332
+ },
1333
+ fadeout: function (color, amount) {
1334
+ var hsl = color.toHSL();
1335
+
1336
+ hsl.a -= amount.value / 100;
1337
+ hsl.a = clamp(hsl.a);
1338
+ return hsla(hsl);
1339
+ },
1340
+ fade: function (color, amount) {
1341
+ var hsl = color.toHSL();
1342
+
1343
+ hsl.a = amount.value / 100;
1344
+ hsl.a = clamp(hsl.a);
1345
+ return hsla(hsl);
1346
+ },
1347
+ spin: function (color, amount) {
1348
+ var hsl = color.toHSL();
1349
+ var hue = (hsl.h + amount.value) % 360;
1350
+
1351
+ hsl.h = hue < 0 ? 360 + hue : hue;
1352
+
1353
+ return hsla(hsl);
1354
+ },
1355
+ //
1356
+ // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
1357
+ // http://sass-lang.com
1358
+ //
1359
+ mix: function (color1, color2, weight) {
1360
+ var p = weight.value / 100.0;
1361
+ var w = p * 2 - 1;
1362
+ var a = color1.toHSL().a - color2.toHSL().a;
1363
+
1364
+ var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
1365
+ var w2 = 1 - w1;
1366
+
1367
+ var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
1368
+ color1.rgb[1] * w1 + color2.rgb[1] * w2,
1369
+ color1.rgb[2] * w1 + color2.rgb[2] * w2];
1370
+
1371
+ var alpha = color1.alpha * p + color2.alpha * (1 - p);
1372
+
1373
+ return new(tree.Color)(rgb, alpha);
1374
+ },
1375
+ greyscale: function (color) {
1376
+ return this.desaturate(color, new(tree.Dimension)(100));
1377
+ },
1378
+ e: function (str) {
1379
+ return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
1380
+ },
1381
+ escape: function (str) {
1382
+ return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
1383
+ },
1384
+ '%': function (quoted /* arg, arg, ...*/) {
1385
+ var args = Array.prototype.slice.call(arguments, 1),
1386
+ str = quoted.value;
1387
+
1388
+ for (var i = 0; i < args.length; i++) {
1389
+ str = str.replace(/%[sda]/i, function(token) {
1390
+ var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
1391
+ return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
1392
+ });
1393
+ }
1394
+ str = str.replace(/%%/g, '%');
1395
+ return new(tree.Quoted)('"' + str + '"', str);
1396
+ },
1397
+ round: function (n) {
1398
+ if (n instanceof tree.Dimension) {
1399
+ return new(tree.Dimension)(Math.round(number(n)), n.unit);
1400
+ } else if (typeof(n) === 'number') {
1401
+ return Math.round(n);
1402
+ } else {
1403
+ throw {
1404
+ error: "RuntimeError",
1405
+ message: "math functions take numbers as parameters"
1406
+ };
1407
+ }
1408
+ },
1409
+ argb: function (color) {
1410
+ return new(tree.Anonymous)(color.toARGB());
1411
+
1412
+ }
1413
+ };
1414
+
1415
+ function hsla(hsla) {
1416
+ return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
1417
+ }
1418
+
1419
+ function number(n) {
1420
+ if (n instanceof tree.Dimension) {
1421
+ return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
1422
+ } else if (typeof(n) === 'number') {
1423
+ return n;
1424
+ } else {
1425
+ throw {
1426
+ error: "RuntimeError",
1427
+ message: "color functions take numbers as parameters"
1428
+ };
1429
+ }
1430
+ }
1431
+
1432
+ function clamp(val) {
1433
+ return Math.min(1, Math.max(0, val));
1434
+ }
1435
+
1436
+ })(require('./tree'));
1437
+ (function (tree) {
1438
+
1439
+ tree.Alpha = function (val) {
1440
+ this.value = val;
1441
+ };
1442
+ tree.Alpha.prototype = {
1443
+ toCSS: function () {
1444
+ return "alpha(opacity=" +
1445
+ (this.value.toCSS ? this.value.toCSS() : this.value) + ")";
1446
+ },
1447
+ eval: function (env) {
1448
+ if (this.value.eval) { this.value = this.value.eval(env) }
1449
+ return this;
1450
+ }
1451
+ };
1452
+
1453
+ })(require('../tree'));
1454
+ (function (tree) {
1455
+
1456
+ tree.Anonymous = function (string) {
1457
+ this.value = string.value || string;
1458
+ };
1459
+ tree.Anonymous.prototype = {
1460
+ toCSS: function () {
1461
+ return this.value;
1462
+ },
1463
+ eval: function () { return this }
1464
+ };
1465
+
1466
+ })(require('../tree'));
1467
+ (function (tree) {
1468
+
1469
+ //
1470
+ // A function call node.
1471
+ //
1472
+ tree.Call = function (name, args, index) {
1473
+ this.name = name;
1474
+ this.args = args;
1475
+ this.index = index;
1476
+ };
1477
+ tree.Call.prototype = {
1478
+ //
1479
+ // When evaluating a function call,
1480
+ // we either find the function in `tree.functions` [1],
1481
+ // in which case we call it, passing the evaluated arguments,
1482
+ // or we simply print it out as it appeared originally [2].
1483
+ //
1484
+ // The *functions.js* file contains the built-in functions.
1485
+ //
1486
+ // The reason why we evaluate the arguments, is in the case where
1487
+ // we try to pass a variable to a function, like: `saturate(@color)`.
1488
+ // The function should receive the value, not the variable.
1489
+ //
1490
+ eval: function (env) {
1491
+ var args = this.args.map(function (a) { return a.eval(env) });
1492
+
1493
+ if (this.name in tree.functions) { // 1.
1494
+ try {
1495
+ return tree.functions[this.name].apply(tree.functions, args);
1496
+ } catch (e) {
1497
+ throw { message: "error evaluating function `" + this.name + "`",
1498
+ index: this.index };
1499
+ }
1500
+ } else { // 2.
1501
+ return new(tree.Anonymous)(this.name +
1502
+ "(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
1503
+ }
1504
+ },
1505
+
1506
+ toCSS: function (env) {
1507
+ return this.eval(env).toCSS();
1508
+ }
1509
+ };
1510
+
1511
+ })(require('../tree'));
1512
+ (function (tree) {
1513
+ //
1514
+ // RGB Colors - #ff0014, #eee
1515
+ //
1516
+ tree.Color = function (rgb, a) {
1517
+ //
1518
+ // The end goal here, is to parse the arguments
1519
+ // into an integer triplet, such as `128, 255, 0`
1520
+ //
1521
+ // This facilitates operations and conversions.
1522
+ //
1523
+ if (Array.isArray(rgb)) {
1524
+ this.rgb = rgb;
1525
+ } else if (rgb.length == 6) {
1526
+ this.rgb = rgb.match(/.{2}/g).map(function (c) {
1527
+ return parseInt(c, 16);
1528
+ });
1529
+ } else {
1530
+ this.rgb = rgb.split('').map(function (c) {
1531
+ return parseInt(c + c, 16);
1532
+ });
1533
+ }
1534
+ this.alpha = typeof(a) === 'number' ? a : 1;
1535
+ };
1536
+ tree.Color.prototype = {
1537
+ eval: function () { return this },
1538
+
1539
+ //
1540
+ // If we have some transparency, the only way to represent it
1541
+ // is via `rgba`. Otherwise, we use the hex representation,
1542
+ // which has better compatibility with older browsers.
1543
+ // Values are capped between `0` and `255`, rounded and zero-padded.
1544
+ //
1545
+ toCSS: function () {
1546
+ if (this.alpha < 1.0) {
1547
+ return "rgba(" + this.rgb.map(function (c) {
1548
+ return Math.round(c);
1549
+ }).concat(this.alpha).join(', ') + ")";
1550
+ } else {
1551
+ return '#' + this.rgb.map(function (i) {
1552
+ i = Math.round(i);
1553
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1554
+ return i.length === 1 ? '0' + i : i;
1555
+ }).join('');
1556
+ }
1557
+ },
1558
+
1559
+ //
1560
+ // Operations have to be done per-channel, if not,
1561
+ // channels will spill onto each other. Once we have
1562
+ // our result, in the form of an integer triplet,
1563
+ // we create a new Color node to hold the result.
1564
+ //
1565
+ operate: function (op, other) {
1566
+ var result = [];
1567
+
1568
+ if (! (other instanceof tree.Color)) {
1569
+ other = other.toColor();
1570
+ }
1571
+
1572
+ for (var c = 0; c < 3; c++) {
1573
+ result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
1574
+ }
1575
+ return new(tree.Color)(result, this.alpha + other.alpha);
1576
+ },
1577
+
1578
+ toHSL: function () {
1579
+ var r = this.rgb[0] / 255,
1580
+ g = this.rgb[1] / 255,
1581
+ b = this.rgb[2] / 255,
1582
+ a = this.alpha;
1583
+
1584
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
1585
+ var h, s, l = (max + min) / 2, d = max - min;
1586
+
1587
+ if (max === min) {
1588
+ h = s = 0;
1589
+ } else {
1590
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1591
+
1592
+ switch (max) {
1593
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1594
+ case g: h = (b - r) / d + 2; break;
1595
+ case b: h = (r - g) / d + 4; break;
1596
+ }
1597
+ h /= 6;
1598
+ }
1599
+ return { h: h * 360, s: s, l: l, a: a };
1600
+ },
1601
+ toARGB: function () {
1602
+ var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
1603
+ return '#' + argb.map(function (i) {
1604
+ i = Math.round(i);
1605
+ i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
1606
+ return i.length === 1 ? '0' + i : i;
1607
+ }).join('');
1608
+ }
1609
+ };
1610
+
1611
+
1612
+ })(require('../tree'));
1613
+ (function (tree) {
1614
+
1615
+ tree.Comment = function (value, silent) {
1616
+ this.value = value;
1617
+ this.silent = !!silent;
1618
+ };
1619
+ tree.Comment.prototype = {
1620
+ toCSS: function (env) {
1621
+ return env.compress ? '' : this.value;
1622
+ },
1623
+ eval: function () { return this }
1624
+ };
1625
+
1626
+ })(require('../tree'));
1627
+ (function (tree) {
1628
+
1629
+ //
1630
+ // A number with a unit
1631
+ //
1632
+ tree.Dimension = function (value, unit) {
1633
+ this.value = parseFloat(value);
1634
+ this.unit = unit || null;
1635
+ };
1636
+
1637
+ tree.Dimension.prototype = {
1638
+ eval: function () { return this },
1639
+ toColor: function () {
1640
+ return new(tree.Color)([this.value, this.value, this.value]);
1641
+ },
1642
+ toCSS: function () {
1643
+ var css = this.value + this.unit;
1644
+ return css;
1645
+ },
1646
+
1647
+ // In an operation between two Dimensions,
1648
+ // we default to the first Dimension's unit,
1649
+ // so `1px + 2em` will yield `3px`.
1650
+ // In the future, we could implement some unit
1651
+ // conversions such that `100cm + 10mm` would yield
1652
+ // `101cm`.
1653
+ operate: function (op, other) {
1654
+ return new(tree.Dimension)
1655
+ (tree.operate(op, this.value, other.value),
1656
+ this.unit || other.unit);
1657
+ }
1658
+ };
1659
+
1660
+ })(require('../tree'));
1661
+ (function (tree) {
1662
+
1663
+ tree.Directive = function (name, value) {
1664
+ this.name = name;
1665
+ if (Array.isArray(value)) {
1666
+ this.ruleset = new(tree.Ruleset)([], value);
1667
+ } else {
1668
+ this.value = value;
1669
+ }
1670
+ };
1671
+ tree.Directive.prototype = {
1672
+ toCSS: function (ctx, env) {
1673
+ if (this.ruleset) {
1674
+ this.ruleset.root = true;
1675
+ return this.name + (env.compress ? '{' : ' {\n ') +
1676
+ this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
1677
+ (env.compress ? '}': '\n}\n');
1678
+ } else {
1679
+ return this.name + ' ' + this.value.toCSS() + ';\n';
1680
+ }
1681
+ },
1682
+ eval: function (env) {
1683
+ env.frames.unshift(this);
1684
+ this.ruleset = this.ruleset && this.ruleset.eval(env);
1685
+ env.frames.shift();
1686
+ return this;
1687
+ },
1688
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
1689
+ find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
1690
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
1691
+ };
1692
+
1693
+ })(require('../tree'));
1694
+ (function (tree) {
1695
+
1696
+ tree.Element = function (combinator, value, index) {
1697
+ this.combinator = combinator instanceof tree.Combinator ?
1698
+ combinator : new(tree.Combinator)(combinator);
1699
+ this.value = value ? value.trim() : "";
1700
+ this.index = index;
1701
+ };
1702
+ tree.Element.prototype.toCSS = function (env) {
1703
+ return this.combinator.toCSS(env || {}) + this.value;
1704
+ };
1705
+
1706
+ tree.Combinator = function (value) {
1707
+ if (value === ' ') {
1708
+ this.value = ' ';
1709
+ } else if (value === '& ') {
1710
+ this.value = '& ';
1711
+ } else {
1712
+ this.value = value ? value.trim() : "";
1713
+ }
1714
+ };
1715
+ tree.Combinator.prototype.toCSS = function (env) {
1716
+ return {
1717
+ '' : '',
1718
+ ' ' : ' ',
1719
+ '&' : '',
1720
+ '& ' : ' ',
1721
+ ':' : ' :',
1722
+ '::': '::',
1723
+ '+' : env.compress ? '+' : ' + ',
1724
+ '~' : env.compress ? '~' : ' ~ ',
1725
+ '>' : env.compress ? '>' : ' > '
1726
+ }[this.value];
1727
+ };
1728
+
1729
+ })(require('../tree'));
1730
+ (function (tree) {
1731
+
1732
+ tree.Expression = function (value) { this.value = value };
1733
+ tree.Expression.prototype = {
1734
+ eval: function (env) {
1735
+ if (this.value.length > 1) {
1736
+ return new(tree.Expression)(this.value.map(function (e) {
1737
+ return e.eval(env);
1738
+ }));
1739
+ } else if (this.value.length === 1) {
1740
+ return this.value[0].eval(env);
1741
+ } else {
1742
+ return this;
1743
+ }
1744
+ },
1745
+ toCSS: function (env) {
1746
+ return this.value.map(function (e) {
1747
+ return e.toCSS(env);
1748
+ }).join(' ');
1749
+ }
1750
+ };
1751
+
1752
+ })(require('../tree'));
1753
+ (function (tree) {
1754
+ //
1755
+ // CSS @import node
1756
+ //
1757
+ // The general strategy here is that we don't want to wait
1758
+ // for the parsing to be completed, before we start importing
1759
+ // the file. That's because in the context of a browser,
1760
+ // most of the time will be spent waiting for the server to respond.
1761
+ //
1762
+ // On creation, we push the import path to our import queue, though
1763
+ // `import,push`, we also pass it a callback, which it'll call once
1764
+ // the file has been fetched, and parsed.
1765
+ //
1766
+ tree.Import = function (path, imports) {
1767
+ var that = this;
1768
+
1769
+ this._path = path;
1770
+
1771
+ // The '.less' extension is optional
1772
+ if (path instanceof tree.Quoted) {
1773
+ this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
1774
+ } else {
1775
+ this.path = path.value.value || path.value;
1776
+ }
1777
+
1778
+ this.css = /css(\?.*)?$/.test(this.path);
1779
+
1780
+ // Only pre-compile .less files
1781
+ if (! this.css) {
1782
+ imports.push(this.path, function (root) {
1783
+ if (! root) {
1784
+ throw new(Error)("Error parsing " + that.path);
1785
+ }
1786
+ that.root = root;
1787
+ });
1788
+ }
1789
+ };
1790
+
1791
+ //
1792
+ // The actual import node doesn't return anything, when converted to CSS.
1793
+ // The reason is that it's used at the evaluation stage, so that the rules
1794
+ // it imports can be treated like any other rules.
1795
+ //
1796
+ // In `eval`, we make sure all Import nodes get evaluated, recursively, so
1797
+ // we end up with a flat structure, which can easily be imported in the parent
1798
+ // ruleset.
1799
+ //
1800
+ tree.Import.prototype = {
1801
+ toCSS: function () {
1802
+ if (this.css) {
1803
+ return "@import " + this._path.toCSS() + ';\n';
1804
+ } else {
1805
+ return "";
1806
+ }
1807
+ },
1808
+ eval: function (env) {
1809
+ var ruleset;
1810
+
1811
+ if (this.css) {
1812
+ return this;
1813
+ } else {
1814
+ ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
1815
+
1816
+ for (var i = 0; i < ruleset.rules.length; i++) {
1817
+ if (ruleset.rules[i] instanceof tree.Import) {
1818
+ Array.prototype
1819
+ .splice
1820
+ .apply(ruleset.rules,
1821
+ [i, 1].concat(ruleset.rules[i].eval(env)));
1822
+ }
1823
+ }
1824
+ return ruleset.rules;
1825
+ }
1826
+ }
1827
+ };
1828
+
1829
+ })(require('../tree'));
1830
+ (function (tree) {
1831
+
1832
+ tree.JavaScript = function (string, index, escaped) {
1833
+ this.escaped = escaped;
1834
+ this.expression = string;
1835
+ this.index = index;
1836
+ };
1837
+ tree.JavaScript.prototype = {
1838
+ eval: function (env) {
1839
+ var result,
1840
+ that = this,
1841
+ context = {};
1842
+
1843
+ var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
1844
+ return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
1845
+ });
1846
+
1847
+ try {
1848
+ expression = new(Function)('return (' + expression + ')');
1849
+ } catch (e) {
1850
+ throw { message: "JavaScript evaluation error: `" + expression + "`" ,
1851
+ index: this.index };
1852
+ }
1853
+
1854
+ for (var k in env.frames[0].variables()) {
1855
+ context[k.slice(1)] = {
1856
+ value: env.frames[0].variables()[k].value,
1857
+ toJS: function () {
1858
+ return this.value.eval(env).toCSS();
1859
+ }
1860
+ };
1861
+ }
1862
+
1863
+ try {
1864
+ result = expression.call(context);
1865
+ } catch (e) {
1866
+ throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
1867
+ index: this.index };
1868
+ }
1869
+ if (typeof(result) === 'string') {
1870
+ return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
1871
+ } else if (Array.isArray(result)) {
1872
+ return new(tree.Anonymous)(result.join(', '));
1873
+ } else {
1874
+ return new(tree.Anonymous)(result);
1875
+ }
1876
+ }
1877
+ };
1878
+
1879
+ })(require('../tree'));
1880
+
1881
+ (function (tree) {
1882
+
1883
+ tree.Keyword = function (value) { this.value = value };
1884
+ tree.Keyword.prototype = {
1885
+ eval: function () { return this },
1886
+ toCSS: function () { return this.value }
1887
+ };
1888
+
1889
+ })(require('../tree'));
1890
+ (function (tree) {
1891
+
1892
+ tree.mixin = {};
1893
+ tree.mixin.Call = function (elements, args, index) {
1894
+ this.selector = new(tree.Selector)(elements);
1895
+ this.arguments = args;
1896
+ this.index = index;
1897
+ };
1898
+ tree.mixin.Call.prototype = {
1899
+ eval: function (env) {
1900
+ var mixins, args, rules = [], match = false;
1901
+
1902
+ for (var i = 0; i < env.frames.length; i++) {
1903
+ if ((mixins = env.frames[i].find(this.selector)).length > 0) {
1904
+ args = this.arguments && this.arguments.map(function (a) { return a.eval(env) });
1905
+ for (var m = 0; m < mixins.length; m++) {
1906
+ if (mixins[m].match(args, env)) {
1907
+ try {
1908
+ Array.prototype.push.apply(
1909
+ rules, mixins[m].eval(env, this.arguments).rules);
1910
+ match = true;
1911
+ } catch (e) {
1912
+ throw { message: e.message, index: e.index, stack: e.stack, call: this.index };
1913
+ }
1914
+ }
1915
+ }
1916
+ if (match) {
1917
+ return rules;
1918
+ } else {
1919
+ throw { message: 'No matching definition was found for `' +
1920
+ this.selector.toCSS().trim() + '(' +
1921
+ this.arguments.map(function (a) {
1922
+ return a.toCSS();
1923
+ }).join(', ') + ")`",
1924
+ index: this.index };
1925
+ }
1926
+ }
1927
+ }
1928
+ throw { message: this.selector.toCSS().trim() + " is undefined",
1929
+ index: this.index };
1930
+ }
1931
+ };
1932
+
1933
+ tree.mixin.Definition = function (name, params, rules) {
1934
+ this.name = name;
1935
+ this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
1936
+ this.params = params;
1937
+ this.arity = params.length;
1938
+ this.rules = rules;
1939
+ this._lookups = {};
1940
+ this.required = params.reduce(function (count, p) {
1941
+ if (!p.name || (p.name && !p.value)) { return count + 1 }
1942
+ else { return count }
1943
+ }, 0);
1944
+ this.parent = tree.Ruleset.prototype;
1945
+ this.frames = [];
1946
+ };
1947
+ tree.mixin.Definition.prototype = {
1948
+ toCSS: function () { return "" },
1949
+ variable: function (name) { return this.parent.variable.call(this, name) },
1950
+ variables: function () { return this.parent.variables.call(this) },
1951
+ find: function () { return this.parent.find.apply(this, arguments) },
1952
+ rulesets: function () { return this.parent.rulesets.apply(this) },
1953
+
1954
+ eval: function (env, args) {
1955
+ var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
1956
+
1957
+ for (var i = 0, val; i < this.params.length; i++) {
1958
+ if (this.params[i].name) {
1959
+ if (val = (args && args[i]) || this.params[i].value) {
1960
+ frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));
1961
+ } else {
1962
+ throw { message: "wrong number of arguments for " + this.name +
1963
+ ' (' + args.length + ' for ' + this.arity + ')' };
1964
+ }
1965
+ }
1966
+ }
1967
+ for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
1968
+ _arguments.push(args[i] || this.params[i].value);
1969
+ }
1970
+ frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
1971
+
1972
+ return new(tree.Ruleset)(null, this.rules.slice(0)).eval({
1973
+ frames: [this, frame].concat(this.frames, env.frames)
1974
+ });
1975
+ },
1976
+ match: function (args, env) {
1977
+ var argsLength = (args && args.length) || 0, len;
1978
+
1979
+ if (argsLength < this.required) { return false }
1980
+ if ((this.required > 0) && (argsLength > this.params.length)) { return false }
1981
+
1982
+ len = Math.min(argsLength, this.arity);
1983
+
1984
+ for (var i = 0; i < len; i++) {
1985
+ if (!this.params[i].name) {
1986
+ if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
1987
+ return false;
1988
+ }
1989
+ }
1990
+ }
1991
+ return true;
1992
+ }
1993
+ };
1994
+
1995
+ })(require('../tree'));
1996
+ (function (tree) {
1997
+
1998
+ tree.Operation = function (op, operands) {
1999
+ this.op = op.trim();
2000
+ this.operands = operands;
2001
+ };
2002
+ tree.Operation.prototype.eval = function (env) {
2003
+ var a = this.operands[0].eval(env),
2004
+ b = this.operands[1].eval(env),
2005
+ temp;
2006
+
2007
+ if (a instanceof tree.Dimension && b instanceof tree.Color) {
2008
+ if (this.op === '*' || this.op === '+') {
2009
+ temp = b, b = a, a = temp;
2010
+ } else {
2011
+ throw { name: "OperationError",
2012
+ message: "Can't substract or divide a color from a number" };
2013
+ }
2014
+ }
2015
+ return a.operate(this.op, b);
2016
+ };
2017
+
2018
+ tree.operate = function (op, a, b) {
2019
+ switch (op) {
2020
+ case '+': return a + b;
2021
+ case '-': return a - b;
2022
+ case '*': return a * b;
2023
+ case '/': return a / b;
2024
+ }
2025
+ };
2026
+
2027
+ })(require('../tree'));
2028
+ (function (tree) {
2029
+
2030
+ tree.Quoted = function (str, content, escaped, i) {
2031
+ this.escaped = escaped;
2032
+ this.value = content || '';
2033
+ this.quote = str.charAt(0);
2034
+ this.index = i;
2035
+ };
2036
+ tree.Quoted.prototype = {
2037
+ toCSS: function () {
2038
+ if (this.escaped) {
2039
+ return this.value;
2040
+ } else {
2041
+ return this.quote + this.value + this.quote;
2042
+ }
2043
+ },
2044
+ eval: function (env) {
2045
+ var that = this;
2046
+ var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
2047
+ return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
2048
+ }).replace(/@\{([\w-]+)\}/g, function (_, name) {
2049
+ var v = new(tree.Variable)('@' + name, that.index).eval(env);
2050
+ return v.value || v.toCSS();
2051
+ });
2052
+ return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
2053
+ }
2054
+ };
2055
+
2056
+ })(require('../tree'));
2057
+ (function (tree) {
2058
+
2059
+ tree.Rule = function (name, value, important, index) {
2060
+ this.name = name;
2061
+ this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
2062
+ this.important = important ? ' ' + important.trim() : '';
2063
+ this.index = index;
2064
+
2065
+ if (name.charAt(0) === '@') {
2066
+ this.variable = true;
2067
+ } else { this.variable = false }
2068
+ };
2069
+ tree.Rule.prototype.toCSS = function (env) {
2070
+ if (this.variable) { return "" }
2071
+ else {
2072
+ return this.name + (env.compress ? ':' : ': ') +
2073
+ this.value.toCSS(env) +
2074
+ this.important + ";";
2075
+ }
2076
+ };
2077
+
2078
+ tree.Rule.prototype.eval = function (context) {
2079
+ return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index);
2080
+ };
2081
+
2082
+ tree.Shorthand = function (a, b) {
2083
+ this.a = a;
2084
+ this.b = b;
2085
+ };
2086
+
2087
+ tree.Shorthand.prototype = {
2088
+ toCSS: function (env) {
2089
+ return this.a.toCSS(env) + "/" + this.b.toCSS(env);
2090
+ },
2091
+ eval: function () { return this }
2092
+ };
2093
+
2094
+ })(require('../tree'));
2095
+ (function (tree) {
2096
+
2097
+ tree.Ruleset = function (selectors, rules) {
2098
+ this.selectors = selectors;
2099
+ this.rules = rules;
2100
+ this._lookups = {};
2101
+ };
2102
+ tree.Ruleset.prototype = {
2103
+ eval: function (env) {
2104
+ var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));
2105
+
2106
+ ruleset.root = this.root;
2107
+
2108
+ // push the current ruleset to the frames stack
2109
+ env.frames.unshift(ruleset);
2110
+
2111
+ // Evaluate imports
2112
+ if (ruleset.root) {
2113
+ for (var i = 0; i < ruleset.rules.length; i++) {
2114
+ if (ruleset.rules[i] instanceof tree.Import) {
2115
+ Array.prototype.splice
2116
+ .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2117
+ }
2118
+ }
2119
+ }
2120
+
2121
+ // Store the frames around mixin definitions,
2122
+ // so they can be evaluated like closures when the time comes.
2123
+ for (var i = 0; i < ruleset.rules.length; i++) {
2124
+ if (ruleset.rules[i] instanceof tree.mixin.Definition) {
2125
+ ruleset.rules[i].frames = env.frames.slice(0);
2126
+ }
2127
+ }
2128
+
2129
+ // Evaluate mixin calls.
2130
+ for (var i = 0; i < ruleset.rules.length; i++) {
2131
+ if (ruleset.rules[i] instanceof tree.mixin.Call) {
2132
+ Array.prototype.splice
2133
+ .apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
2134
+ }
2135
+ }
2136
+
2137
+ // Evaluate everything else
2138
+ for (var i = 0, rule; i < ruleset.rules.length; i++) {
2139
+ rule = ruleset.rules[i];
2140
+
2141
+ if (! (rule instanceof tree.mixin.Definition)) {
2142
+ ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
2143
+ }
2144
+ }
2145
+
2146
+ // Pop the stack
2147
+ env.frames.shift();
2148
+
2149
+ return ruleset;
2150
+ },
2151
+ match: function (args) {
2152
+ return !args || args.length === 0;
2153
+ },
2154
+ variables: function () {
2155
+ if (this._variables) { return this._variables }
2156
+ else {
2157
+ return this._variables = this.rules.reduce(function (hash, r) {
2158
+ if (r instanceof tree.Rule && r.variable === true) {
2159
+ hash[r.name] = r;
2160
+ }
2161
+ return hash;
2162
+ }, {});
2163
+ }
2164
+ },
2165
+ variable: function (name) {
2166
+ return this.variables()[name];
2167
+ },
2168
+ rulesets: function () {
2169
+ if (this._rulesets) { return this._rulesets }
2170
+ else {
2171
+ return this._rulesets = this.rules.filter(function (r) {
2172
+ return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
2173
+ });
2174
+ }
2175
+ },
2176
+ find: function (selector, self) {
2177
+ self = self || this;
2178
+ var rules = [], rule, match,
2179
+ key = selector.toCSS();
2180
+
2181
+ if (key in this._lookups) { return this._lookups[key] }
2182
+
2183
+ this.rulesets().forEach(function (rule) {
2184
+ if (rule !== self) {
2185
+ for (var j = 0; j < rule.selectors.length; j++) {
2186
+ if (match = selector.match(rule.selectors[j])) {
2187
+ if (selector.elements.length > rule.selectors[j].elements.length) {
2188
+ Array.prototype.push.apply(rules, rule.find(
2189
+ new(tree.Selector)(selector.elements.slice(1)), self));
2190
+ } else {
2191
+ rules.push(rule);
2192
+ }
2193
+ break;
2194
+ }
2195
+ }
2196
+ }
2197
+ });
2198
+ return this._lookups[key] = rules;
2199
+ },
2200
+ //
2201
+ // Entry point for code generation
2202
+ //
2203
+ // `context` holds an array of arrays.
2204
+ //
2205
+ toCSS: function (context, env) {
2206
+ var css = [], // The CSS output
2207
+ rules = [], // node.Rule instances
2208
+ rulesets = [], // node.Ruleset instances
2209
+ paths = [], // Current selectors
2210
+ selector, // The fully rendered selector
2211
+ rule;
2212
+
2213
+ if (! this.root) {
2214
+ if (context.length === 0) {
2215
+ paths = this.selectors.map(function (s) { return [s] });
2216
+ } else {
2217
+ this.joinSelectors( paths, context, this.selectors );
2218
+ }
2219
+ }
2220
+
2221
+ // Compile rules and rulesets
2222
+ for (var i = 0; i < this.rules.length; i++) {
2223
+ rule = this.rules[i];
2224
+
2225
+ if (rule.rules || (rule instanceof tree.Directive)) {
2226
+ rulesets.push(rule.toCSS(paths, env));
2227
+ } else if (rule instanceof tree.Comment) {
2228
+ if (!rule.silent) {
2229
+ if (this.root) {
2230
+ rulesets.push(rule.toCSS(env));
2231
+ } else {
2232
+ rules.push(rule.toCSS(env));
2233
+ }
2234
+ }
2235
+ } else {
2236
+ if (rule.toCSS && !rule.variable) {
2237
+ rules.push(rule.toCSS(env));
2238
+ } else if (rule.value && !rule.variable) {
2239
+ rules.push(rule.value.toString());
2240
+ }
2241
+ }
2242
+ }
2243
+
2244
+ rulesets = rulesets.join('');
2245
+
2246
+ // If this is the root node, we don't render
2247
+ // a selector, or {}.
2248
+ // Otherwise, only output if this ruleset has rules.
2249
+ if (this.root) {
2250
+ css.push(rules.join(env.compress ? '' : '\n'));
2251
+ } else {
2252
+ if (rules.length > 0) {
2253
+ selector = paths.map(function (p) {
2254
+ return p.map(function (s) {
2255
+ return s.toCSS(env);
2256
+ }).join('').trim();
2257
+ }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
2258
+ css.push(selector,
2259
+ (env.compress ? '{' : ' {\n ') +
2260
+ rules.join(env.compress ? '' : '\n ') +
2261
+ (env.compress ? '}' : '\n}\n'));
2262
+ }
2263
+ }
2264
+ css.push(rulesets);
2265
+
2266
+ return css.join('') + (env.compress ? '\n' : '');
2267
+ },
2268
+
2269
+ joinSelectors: function (paths, context, selectors) {
2270
+ for (var s = 0; s < selectors.length; s++) {
2271
+ this.joinSelector(paths, context, selectors[s]);
2272
+ }
2273
+ },
2274
+
2275
+ joinSelector: function (paths, context, selector) {
2276
+ var before = [], after = [], beforeElements = [],
2277
+ afterElements = [], hasParentSelector = false, el;
2278
+
2279
+ for (var i = 0; i < selector.elements.length; i++) {
2280
+ el = selector.elements[i];
2281
+ if (el.combinator.value.charAt(0) === '&') {
2282
+ hasParentSelector = true;
2283
+ }
2284
+ if (hasParentSelector) afterElements.push(el);
2285
+ else beforeElements.push(el);
2286
+ }
2287
+
2288
+ if (! hasParentSelector) {
2289
+ afterElements = beforeElements;
2290
+ beforeElements = [];
2291
+ }
2292
+
2293
+ if (beforeElements.length > 0) {
2294
+ before.push(new(tree.Selector)(beforeElements));
2295
+ }
2296
+
2297
+ if (afterElements.length > 0) {
2298
+ after.push(new(tree.Selector)(afterElements));
2299
+ }
2300
+
2301
+ for (var c = 0; c < context.length; c++) {
2302
+ paths.push(before.concat(context[c]).concat(after));
2303
+ }
2304
+ }
2305
+ };
2306
+ })(require('../tree'));
2307
+ (function (tree) {
2308
+
2309
+ tree.Selector = function (elements) {
2310
+ this.elements = elements;
2311
+ if (this.elements[0].combinator.value === "") {
2312
+ this.elements[0].combinator.value = ' ';
2313
+ }
2314
+ };
2315
+ tree.Selector.prototype.match = function (other) {
2316
+ var len = this.elements.length,
2317
+ olen = other.elements.length,
2318
+ max = Math.min(len, olen);
2319
+
2320
+ if (len < olen) {
2321
+ return false;
2322
+ } else {
2323
+ for (var i = 0; i < max; i++) {
2324
+ if (this.elements[i].value !== other.elements[i].value) {
2325
+ return false;
2326
+ }
2327
+ }
2328
+ }
2329
+ return true;
2330
+ };
2331
+ tree.Selector.prototype.toCSS = function (env) {
2332
+ if (this._css) { return this._css }
2333
+
2334
+ return this._css = this.elements.map(function (e) {
2335
+ if (typeof(e) === 'string') {
2336
+ return ' ' + e.trim();
2337
+ } else {
2338
+ return e.toCSS(env);
2339
+ }
2340
+ }).join('');
2341
+ };
2342
+
2343
+ })(require('../tree'));
2344
+ (function (tree) {
2345
+
2346
+ tree.URL = function (val, paths) {
2347
+ if (val.data) {
2348
+ this.attrs = val;
2349
+ } else {
2350
+ // Add the base path if the URL is relative and we are in the browser
2351
+ if (less.mode === 'browser' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
2352
+ val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
2353
+ }
2354
+ this.value = val;
2355
+ this.paths = paths;
2356
+ }
2357
+ };
2358
+ tree.URL.prototype = {
2359
+ toCSS: function () {
2360
+ return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data
2361
+ : this.value.toCSS()) + ")";
2362
+ },
2363
+ eval: function (ctx) {
2364
+ return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths);
2365
+ }
2366
+ };
2367
+
2368
+ })(require('../tree'));
2369
+ (function (tree) {
2370
+
2371
+ tree.Value = function (value) {
2372
+ this.value = value;
2373
+ this.is = 'value';
2374
+ };
2375
+ tree.Value.prototype = {
2376
+ eval: function (env) {
2377
+ if (this.value.length === 1) {
2378
+ return this.value[0].eval(env);
2379
+ } else {
2380
+ return new(tree.Value)(this.value.map(function (v) {
2381
+ return v.eval(env);
2382
+ }));
2383
+ }
2384
+ },
2385
+ toCSS: function (env) {
2386
+ return this.value.map(function (e) {
2387
+ return e.toCSS(env);
2388
+ }).join(env.compress ? ',' : ', ');
2389
+ }
2390
+ };
2391
+
2392
+ })(require('../tree'));
2393
+ (function (tree) {
2394
+
2395
+ tree.Variable = function (name, index) { this.name = name, this.index = index };
2396
+ tree.Variable.prototype = {
2397
+ eval: function (env) {
2398
+ var variable, v, name = this.name;
2399
+
2400
+ if (name.indexOf('@@') == 0) {
2401
+ name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
2402
+ }
2403
+
2404
+ if (variable = tree.find(env.frames, function (frame) {
2405
+ if (v = frame.variable(name)) {
2406
+ return v.value.eval(env);
2407
+ }
2408
+ })) { return variable }
2409
+ else {
2410
+ throw { message: "variable " + name + " is undefined",
2411
+ index: this.index };
2412
+ }
2413
+ }
2414
+ };
2415
+
2416
+ })(require('../tree'));
2417
+ require('./tree').find = function (obj, fun) {
2418
+ for (var i = 0, r; i < obj.length; i++) {
2419
+ if (r = fun.call(obj, obj[i])) { return r }
2420
+ }
2421
+ return null;
2422
+ };
2423
+ require('./tree').jsify = function (obj) {
2424
+ if (Array.isArray(obj.value) && (obj.value.length > 1)) {
2425
+ return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
2426
+ } else {
2427
+ return obj.toCSS(false);
2428
+ }
2429
+ };
2430
+ //
2431
+ // browser.js - client-side engine
2432
+ //
2433
+
2434
+ var isFileProtocol = (location.protocol === 'file:' ||
2435
+ location.protocol === 'chrome:' ||
2436
+ location.protocol === 'chrome-extension:' ||
2437
+ location.protocol === 'resource:');
2438
+
2439
+ less.env = less.env || (location.hostname == '127.0.0.1' ||
2440
+ location.hostname == '0.0.0.0' ||
2441
+ location.hostname == 'localhost' ||
2442
+ location.port.length > 0 ||
2443
+ isFileProtocol ? 'development'
2444
+ : 'production');
2445
+
2446
+ // Load styles asynchronously (default: false)
2447
+ //
2448
+ // This is set to `false` by default, so that the body
2449
+ // doesn't start loading before the stylesheets are parsed.
2450
+ // Setting this to `true` can result in flickering.
2451
+ //
2452
+ less.async = false;
2453
+
2454
+ // Interval between watch polls
2455
+ less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
2456
+
2457
+ //
2458
+ // Watch mode
2459
+ //
2460
+ less.watch = function () { return this.watchMode = true };
2461
+ less.unwatch = function () { return this.watchMode = false };
2462
+
2463
+ if (less.env === 'development') {
2464
+ less.optimization = 0;
2465
+
2466
+ if (/!watch/.test(location.hash)) {
2467
+ less.watch();
2468
+ }
2469
+ less.watchTimer = setInterval(function () {
2470
+ if (less.watchMode) {
2471
+ loadStyleSheets(function (root, sheet, env) {
2472
+ if (root) {
2473
+ createCSS(root.toCSS(), sheet, env.lastModified);
2474
+ }
2475
+ });
2476
+ }
2477
+ }, less.poll);
2478
+ } else {
2479
+ less.optimization = 3;
2480
+ }
2481
+
2482
+ var cache;
2483
+
2484
+ try {
2485
+ cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
2486
+ } catch (_) {
2487
+ cache = null;
2488
+ }
2489
+
2490
+ //
2491
+ // Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
2492
+ //
2493
+ var links = document.getElementsByTagName('link');
2494
+ var typePattern = /^text\/(x-)?less$/;
2495
+
2496
+ less.sheets = [];
2497
+
2498
+ for (var i = 0; i < links.length; i++) {
2499
+ if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
2500
+ (links[i].type.match(typePattern)))) {
2501
+ less.sheets.push(links[i]);
2502
+ }
2503
+ }
2504
+
2505
+
2506
+ less.refresh = function (reload) {
2507
+ var startTime, endTime;
2508
+ startTime = endTime = new(Date);
2509
+
2510
+ loadStyleSheets(function (root, sheet, env) {
2511
+ if (env.local) {
2512
+ log("loading " + sheet.href + " from cache.");
2513
+ } else {
2514
+ log("parsed " + sheet.href + " successfully.");
2515
+ createCSS(root.toCSS(), sheet, env.lastModified);
2516
+ }
2517
+ log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
2518
+ (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
2519
+ endTime = new(Date);
2520
+ }, reload);
2521
+
2522
+ loadStyles();
2523
+ };
2524
+ less.refreshStyles = loadStyles;
2525
+
2526
+ less.refresh(less.env === 'development');
2527
+
2528
+ function loadStyles() {
2529
+ var styles = document.getElementsByTagName('style');
2530
+ for (var i = 0; i < styles.length; i++) {
2531
+ if (styles[i].type.match(typePattern)) {
2532
+ new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) {
2533
+ var css = tree.toCSS();
2534
+ var style = styles[i];
2535
+ try {
2536
+ style.innerHTML = css;
2537
+ } catch (_) {
2538
+ style.styleSheets.cssText = css;
2539
+ }
2540
+ style.type = 'text/css';
2541
+ });
2542
+ }
2543
+ }
2544
+ }
2545
+
2546
+ function loadStyleSheets(callback, reload) {
2547
+ for (var i = 0; i < less.sheets.length; i++) {
2548
+ loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
2549
+ }
2550
+ }
2551
+
2552
+ function loadStyleSheet(sheet, callback, reload, remaining) {
2553
+ var url = window.location.href.replace(/[#?].*$/, '');
2554
+ var href = sheet.href.replace(/\?.*$/, '');
2555
+ var css = cache && cache.getItem(href);
2556
+ var timestamp = cache && cache.getItem(href + ':timestamp');
2557
+ var styles = { css: css, timestamp: timestamp };
2558
+
2559
+ // Stylesheets in IE don't always return the full path
2560
+ if (! /^(https?|file):/.test(href)) {
2561
+ if (href.charAt(0) == "/") {
2562
+ href = window.location.protocol + "//" + window.location.host + href;
2563
+ } else {
2564
+ href = url.slice(0, url.lastIndexOf('/') + 1) + href;
2565
+ }
2566
+ }
2567
+
2568
+ xhr(sheet.href, sheet.type, function (data, lastModified) {
2569
+ if (!reload && styles && lastModified &&
2570
+ (new(Date)(lastModified).valueOf() ===
2571
+ new(Date)(styles.timestamp).valueOf())) {
2572
+ // Use local copy
2573
+ createCSS(styles.css, sheet);
2574
+ callback(null, sheet, { local: true, remaining: remaining });
2575
+ } else {
2576
+ // Use remote copy (re-parse)
2577
+ try {
2578
+ new(less.Parser)({
2579
+ optimization: less.optimization,
2580
+ paths: [href.replace(/[\w\.-]+$/, '')],
2581
+ mime: sheet.type
2582
+ }).parse(data, function (e, root) {
2583
+ if (e) { return error(e, href) }
2584
+ try {
2585
+ callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining });
2586
+ removeNode(document.getElementById('less-error-message:' + extractId(href)));
2587
+ } catch (e) {
2588
+ error(e, href);
2589
+ }
2590
+ });
2591
+ } catch (e) {
2592
+ error(e, href);
2593
+ }
2594
+ }
2595
+ }, function (status, url) {
2596
+ throw new(Error)("Couldn't load " + url + " (" + status + ")");
2597
+ });
2598
+ }
2599
+
2600
+ function extractId(href) {
2601
+ return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain
2602
+ .replace(/^\//, '' ) // Remove root /
2603
+ .replace(/\?.*$/, '' ) // Remove query
2604
+ .replace(/\.[^\.\/]+$/, '' ) // Remove file extension
2605
+ .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
2606
+ .replace(/\./g, ':'); // Replace dots with colons(for valid id)
2607
+ }
2608
+
2609
+ function createCSS(styles, sheet, lastModified) {
2610
+ var css;
2611
+
2612
+ // Strip the query-string
2613
+ var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';
2614
+
2615
+ // If there is no title set, use the filename, minus the extension
2616
+ var id = 'less:' + (sheet.title || extractId(href));
2617
+
2618
+ // If the stylesheet doesn't exist, create a new node
2619
+ if ((css = document.getElementById(id)) === null) {
2620
+ css = document.createElement('style');
2621
+ css.type = 'text/css';
2622
+ css.media = sheet.media || 'screen';
2623
+ css.id = id;
2624
+ document.getElementsByTagName('head')[0].appendChild(css);
2625
+ }
2626
+
2627
+ if (css.styleSheet) { // IE
2628
+ try {
2629
+ css.styleSheet.cssText = styles;
2630
+ } catch (e) {
2631
+ throw new(Error)("Couldn't reassign styleSheet.cssText.");
2632
+ }
2633
+ } else {
2634
+ (function (node) {
2635
+ if (css.childNodes.length > 0) {
2636
+ if (css.firstChild.nodeValue !== node.nodeValue) {
2637
+ css.replaceChild(node, css.firstChild);
2638
+ }
2639
+ } else {
2640
+ css.appendChild(node);
2641
+ }
2642
+ })(document.createTextNode(styles));
2643
+ }
2644
+
2645
+ // Don't update the local store if the file wasn't modified
2646
+ if (lastModified && cache) {
2647
+ log('saving ' + href + ' to cache.');
2648
+ cache.setItem(href, styles);
2649
+ cache.setItem(href + ':timestamp', lastModified);
2650
+ }
2651
+ }
2652
+
2653
+ function xhr(url, type, callback, errback) {
2654
+ var xhr = getXMLHttpRequest();
2655
+ var async = isFileProtocol ? false : less.async;
2656
+
2657
+ if (typeof(xhr.overrideMimeType) === 'function') {
2658
+ xhr.overrideMimeType('text/css');
2659
+ }
2660
+ xhr.open('GET', url, async);
2661
+ xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
2662
+ xhr.send(null);
2663
+
2664
+ if (isFileProtocol) {
2665
+ if (xhr.status === 0) {
2666
+ callback(xhr.responseText);
2667
+ } else {
2668
+ errback(xhr.status, url);
2669
+ }
2670
+ } else if (async) {
2671
+ xhr.onreadystatechange = function () {
2672
+ if (xhr.readyState == 4) {
2673
+ handleResponse(xhr, callback, errback);
2674
+ }
2675
+ };
2676
+ } else {
2677
+ handleResponse(xhr, callback, errback);
2678
+ }
2679
+
2680
+ function handleResponse(xhr, callback, errback) {
2681
+ if (xhr.status >= 200 && xhr.status < 300) {
2682
+ callback(xhr.responseText,
2683
+ xhr.getResponseHeader("Last-Modified"));
2684
+ } else if (typeof(errback) === 'function') {
2685
+ errback(xhr.status, url);
2686
+ }
2687
+ }
2688
+ }
2689
+
2690
+ function getXMLHttpRequest() {
2691
+ if (window.XMLHttpRequest) {
2692
+ return new(XMLHttpRequest);
2693
+ } else {
2694
+ try {
2695
+ return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
2696
+ } catch (e) {
2697
+ log("browser doesn't support AJAX.");
2698
+ return null;
2699
+ }
2700
+ }
2701
+ }
2702
+
2703
+ function removeNode(node) {
2704
+ return node && node.parentNode.removeChild(node);
2705
+ }
2706
+
2707
+ function log(str) {
2708
+ if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
2709
+ }
2710
+
2711
+ function error(e, href) {
2712
+ var id = 'less-error-message:' + extractId(href);
2713
+
2714
+ var template = ['<ul>',
2715
+ '<li><label>[-1]</label><pre class="ctx">{0}</pre></li>',
2716
+ '<li><label>[0]</label><pre>{current}</pre></li>',
2717
+ '<li><label>[1]</label><pre class="ctx">{2}</pre></li>',
2718
+ '</ul>'].join('\n');
2719
+
2720
+ var elem = document.createElement('div'), timer, content;
2721
+
2722
+ elem.id = id;
2723
+ elem.className = "less-error-message";
2724
+
2725
+ content = '<h3>' + (e.message || 'There is an error in your .less file') +
2726
+ '</h3>' + '<p><a href="' + href + '">' + href + "</a> ";
2727
+
2728
+ if (e.extract) {
2729
+ content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
2730
+ template.replace(/\[(-?\d)\]/g, function (_, i) {
2731
+ return (parseInt(e.line) + parseInt(i)) || '';
2732
+ }).replace(/\{(\d)\}/g, function (_, i) {
2733
+ return e.extract[parseInt(i)] || '';
2734
+ }).replace(/\{current\}/, e.extract[1].slice(0, e.column) + '<span class="error">' +
2735
+ e.extract[1].slice(e.column) + '</span>');
2736
+ }
2737
+ elem.innerHTML = content;
2738
+
2739
+ // CSS for error messages
2740
+ createCSS([
2741
+ '.less-error-message ul, .less-error-message li {',
2742
+ 'list-style-type: none;',
2743
+ 'margin-right: 15px;',
2744
+ 'padding: 4px 0;',
2745
+ 'margin: 0;',
2746
+ '}',
2747
+ '.less-error-message label {',
2748
+ 'font-size: 12px;',
2749
+ 'margin-right: 15px;',
2750
+ 'padding: 4px 0;',
2751
+ 'color: #cc7777;',
2752
+ '}',
2753
+ '.less-error-message pre {',
2754
+ 'color: #ee4444;',
2755
+ 'padding: 4px 0;',
2756
+ 'margin: 0;',
2757
+ 'display: inline-block;',
2758
+ '}',
2759
+ '.less-error-message pre.ctx {',
2760
+ 'color: #dd4444;',
2761
+ '}',
2762
+ '.less-error-message h3 {',
2763
+ 'font-size: 20px;',
2764
+ 'font-weight: bold;',
2765
+ 'padding: 15px 0 5px 0;',
2766
+ 'margin: 0;',
2767
+ '}',
2768
+ '.less-error-message a {',
2769
+ 'color: #10a',
2770
+ '}',
2771
+ '.less-error-message .error {',
2772
+ 'color: red;',
2773
+ 'font-weight: bold;',
2774
+ 'padding-bottom: 2px;',
2775
+ 'border-bottom: 1px dashed red;',
2776
+ '}'
2777
+ ].join('\n'), { title: 'error-message' });
2778
+
2779
+ elem.style.cssText = [
2780
+ "font-family: Arial, sans-serif",
2781
+ "border: 1px solid #e00",
2782
+ "background-color: #eee",
2783
+ "border-radius: 5px",
2784
+ "-webkit-border-radius: 5px",
2785
+ "-moz-border-radius: 5px",
2786
+ "color: #e00",
2787
+ "padding: 15px",
2788
+ "margin-bottom: 15px"
2789
+ ].join(';');
2790
+
2791
+ if (less.env == 'development') {
2792
+ timer = setInterval(function () {
2793
+ if (document.body) {
2794
+ if (document.getElementById(id)) {
2795
+ document.body.replaceChild(elem, document.getElementById(id));
2796
+ } else {
2797
+ document.body.insertBefore(elem, document.body.firstChild);
2798
+ }
2799
+ clearInterval(timer);
2800
+ }
2801
+ }, 10);
2802
+ }
2803
+ }
2804
+
2805
+ })(window);