Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Update LESS to v1.3.0 #40

Closed
wants to merge 2 commits into from
@Costo

Tested with Twitter Bootstrap v2.0.2, works great!

@Costo Costo Update LESS to v1.3.0
Tested with Twitter Bootstrap v2.0.2, works great!
ed2f6b2
@Costo

If you need this right now, you can replace the content of C:\Program Files (x86)\SimpLESS\Resources\js\less.js
with this version https://github.com/Costo/SimpLESS/blob/patch-1/Resources/js/less.js

Works on my machine!
Backup the file!

@Costo Costo referenced this pull request
Closed

LESS 1.3.0 ? #39

@Costo

Ok there is actually a problem with Twitter Bootstrap.
In variables.less, these two variables:

// Sprite icons path
// -------------------------
@iconSpritePath:          "../img/glyphicons-halflings.png";
@iconWhiteSpritePath:     "../img/glyphicons-halflings-white.png";

When used in sprites.less:

.icon-white {
  background-image: url('@{iconWhiteSpritePath}');
}

The resulting CSS looks like this:

.icon-white {
  background-image: url('app://com.wearekiss.simpless.open/app://com.wearekiss.simpless.open/app://com.wearekiss.simpless.open/app://com.wearekiss.simpless.open/../img/glyphicons-halflings-white.png');
}
@gagarine

Did you try with the last version of bootstrap? I think they was a bug like that on their side.

@Costo

Yes I tested with Twitter Bootstrap v2.0.2.

@mbengtson

It seems to work if you remove the if-statement in less.js right after the comment "// Add the base path if the URL is relative and we are in the browser". Will that cause any problems?

if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
}

@gagarine

I will not hack the lib by removing this. But instead calling less.js properly. How less.js is used now? Why we don't use lessc?

We can also make a "delete windows;" right before calling this script.

delete window; doesn't seem to work. It is the root object, I don't think it can be deleted.
I think the simplest option is to comment out those lines.

@gagarine

How I get it now.. SimpleLess use Titanium Desktop so we really are in a browser.

So I agree removing those lines are certainly the best we can do.

@Paratron
Owner

less.js version 1.3 will be included within our next SimpLESS update which will be released somewhere around monday next week.
There will also be be an easy way for users to update the less.js in SimpLESS without having to wait again until we provide an update by ourselves.

@lhwparis

still no new version :(

@boast

still no new version :( (+one week)

@Paratron
Owner

Yes, sorry for that. We have currently all our coding power bound to some customer projects and cant spend any time on free stuff. Because of that, the SimpLESS update will have to wait.

Notheless I have created a quick fix a few days ago to help you guys out with a recent version of the less compiler at least (i mentioned it at twitter, you guys should follow us there -> @wearekiss ).

Download http://wearekiss.com/less.js and put it in the application under resources/lib/js/less.js (replace the old file).
After a restart of the SimpLESS app, you have less compiler 1.3 available.

Sorry guys for getting this late with the app update, maybe you are familiar with our problems. I currently wish that we have 26 hours a day ;)

@itproject

Great thanks! It works :)

@ingro

Hello, I don't know if it is caused by the new less.js but the annoying url bug (which insert "app://com.wearekiss.simpless.open/" before the proper url) is back :\

@pyrokinetiq

Works perfectly, thanks! :D

@cghobbs

Any updates on this?

@mapb1990
background-image:url("app://com.wearekiss.simpless.open/app://com.wearekiss.simpless.open/../../less/app://com.wearekiss.simpless.open/app://com.wearekiss.simpless.open/../../less/../images/glyphicons-halflings.png");

Any updates on this?

@JakeWorrell

I can confirm that this works on both my MacBook Pro and my iMac at work. My Colleague has also confirmed this as working on Windows 7.

@slaur

@ingro, @mapb1990
I confirm URL bug was solved for me using the method provided by @Costo : b7c44bc

@ingro

Thank you for the info!

@Paratron
Owner

Fixed in 1.4

@Paratron Paratron closed this
@silentworks

This is not fixed as I am still getting backrgound: url(''); with some relative path, I did as @slaur pointed out and that worked for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 17, 2012
  1. @Costo

    Update LESS to v1.3.0

    Costo authored
    Tested with Twitter Bootstrap v2.0.2, works great!
Commits on Mar 20, 2012
  1. @Costo
This page is out of date. Refresh to see the latest.
Showing with 642 additions and 172 deletions.
  1. +642 −172 Resources/js/less.js
View
814 Resources/js/less.js
@@ -1,5 +1,5 @@
//
-// LESS - Leaner CSS v1.1.6
+// LESS - Leaner CSS v1.3.0
// http://lesscss.org
//
// Copyright (c) 2009-2011, Alexis Sellier
@@ -13,6 +13,12 @@ function require(arg) {
return window.less[arg.split('/')[1]];
};
+// amd.js
+//
+// Define Less as an AMD module.
+if (typeof define === "function" && define.amd) {
+ define("less", [], function () { return less; } );
+}
// ecma-5.js
//
@@ -138,7 +144,8 @@ var less, tree;
if (typeof environment === "object" && ({}).toString.call(environment) === "[object Environment]") {
// Rhino
// Details on how to detect Rhino: https://github.com/ringo/ringojs/issues/88
- less = {};
+ if (typeof(window) === 'undefined') { less = {} }
+ else { less = window.less = {} }
tree = less.tree = {};
less.mode = 'rhino';
} else if (typeof(window) === 'undefined') {
@@ -207,7 +214,9 @@ less.Parser = function Parser(env) {
paths: env && env.paths || [], // Search paths, when importing
queue: [], // Files which haven't been imported yet
files: {}, // Holds the imported parse trees
+ contents: {}, // Holds the imported file contents
mime: env && env.mime, // MIME type of .less files
+ error: null, // Error in parsing/evaluating an import
push: function (path, callback) {
var that = this;
this.queue.push(path);
@@ -215,11 +224,13 @@ less.Parser = function Parser(env) {
//
// Import a file asynchronously
//
- less.Parser.importer(path, this.paths, function (root) {
+ less.Parser.importer(path, this.paths, function (e, root, contents) {
that.queue.splice(that.queue.indexOf(path), 1); // Remove the path from the queue
that.files[path] = root; // Store the root
+ that.contents[path] = contents;
- callback(root);
+ if (e && !that.error) { that.error = e }
+ callback(e, root);
if (that.queue.length === 0) { finish() } // Call `finish` if we're done importing
}, env);
@@ -293,6 +304,20 @@ less.Parser = function Parser(env) {
}
}
+ function expect(arg, msg) {
+ var result = $(arg);
+ if (! result) {
+ error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
+ : "unexpected token"));
+ } else {
+ return result;
+ }
+ }
+
+ function error(msg, type) {
+ throw { index: i, type: type || 'Syntax', message: msg };
+ }
+
// Same as $(), but don't change the state of the parser,
// just return the match.
function peek(tok) {
@@ -307,6 +332,54 @@ less.Parser = function Parser(env) {
}
}
+ function basename(pathname) {
+ if (less.mode === 'node') {
+ return require('path').basename(pathname);
+ } else {
+ return pathname.match(/[^\/]+$/)[0];
+ }
+ }
+
+ function getInput(e, env) {
+ if (e.filename && env.filename && (e.filename !== env.filename)) {
+ return parser.imports.contents[basename(e.filename)];
+ } else {
+ return input;
+ }
+ }
+
+ function getLocation(index, input) {
+ for (var n = index, column = -1;
+ n >= 0 && input.charAt(n) !== '\n';
+ n--) { column++ }
+
+ return { line: typeof(index) === 'number' ? (input.slice(0, index).match(/\n/g) || "").length : null,
+ column: column };
+ }
+
+ function LessError(e, env) {
+ var input = getInput(e, env),
+ loc = getLocation(e.index, input),
+ line = loc.line,
+ col = loc.column,
+ lines = input.split('\n');
+
+ this.type = e.type || 'Syntax';
+ this.message = e.message;
+ this.filename = e.filename || env.filename;
+ this.index = e.index;
+ this.line = typeof(line) === 'number' ? line + 1 : null;
+ this.callLine = e.call && (getLocation(e.call, input).line + 1);
+ this.callExtract = lines[getLocation(e.call, input).line];
+ this.stack = e.stack;
+ this.column = col;
+ this.extract = [
+ lines[line - 1],
+ lines[line],
+ lines[line + 1]
+ ];
+ }
+
this.env = env = env || {};
// The optimization level dictates the thoroughness of the parser,
@@ -331,19 +404,18 @@ less.Parser = function Parser(env) {
var root, start, end, zone, line, lines, buff = [], c, error = null;
i = j = current = furthest = 0;
- chunks = [];
input = str.replace(/\r\n/g, '\n');
// Split the input into chunks.
chunks = (function (chunks) {
var j = 0,
- skip = /[^"'`\{\}\/\(\)]+/g,
+ skip = /[^"'`\{\}\/\(\)\\]+/g,
comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
+ string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`\\\r\n]|\\.)*)`/g,
level = 0,
match,
chunk = chunks[0],
- inParam,
- inString;
+ inParam;
for (var i = 0, c, cc; i < input.length; i++) {
skip.lastIndex = i;
@@ -354,9 +426,17 @@ less.Parser = function Parser(env) {
}
}
c = input.charAt(i);
- comment.lastIndex = i;
+ comment.lastIndex = string.lastIndex = i;
+
+ if (match = string.exec(input)) {
+ if (match.index === i) {
+ i += match[0].length;
+ chunk.push(match[0]);
+ c = input.charAt(i);
+ }
+ }
- if (!inString && !inParam && c === '/') {
+ if (!inParam && c === '/') {
cc = input.charAt(i + 1);
if (cc === '/' || cc === '*') {
if (match = comment.exec(input)) {
@@ -369,51 +449,46 @@ less.Parser = function Parser(env) {
}
}
- if (c === '{' && !inString && !inParam) { level ++;
- chunk.push(c);
- } else if (c === '}' && !inString && !inParam) { level --;
- chunk.push(c);
- chunks[++j] = chunk = [];
- } else if (c === '(' && !inString && !inParam) {
- chunk.push(c);
- inParam = true;
- } else if (c === ')' && !inString && inParam) {
- chunk.push(c);
- inParam = false;
- } else {
- if (c === '"' || c === "'" || c === '`') {
- if (! inString) {
- inString = c;
- } else {
- inString = inString === c ? false : inString;
- }
- }
- chunk.push(c);
+ switch (c) {
+ case '{': if (! inParam) { level ++; chunk.push(c); break }
+ case '}': if (! inParam) { level --; chunk.push(c); chunks[++j] = chunk = []; break }
+ case '(': if (! inParam) { inParam = true; chunk.push(c); break }
+ case ')': if ( inParam) { inParam = false; chunk.push(c); break }
+ default: chunk.push(c);
}
}
if (level > 0) {
- throw {
- type: 'Syntax',
- message: "Missing closing `}`",
+ error = new(LessError)({
+ index: i,
+ type: 'Parse',
+ message: "missing closing `}`",
filename: env.filename
- };
+ }, env);
}
return chunks.map(function (c) { return c.join('') });;
})([[]]);
+ if (error) {
+ return callback(error);
+ }
+
// Start with the primary rule.
// The whole syntax tree is held under a Ruleset node,
// with the `root` property set to true, so no `{}` are
// output. The callback is called when the input is parsed.
- root = new(tree.Ruleset)([], $(this.parsers.primary));
- root.root = true;
+ try {
+ root = new(tree.Ruleset)([], $(this.parsers.primary));
+ root.root = true;
+ } catch (e) {
+ return callback(new(LessError)(e, env));
+ }
root.toCSS = (function (evaluate) {
var line, lines, column;
return function (options, variables) {
- var frames = [];
+ var frames = [], importError;
options = options || {};
//
@@ -448,30 +523,14 @@ less.Parser = function Parser(env) {
var css = evaluate.call(this, { frames: frames })
.toCSS([], { compress: options.compress || false });
} catch (e) {
- lines = input.split('\n');
- line = getLine(e.index);
-
- for (var n = e.index, column = -1;
- n >= 0 && input.charAt(n) !== '\n';
- n--) { column++ }
-
- throw {
- type: e.type,
- message: e.message,
- filename: env.filename,
- index: e.index,
- line: typeof(line) === 'number' ? line + 1 : null,
- callLine: e.call && (getLine(e.call) + 1),
- callExtract: lines[getLine(e.call)],
- stack: e.stack,
- column: column,
- extract: [
- lines[line - 1],
- lines[line],
- lines[line + 1]
- ]
- };
+ throw new(LessError)(e, env);
}
+
+ if ((importError = parser.imports.error)) { // Check if there was an error during importing
+ if (importError instanceof LessError) throw importError;
+ else throw new(LessError)(importError, env);
+ }
+
if (options.yuicompress && less.mode === 'node') {
return require('./cssmin').compressor.cssmin(css);
} else if (options.compress) {
@@ -479,10 +538,6 @@ less.Parser = function Parser(env) {
} else {
return css;
}
-
- function getLine(index) {
- return index ? (input.slice(0, index).match(/\n/g) || "").length : null;
- }
};
})(root.eval);
@@ -502,7 +557,7 @@ less.Parser = function Parser(env) {
for (var n = i, column = -1; n >= 0 && input.charAt(n) !== '\n'; n--) { column++ }
error = {
- name: "ParseError",
+ type: "Parse",
message: "Syntax Error on line " + line,
index: i,
filename: env.filename,
@@ -629,7 +684,7 @@ less.Parser = function Parser(env) {
// detect named color
return new(tree.Color)(tree.colors[k].slice(1));
} else {
- return new(tree.Keyword)(k)
+ return new(tree.Keyword)(k);
}
}
},
@@ -662,7 +717,7 @@ less.Parser = function Parser(env) {
if (! $(')')) return;
- if (name) { return new(tree.Call)(name, args, index) }
+ if (name) { return new(tree.Call)(name, args, index, env.filename) }
},
arguments: function () {
var args = [], arg;
@@ -705,7 +760,8 @@ less.Parser = function Parser(env) {
if (input.charAt(i) !== 'u' || !$(/^url\(/)) return;
value = $(this.entities.quoted) || $(this.entities.variable) ||
$(this.entities.dataURI) || $(/^[-\w%@$\/.&=:;#+?~]+/) || "";
- if (! $(')')) throw new(Error)("missing closing ) for url()");
+
+ expect(')');
return new(tree.URL)((value.value || value.data || value instanceof tree.Variable)
? value : new(tree.Anonymous)(value), imports.paths);
@@ -737,7 +793,7 @@ less.Parser = function Parser(env) {
var name, index = i;
if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
- return new(tree.Variable)(name, index);
+ return new(tree.Variable)(name, index, env.filename);
}
},
@@ -833,7 +889,7 @@ less.Parser = function Parser(env) {
// selector for now.
//
call: function () {
- var elements = [], e, c, args, index = i, s = input.charAt(i);
+ var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
if (s !== '.' && s !== '#') { return }
@@ -843,8 +899,12 @@ less.Parser = function Parser(env) {
}
$('(') && (args = $(this.entities.arguments)) && $(')');
+ if ($(this.important)) {
+ important = true;
+ }
+
if (elements.length > 0 && ($(';') || peek('}'))) {
- return new(tree.mixin.Call)(elements, args, index);
+ return new(tree.mixin.Call)(elements, args || [], index, env.filename, important);
}
},
@@ -868,38 +928,53 @@ less.Parser = function Parser(env) {
// the `{...}` block.
//
definition: function () {
- var name, params = [], match, ruleset, param, value;
-
+ var name, params = [], match, ruleset, param, value, cond, variadic = false;
if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
peek(/^[^{]*(;|})/)) return;
+ save();
+
if (match = $(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)) {
name = match[1];
- while (param = $(this.entities.variable) || $(this.entities.literal)
- || $(this.entities.keyword)) {
- // Variable
- if (param instanceof tree.Variable) {
- if ($(':')) {
- if (value = $(this.expression)) {
+ do {
+ if (input.charAt(i) === '.' && $(/^\.{3}/)) {
+ variadic = true;
+ break;
+ } else if (param = $(this.entities.variable) || $(this.entities.literal)
+ || $(this.entities.keyword)) {
+ // Variable
+ if (param instanceof tree.Variable) {
+ if ($(':')) {
+ value = expect(this.expression, 'expected expression');
params.push({ name: param.name, value: value });
+ } else if ($(/^\.{3}/)) {
+ params.push({ name: param.name, variadic: true });
+ variadic = true;
+ break;
} else {
- throw new(Error)("Expected value");
+ params.push({ name: param.name });
}
} else {
- params.push({ name: param.name });
+ params.push({ value: param });
}
} else {
- params.push({ value: param });
+ break;
}
- if (! $(',')) { break }
+ } while ($(','))
+
+ expect(')');
+
+ if ($(/^when/)) { // Guard
+ cond = expect(this.conditions, 'expected condition');
}
- if (! $(')')) throw new(Error)("Expected )");
ruleset = $(this.block);
if (ruleset) {
- return new(tree.mixin.Definition)(name, params, ruleset);
+ return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
+ } else {
+ restore();
}
}
}
@@ -934,7 +1009,7 @@ less.Parser = function Parser(env) {
if (! $(/^\(opacity=/i)) return;
if (value = $(/^\d+/) || $(this.entities.variable)) {
- if (! $(')')) throw new(Error)("missing closing ) for alpha()");
+ expect(')');
return new(tree.Alpha)(value);
}
},
@@ -952,12 +1027,16 @@ less.Parser = function Parser(env) {
// and an element name, such as a tag a class, or `*`.
//
element: function () {
- var e, t, c;
+ var e, t, c, v;
c = $(this.combinator);
e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) ||
$('*') || $(this.attribute) || $(/^\([^)@]+\)/);
+ if (! e) {
+ $('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
+ }
+
if (e) { return new(tree.Element)(c, e, i) }
if (c.value && c.value.charAt(0) === '&') {
@@ -989,10 +1068,6 @@ less.Parser = function Parser(env) {
}
while (input.charAt(i) === ' ') { i++ }
return new(tree.Combinator)(match);
- } else if (c === ':' && input.charAt(i + 1) === ':') {
- i += 2;
- while (input.charAt(i) === ' ') { i++ }
- return new(tree.Combinator)('::');
} else if (input.charAt(i - 1) === ' ') {
return new(tree.Combinator)(" ");
} else {
@@ -1011,6 +1086,12 @@ less.Parser = function Parser(env) {
selector: function () {
var sel, e, elements = [], c, match;
+ if ($('(')) {
+ sel = $(this.entity);
+ expect(')');
+ return new(tree.Selector)([new(tree.Element)('', sel, i)]);
+ }
+
while (e = $(this.element)) {
c = input.charAt(i);
elements.push(e)
@@ -1066,7 +1147,7 @@ less.Parser = function Parser(env) {
}
if (selectors.length > 0 && (rules = $(this.block))) {
- return new(tree.Ruleset)(selectors, rules);
+ return new(tree.Ruleset)(selectors, rules, env.strictImports);
} else {
// Backtrack
furthest = i;
@@ -1110,11 +1191,67 @@ less.Parser = function Parser(env) {
// stored in `import`, which we pass to the Import constructor.
//
"import": function () {
- var path;
+ var path, features, index = i;
if ($(/^@import\s+/) &&
- (path = $(this.entities.quoted) || $(this.entities.url)) &&
- $(';')) {
- return new(tree.Import)(path, imports);
+ (path = $(this.entities.quoted) || $(this.entities.url))) {
+ features = $(this.mediaFeatures);
+ if ($(';')) {
+ return new(tree.Import)(path, imports, features, index);
+ }
+ }
+ },
+
+ mediaFeature: function () {
+ var e, p, nodes = [];
+
+ do {
+ if (e = $(this.entities.keyword)) {
+ nodes.push(e);
+ } else if ($('(')) {
+ p = $(this.property);
+ e = $(this.entity);
+ if ($(')')) {
+ if (p && e) {
+ nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, true)));
+ } else if (e) {
+ nodes.push(new(tree.Paren)(e));
+ } else {
+ return null;
+ }
+ } else { return null }
+ }
+ } while (e);
+
+ if (nodes.length > 0) {
+ return new(tree.Expression)(nodes);
+ }
+ },
+
+ mediaFeatures: function () {
+ var e, features = [];
+
+ do {
+ if (e = $(this.mediaFeature)) {
+ features.push(e);
+ if (! $(',')) { break }
+ } else if (e = $(this.entities.variable)) {
+ features.push(e);
+ if (! $(',')) { break }
+ }
+ } while (e);
+
+ return features.length > 0 ? features : null;
+ },
+
+ media: function () {
+ var features, rules;
+
+ if ($(/^@media/)) {
+ features = $(this.mediaFeatures);
+
+ if (rules = $(this.block)) {
+ return new(tree.Media)(rules, features);
+ }
}
},
@@ -1124,13 +1261,13 @@ less.Parser = function Parser(env) {
// @charset "utf-8";
//
directive: function () {
- var name, value, rules, types;
+ var name, value, rules, types, e, nodes;
if (input.charAt(i) !== '@') return;
- if (value = $(this['import'])) {
+ if (value = $(this['import']) || $(this.media)) {
return value;
- } else if (name = $(/^@media|@page/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/) || $('keyframes')) {
+ } else if (name = $(/^@page|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
types = ($(/^[^{]+/) || '').trim();
if (rules = $(this.block)) {
return new(tree.Directive)(name + " " + types, rules);
@@ -1213,6 +1350,35 @@ less.Parser = function Parser(env) {
return operation || m;
}
},
+ conditions: function () {
+ var a, b, index = i, condition;
+
+ if (a = $(this.condition)) {
+ while ($(',') && (b = $(this.condition))) {
+ condition = new(tree.Condition)('or', condition || a, b, index);
+ }
+ return condition || a;
+ }
+ },
+ condition: function () {
+ var a, b, c, op, index = i, negate = false;
+
+ if ($(/^not/)) { negate = true }
+ expect('(');
+ if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
+ if (op = $(/^(?:>=|=<|[<=>])/)) {
+ if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
+ c = new(tree.Condition)(op, a, b, index, negate);
+ } else {
+ error('expected expression');
+ }
+ } else {
+ c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
+ }
+ expect(')');
+ return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
+ }
+ },
//
// An operand is anything that can be part of an operation,
@@ -1262,13 +1428,19 @@ if (less.mode === 'browser' || less.mode === 'rhino') {
// Used by `@import` directives
//
less.Parser.importer = function (path, paths, callback, env) {
- if (path.charAt(0) !== '/' && paths.length > 0) {
+ if (!/^([a-z]+:)?\//.test(path) && paths.length > 0) {
path = paths[0] + path;
}
// We pass `true` as 3rd argument, to force the reload of the import.
// This is so we can get the syntax tree as opposed to just the CSS output,
// as we need this to evaluate the current stylesheet.
- loadStyleSheet({ href: path, title: path, type: env.mime }, callback, true);
+ loadStyleSheet({ href: path, title: path, type: env.mime }, function (e) {
+ if (e && typeof(env.errback) === "function") {
+ env.errback.call(null, path, paths, callback, env);
+ } else {
+ callback.apply(null, arguments);
+ }
+ }, true);
};
}
@@ -1432,15 +1604,49 @@ tree.functions = {
} else if (typeof(n) === 'number') {
return Math[fn](n);
} else {
- throw {
- error: "RuntimeError",
- message: "math functions take numbers as parameters"
- };
+ throw { type: "Argument", message: "argument must be a number" };
}
},
argb: function (color) {
return new(tree.Anonymous)(color.toARGB());
+ },
+ percentage: function (n) {
+ return new(tree.Dimension)(n.value * 100, '%');
+ },
+ color: function (n) {
+ if (n instanceof tree.Quoted) {
+ return new(tree.Color)(n.value.slice(1));
+ } else {
+ throw { type: "Argument", message: "argument must be a string" };
+ }
+ },
+ iscolor: function (n) {
+ return this._isa(n, tree.Color);
+ },
+ isnumber: function (n) {
+ return this._isa(n, tree.Dimension);
+ },
+ isstring: function (n) {
+ return this._isa(n, tree.Quoted);
+ },
+ iskeyword: function (n) {
+ return this._isa(n, tree.Keyword);
+ },
+ isurl: function (n) {
+ return this._isa(n, tree.URL);
+ },
+ ispixel: function (n) {
+ return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False;
+ },
+ ispercentage: function (n) {
+ return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False;
+ },
+ isem: function (n) {
+ return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False;
+ },
+ _isa: function (n, Type) {
+ return (n instanceof Type) ? tree.True : tree.False;
}
};
@@ -1668,10 +1874,11 @@ tree.Assignment.prototype = {
//
// A function call node.
//
-tree.Call = function (name, args, index) {
+tree.Call = function (name, args, index, filename) {
this.name = name;
this.args = args;
this.index = index;
+ this.filename = filename;
};
tree.Call.prototype = {
//
@@ -1693,8 +1900,10 @@ tree.Call.prototype = {
try {
return tree.functions[this.name].apply(tree.functions, args);
} catch (e) {
- throw { message: "error evaluating function `" + this.name + "`",
- index: this.index };
+ throw { type: e.type || "Runtime",
+ message: "error evaluating function `" + this.name + "`" +
+ (e.message ? ': ' + e.message : ''),
+ index: this.index, filename: this.filename };
}
} else { // 2.
return new(tree.Anonymous)(this.name +
@@ -1825,6 +2034,48 @@ tree.Comment.prototype = {
})(require('../tree'));
(function (tree) {
+tree.Condition = function (op, l, r, i, negate) {
+ this.op = op.trim();
+ this.lvalue = l;
+ this.rvalue = r;
+ this.index = i;
+ this.negate = negate;
+};
+tree.Condition.prototype.eval = function (env) {
+ var a = this.lvalue.eval(env),
+ b = this.rvalue.eval(env);
+
+ var i = this.index, result;
+
+ var result = (function (op) {
+ switch (op) {
+ case 'and':
+ return a && b;
+ case 'or':
+ return a || b;
+ default:
+ if (a.compare) {
+ result = a.compare(b);
+ } else if (b.compare) {
+ result = b.compare(a);
+ } else {
+ throw { type: "Type",
+ message: "Unable to perform comparison",
+ index: i };
+ }
+ switch (result) {
+ case -1: return op === '<' || op === '=<';
+ case 0: return op === '=' || op === '>=' || op === '=<';
+ case 1: return op === '>' || op === '>=';
+ }
+ }
+ })(this.op);
+ return this.negate ? !result : result;
+};
+
+})(require('../tree'));
+(function (tree) {
+
//
// A number with a unit
//
@@ -1853,16 +2104,33 @@ tree.Dimension.prototype = {
return new(tree.Dimension)
(tree.operate(op, this.value, other.value),
this.unit || other.unit);
+ },
+
+ // TODO: Perform unit conversion before comparing
+ compare: function (other) {
+ if (other instanceof tree.Dimension) {
+ if (other.value > this.value) {
+ return -1;
+ } else if (other.value < this.value) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return -1;
+ }
}
};
})(require('../tree'));
(function (tree) {
-tree.Directive = function (name, value) {
+tree.Directive = function (name, value, features) {
this.name = name;
+
if (Array.isArray(value)) {
this.ruleset = new(tree.Ruleset)([], value);
+ this.ruleset.allowImports = true;
} else {
this.value = value;
}
@@ -1895,11 +2163,23 @@ tree.Directive.prototype = {
tree.Element = function (combinator, value, index) {
this.combinator = combinator instanceof tree.Combinator ?
combinator : new(tree.Combinator)(combinator);
- this.value = value ? value.trim() : "";
+
+ if (typeof(value) === 'string') {
+ this.value = value.trim();
+ } else if (value) {
+ this.value = value;
+ } else {
+ this.value = "";
+ }
this.index = index;
};
+tree.Element.prototype.eval = function (env) {
+ return new(tree.Element)(this.combinator,
+ this.value.eval ? this.value.eval(env) : this.value,
+ this.index);
+};
tree.Element.prototype.toCSS = function (env) {
- return this.combinator.toCSS(env || {}) + this.value;
+ return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
};
tree.Combinator = function (value) {
@@ -1918,7 +2198,6 @@ tree.Combinator.prototype.toCSS = function (env) {
'&' : '',
'& ' : ' ',
':' : ' :',
- '::': '::',
'+' : env.compress ? '+' : ' + ',
'~' : env.compress ? '~' : ' ~ ',
'>' : env.compress ? '>' : ' > '
@@ -1943,7 +2222,7 @@ tree.Expression.prototype = {
},
toCSS: function (env) {
return this.value.map(function (e) {
- return e.toCSS(env);
+ return e.toCSS ? e.toCSS(env) : '';
}).join(' ');
}
};
@@ -1962,10 +2241,12 @@ tree.Expression.prototype = {
// `import,push`, we also pass it a callback, which it'll call once
// the file has been fetched, and parsed.
//
-tree.Import = function (path, imports) {
+tree.Import = function (path, imports, features, index) {
var that = this;
+ this.index = index;
this._path = path;
+ this.features = features && new(tree.Value)(features);
// The '.less' extension is optional
if (path instanceof tree.Quoted) {
@@ -1978,11 +2259,9 @@ tree.Import = function (path, imports) {
// Only pre-compile .less files
if (! this.css) {
- imports.push(this.path, function (root) {
- if (! root) {
- throw new(Error)("Error parsing " + that.path);
- }
- that.root = root;
+ imports.push(this.path, function (e, root) {
+ if (e) { e.index = index }
+ that.root = root || new(tree.Ruleset)([], []);
});
}
};
@@ -1997,20 +2276,22 @@ tree.Import = function (path, imports) {
// ruleset.
//
tree.Import.prototype = {
- toCSS: function () {
+ toCSS: function (env) {
+ var features = this.features ? ' ' + this.features.toCSS(env) : '';
+
if (this.css) {
- return "@import " + this._path.toCSS() + ';\n';
+ return "@import " + this._path.toCSS() + features + ';\n';
} else {
return "";
}
},
eval: function (env) {
- var ruleset;
+ var ruleset, features = this.features && this.features.eval(env);
if (this.css) {
return this;
} else {
- ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));
+ ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
for (var i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.Import) {
@@ -2020,7 +2301,7 @@ tree.Import.prototype = {
[i, 1].concat(ruleset.rules[i].eval(env)));
}
}
- return ruleset.rules;
+ return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
}
}
};
@@ -2082,17 +2363,143 @@ tree.JavaScript.prototype = {
tree.Keyword = function (value) { this.value = value };
tree.Keyword.prototype = {
eval: function () { return this },
- toCSS: function () { return this.value }
+ toCSS: function () { return this.value },
+ compare: function (other) {
+ if (other instanceof tree.Keyword) {
+ return other.value === this.value ? 0 : 1;
+ } else {
+ return -1;
+ }
+ }
+};
+
+tree.True = new(tree.Keyword)('true');
+tree.False = new(tree.Keyword)('false');
+
+})(require('../tree'));
+(function (tree) {
+
+tree.Media = function (value, features) {
+ var el = new(tree.Element)('&', null, 0),
+ selectors = [new(tree.Selector)([el])];
+
+ this.features = new(tree.Value)(features);
+ this.ruleset = new(tree.Ruleset)(selectors, value);
+ this.ruleset.allowImports = true;
+};
+tree.Media.prototype = {
+ toCSS: function (ctx, env) {
+ var features = this.features.toCSS(env);
+
+ this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
+ return '@media ' + features + (env.compress ? '{' : ' {\n ') +
+ this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
+ (env.compress ? '}': '\n}\n');
+ },
+ eval: function (env) {
+ if (!env.mediaBlocks) {
+ env.mediaBlocks = [];
+ env.mediaPath = [];
+ }
+
+ var blockIndex = env.mediaBlocks.length;
+ env.mediaPath.push(this);
+ env.mediaBlocks.push(this);
+
+ var media = new(tree.Media)([], []);
+ media.features = this.features.eval(env);
+
+ env.frames.unshift(this.ruleset);
+ media.ruleset = this.ruleset.eval(env);
+ env.frames.shift();
+
+ env.mediaBlocks[blockIndex] = media;
+ env.mediaPath.pop();
+
+ return env.mediaPath.length === 0 ? media.evalTop(env) :
+ media.evalNested(env)
+ },
+ variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
+ find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
+ rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
+
+ evalTop: function (env) {
+ var result = this;
+
+ // Render all dependent Media blocks.
+ if (env.mediaBlocks.length > 1) {
+ var el = new(tree.Element)('&', null, 0);
+ var selectors = [new(tree.Selector)([el])];
+ result = new(tree.Ruleset)(selectors, env.mediaBlocks);
+ result.multiMedia = true;
+ }
+
+ delete env.mediaBlocks;
+ delete env.mediaPath;
+
+ return result;
+ },
+ evalNested: function (env) {
+ var i, value,
+ path = env.mediaPath.concat([this]);
+
+ // Extract the media-query conditions separated with `,` (OR).
+ for (i = 0; i < path.length; i++) {
+ value = path[i].features instanceof tree.Value ?
+ path[i].features.value : path[i].features;
+ path[i] = Array.isArray(value) ? value : [value];
+ }
+
+ // Trace all permutations to generate the resulting media-query.
+ //
+ // (a, b and c) with nested (d, e) ->
+ // a and d
+ // a and e
+ // b and c and d
+ // b and c and e
+ this.features = new(tree.Value)(this.permute(path).map(function (path) {
+ path = path.map(function (fragment) {
+ return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
+ });
+
+ for(i = path.length - 1; i > 0; i--) {
+ path.splice(i, 0, new(tree.Anonymous)("and"));
+ }
+
+ return new(tree.Expression)(path);
+ }));
+
+ // Fake a tree-node that doesn't output anything.
+ return new(tree.Ruleset)([], []);
+ },
+ permute: function (arr) {
+ if (arr.length === 0) {
+ return [];
+ } else if (arr.length === 1) {
+ return arr[0];
+ } else {
+ var result = [];
+ var rest = this.permute(arr.slice(1));
+ for (var i = 0; i < rest.length; i++) {
+ for (var j = 0; j < arr[0].length; j++) {
+ result.push([arr[0][j]].concat(rest[i]));
+ }
+ }
+ return result;
+ }
+ }
};
})(require('../tree'));
(function (tree) {
tree.mixin = {};
-tree.mixin.Call = function (elements, args, index) {
+tree.mixin.Call = function (elements, args, index, filename, important) {
this.selector = new(tree.Selector)(elements);
this.arguments = args;
this.index = index;
+ this.filename = filename;
+ this.important = important;
};
tree.mixin.Call.prototype = {
eval: function (env) {
@@ -2105,34 +2512,38 @@ tree.mixin.Call.prototype = {
if (mixins[m].match(args, env)) {
try {
Array.prototype.push.apply(
- rules, mixins[m].eval(env, this.arguments).rules);
+ rules, mixins[m].eval(env, this.arguments, this.important).rules);
match = true;
} catch (e) {
- throw { message: e.message, index: e.index, stack: e.stack, call: this.index };
+ throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
}
}
}
if (match) {
return rules;
} else {
- throw { message: 'No matching definition was found for `' +
+ throw { type: 'Runtime',
+ message: 'No matching definition was found for `' +
this.selector.toCSS().trim() + '(' +
this.arguments.map(function (a) {
return a.toCSS();
}).join(', ') + ")`",
- index: this.index };
+ index: this.index, filename: this.filename };
}
}
}
- throw { message: this.selector.toCSS().trim() + " is undefined",
- index: this.index };
+ throw { type: 'Name',
+ message: this.selector.toCSS().trim() + " is undefined",
+ index: this.index, filename: this.filename };
}
};
-tree.mixin.Definition = function (name, params, rules) {
+tree.mixin.Definition = function (name, params, rules, condition, variadic) {
this.name = name;
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
this.params = params;
+ this.condition = condition;
+ this.variadic = variadic;
this.arity = params.length;
this.rules = rules;
this._lookups = {};
@@ -2150,33 +2561,56 @@ tree.mixin.Definition.prototype = {
find: function () { return this.parent.find.apply(this, arguments) },
rulesets: function () { return this.parent.rulesets.apply(this) },
- eval: function (env, args) {
- var frame = new(tree.Ruleset)(null, []), context, _arguments = [];
+ evalParams: function (env, args) {
+ var frame = new(tree.Ruleset)(null, []), varargs;
- for (var i = 0, val; i < this.params.length; i++) {
- if (this.params[i].name) {
- if (val = (args && args[i]) || this.params[i].value) {
- frame.rules.unshift(new(tree.Rule)(this.params[i].name, val.eval(env)));
+ for (var i = 0, val, name; i < this.params.length; i++) {
+ if (name = this.params[i].name) {
+ if (this.params[i].variadic && args) {
+ varargs = [];
+ for (var j = i; j < args.length; j++) {
+ varargs.push(args[j].eval(env));
+ }
+ frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
+ } else if (val = (args && args[i]) || this.params[i].value) {
+ frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
} else {
- throw { message: "wrong number of arguments for " + this.name +
+ throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
' (' + args.length + ' for ' + this.arity + ')' };
}
}
}
+ return frame;
+ },
+ eval: function (env, args, important) {
+ var frame = this.evalParams(env, args), context, _arguments = [], rules, start;
+
for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
_arguments.push(args[i] || this.params[i].value);
}
frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
- return new(tree.Ruleset)(null, this.rules.slice(0)).eval({
+ rules = important ?
+ this.rules.map(function (r) {
+ return new(tree.Rule)(r.name, r.value, '!important', r.index);
+ }) : this.rules.slice(0);
+
+ return new(tree.Ruleset)(null, rules).eval({
frames: [this, frame].concat(this.frames, env.frames)
});
},
match: function (args, env) {
- var argsLength = (args && args.length) || 0, len;
+ var argsLength = (args && args.length) || 0, len, frame;
- if (argsLength < this.required) { return false }
- if ((this.required > 0) && (argsLength > this.params.length)) { return false }
+ if (! this.variadic) {
+ if (argsLength < this.required) { return false }
+ if (argsLength > this.params.length) { return false }
+ if ((this.required > 0) && (argsLength > this.params.length)) { return false }
+ }
+
+ if (this.condition && !this.condition.eval({
+ frames: [this.evalParams(env, args)].concat(env.frames)
+ })) { return false }
len = Math.min(argsLength, this.arity);
@@ -2224,6 +2658,22 @@ tree.operate = function (op, a, b) {
};
})(require('../tree'));
+
+(function (tree) {
+
+tree.Paren = function (node) {
+ this.value = node;
+};
+tree.Paren.prototype = {
+ toCSS: function (env) {
+ return '(' + this.value.toCSS(env) + ')';
+ },
+ eval: function (env) {
+ return new(tree.Paren)(this.value.eval(env));
+ }
+};
+
+})(require('../tree'));
(function (tree) {
tree.Quoted = function (str, content, escaped, i) {
@@ -2246,7 +2696,7 @@ tree.Quoted.prototype = {
return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
}).replace(/@\{([\w-]+)\}/g, function (_, name) {
var v = new(tree.Variable)('@' + name, that.index).eval(env);
- return v.value || v.toCSS();
+ return ('value' in v) ? v.value : v.toCSS();
});
return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
}
@@ -2255,11 +2705,12 @@ tree.Quoted.prototype = {
})(require('../tree'));
(function (tree) {
-tree.Rule = function (name, value, important, index) {
+tree.Rule = function (name, value, important, index, inline) {
this.name = name;
this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
this.important = important ? ' ' + important.trim() : '';
this.index = index;
+ this.inline = inline || false;
if (name.charAt(0) === '@') {
this.variable = true;
@@ -2270,12 +2721,15 @@ tree.Rule.prototype.toCSS = function (env) {
else {
return this.name + (env.compress ? ':' : ': ') +
this.value.toCSS(env) +
- this.important + ";";
+ this.important + (this.inline ? "" : ";");
}
};
tree.Rule.prototype.eval = function (context) {
- return new(tree.Rule)(this.name, this.value.eval(context), this.important, this.index);
+ return new(tree.Rule)(this.name,
+ this.value.eval(context),
+ this.important,
+ this.index, this.inline);
};
tree.Shorthand = function (a, b) {
@@ -2293,22 +2747,25 @@ tree.Shorthand.prototype = {
})(require('../tree'));
(function (tree) {
-tree.Ruleset = function (selectors, rules) {
+tree.Ruleset = function (selectors, rules, strictImports) {
this.selectors = selectors;
this.rules = rules;
this._lookups = {};
+ this.strictImports = strictImports;
};
tree.Ruleset.prototype = {
eval: function (env) {
- var ruleset = new(tree.Ruleset)(this.selectors, this.rules.slice(0));
+ var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
+ var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
ruleset.root = this.root;
+ ruleset.allowImports = this.allowImports;
// push the current ruleset to the frames stack
env.frames.unshift(ruleset);
// Evaluate imports
- if (ruleset.root) {
+ if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
for (var i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.Import) {
Array.prototype.splice
@@ -2413,7 +2870,7 @@ tree.Ruleset.prototype = {
if (context.length === 0) {
paths = this.selectors.map(function (s) { return [s] });
} else {
- this.joinSelectors( paths, context, this.selectors );
+ this.joinSelectors(paths, context, this.selectors);
}
}
@@ -2421,7 +2878,7 @@ tree.Ruleset.prototype = {
for (var i = 0; i < this.rules.length; i++) {
rule = this.rules[i];
- if (rule.rules || (rule instanceof tree.Directive)) {
+ if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) {
rulesets.push(rule.toCSS(paths, env));
} else if (rule instanceof tree.Comment) {
if (!rule.silent) {
@@ -2453,7 +2910,8 @@ tree.Ruleset.prototype = {
return p.map(function (s) {
return s.toCSS(env);
}).join('').trim();
- }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
+ }).join( env.compress ? ',' : ',\n');
+
css.push(selector,
(env.compress ? '{' : ' {\n ') +
rules.join(env.compress ? '' : '\n ') +
@@ -2527,6 +2985,11 @@ tree.Selector.prototype.match = function (other) {
}
return true;
};
+tree.Selector.prototype.eval = function (env) {
+ return new(tree.Selector)(this.elements.map(function (e) {
+ return e.eval(env);
+ }));
+};
tree.Selector.prototype.toCSS = function (env) {
if (this._css) { return this._css }
@@ -2547,11 +3010,10 @@ tree.URL = function (val, paths) {
this.attrs = val;
} else {
// Add the base path if the URL is relative and we are in the browser
- if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
- //@TODO: remove paths
- val.value = (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
- //val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
- }
+ // Note: Commented out for SimpLESS
+ //if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
+ // val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
+ //}
this.value = val;
this.paths = paths;
}
@@ -2593,7 +3055,7 @@ tree.Value.prototype = {
})(require('../tree'));
(function (tree) {
-tree.Variable = function (name, index) { this.name = name, this.index = index };
+tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file };
tree.Variable.prototype = {
eval: function (env) {
var variable, v, name = this.name;
@@ -2608,26 +3070,32 @@ tree.Variable.prototype = {
}
})) { return variable }
else {
- throw { message: "variable " + name + " is undefined",
+ throw { type: 'Name',
+ message: "variable " + name + " is undefined",
+ filename: this.file,
index: this.index };
}
}
};
})(require('../tree'));
-require('./tree').find = function (obj, fun) {
+(function (tree) {
+
+tree.find = function (obj, fun) {
for (var i = 0, r; i < obj.length; i++) {
if (r = fun.call(obj, obj[i])) { return r }
}
return null;
};
-require('./tree').jsify = function (obj) {
+tree.jsify = function (obj) {
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
} else {
return obj.toCSS(false);
}
};
+
+})(require('./tree'));
//
// browser.js - client-side engine
//
@@ -2669,7 +3137,7 @@ if (less.env === 'development') {
}
less.watchTimer = setInterval(function () {
if (less.watchMode) {
- loadStyleSheets(function (root, sheet, env) {
+ loadStyleSheets(function (e, root, _, sheet, env) {
if (root) {
createCSS(root.toCSS(), sheet, env.lastModified);
}
@@ -2708,7 +3176,7 @@ less.refresh = function (reload) {
var startTime, endTime;
startTime = endTime = new(Date);
- loadStyleSheets(function (root, sheet, env) {
+ loadStyleSheets(function (e, root, _, sheet, env) {
if (env.local) {
log("loading " + sheet.href + " from cache.");
} else {
@@ -2733,12 +3201,12 @@ function loadStyles() {
new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) {
var css = tree.toCSS();
var style = styles[i];
- try {
+ style.type = 'text/css';
+ if (style.styleSheet) {
+ style.styleSheet.cssText = css;
+ } else {
style.innerHTML = css;
- } catch (_) {
- style.styleSheets.cssText = css;
}
- style.type = 'text/css';
});
}
}
@@ -2765,6 +3233,7 @@ function loadStyleSheet(sheet, callback, reload, remaining) {
href = url.slice(0, url.lastIndexOf('/') + 1) + href;
}
}
+ var filename = href.match(/([^\/]+)$/)[1];
xhr(sheet.href, sheet.type, function (data, lastModified) {
if (!reload && styles && lastModified &&
@@ -2772,18 +3241,19 @@ function loadStyleSheet(sheet, callback, reload, remaining) {
new(Date)(styles.timestamp).valueOf())) {
// Use local copy
createCSS(styles.css, sheet);
- callback(null, sheet, { local: true, remaining: remaining });
+ callback(null, null, data, sheet, { local: true, remaining: remaining });
} else {
// Use remote copy (re-parse)
try {
new(less.Parser)({
optimization: less.optimization,
paths: [href.replace(/[\w\.-]+$/, '')],
- mime: sheet.type
+ mime: sheet.type,
+ filename: filename
}).parse(data, function (e, root) {
if (e) { return error(e, href) }
try {
- callback(root, sheet, { local: false, lastModified: lastModified, remaining: remaining });
+ callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining });
removeNode(document.getElementById('less-error-message:' + extractId(href)));
} catch (e) {
error(e, href);
Something went wrong with that request. Please try again.