properly support @media and @import features

This commit is contained in:
Alexis Sellier
2011-12-17 17:41:54 +01:00
parent 96689e4f37
commit ff3d7c61ff
10 changed files with 99 additions and 21 deletions

View File

@@ -82,7 +82,7 @@ var less = {
'selector', 'quoted', 'expression', 'rule',
'call', 'url', 'alpha', 'import',
'mixin', 'comment', 'anonymous', 'value',
'javascript', 'assignment', 'condition'
'javascript', 'assignment', 'condition', 'paren'
].forEach(function (n) {
require('./tree/' + n);
});

View File

@@ -824,13 +824,15 @@ 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) || $(/^\([^)@]+\)/);
e || ($('(') && (e = $(this.entities.variable)) && $(')'));
if (! e) {
$('(') && (v = $(this.entities.variable)) && $(')') && (e = new(tree.Paren)(v));
}
if (e) { return new(tree.Element)(c, e, i) }
@@ -984,11 +986,60 @@ less.Parser = function Parser(env) {
// stored in `import`, which we pass to the Import constructor.
//
"import": function () {
var path;
var path, features;
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);
}
}
},
mediaFeature: function () {
var 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 f, features = [];
while (f = $(this.mediaFeature)) {
features.push(f);
if (! $(',')) { break }
}
return features.length > 0 ? features : null;
},
media: function () {
var features;
if ($(/^@media/)) {
features = $(this.mediaFeatures);
if (rules = $(this.block)) {
return new(tree.Directive)('@media', rules, features);
}
}
},
@@ -998,13 +1049,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|@keyframes/) || $(/^@(?:-webkit-|-moz-|-o-|-ms-)[a-z0-9-]+/)) {
} 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);

View File

@@ -1,7 +1,9 @@
(function (tree) {
tree.Directive = function (name, value) {
tree.Directive = function (name, value, features) {
this.name = name;
this.features = features && new(tree.Value)(features);
if (Array.isArray(value)) {
this.ruleset = new(tree.Ruleset)([], value);
} else {
@@ -10,9 +12,11 @@ tree.Directive = function (name, value) {
};
tree.Directive.prototype = {
toCSS: function (ctx, env) {
var features = this.features ? ' ' + this.features.toCSS(env) : '';
if (this.ruleset) {
this.ruleset.root = true;
return this.name + (env.compress ? '{' : ' {\n ') +
return this.name + features + (env.compress ? '{' : ' {\n ') +
this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
(env.compress ? '}': '\n}\n');
} else {
@@ -20,6 +24,7 @@ tree.Directive.prototype = {
}
},
eval: function (env) {
this.features = this.features && this.features.eval(env);
env.frames.unshift(this);
this.ruleset = this.ruleset && this.ruleset.eval(env);
env.frames.shift();

View File

@@ -19,7 +19,7 @@ tree.Element.prototype.eval = function (env) {
this.index);
};
tree.Element.prototype.toCSS = function (env) {
return this.combinator.toCSS(env || {}) + (this.value.toCSS ? '(' + this.value.toCSS(env) + ')' : this.value);
return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
};
tree.Combinator = function (value) {

View File

@@ -11,10 +11,11 @@
// `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) {
var that = this;
this._path = path;
this.features = features && new(tree.Value)(features);
// The '.less' extension is optional
if (path instanceof tree.Quoted) {
@@ -46,9 +47,11 @@ 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 "";
}
@@ -57,6 +60,7 @@ tree.Import.prototype = {
var ruleset;
if (this.css) {
this.features = this.features && this.features.eval(env);
return this;
} else {
ruleset = new(tree.Ruleset)(null, this.root.rules.slice(0));

View File

@@ -1,10 +1,11 @@
(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;
@@ -15,12 +16,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) {