carto/lib/less/tree/mixin.js
2010-07-06 16:48:05 +02:00

100 lines
3.6 KiB
JavaScript

(function (tree) {
tree.mixin = {};
tree.mixin.Call = function (elements, args, index) {
this.selector = new(tree.Selector)(elements);
this.arguments = args;
this.index = index;
};
tree.mixin.Call.prototype = {
eval: function (env) {
var mixins, rules = [], match = false;
for (var i = 0; i < env.frames.length; i++) {
if ((mixins = env.frames[i].find(this.selector)).length > 0) {
for (var m = 0; m < mixins.length; m++) {
if (mixins[m].match(this.arguments, env)) {
try {
Array.prototype.push.apply(
rules, mixins[m].eval(this.arguments, env).rules);
match = true;
} catch (e) {
throw { message: e.message, index: e.index, call: this.index };
}
}
}
if (match) {
return rules;
} else {
throw { message: 'No matching definition was found for `' +
this.selector.toCSS().trim() + '(' +
this.arguments.map(function (a) {
return a.toCSS();
}).join(', ') + ")`",
index: this.index };
}
}
}
throw { message: this.selector.toCSS().trim() + " is undefined",
index: this.index };
}
};
tree.mixin.Definition = function (name, params, rules) {
this.name = name;
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
this.params = params;
this.arity = params.length;
this.rules = rules;
this._lookups = {};
this.required = params.reduce(function (count, p) {
if (p.name && !p.value) { return count + 1 }
else { return count }
}, 0);
this.parent = tree.Ruleset.prototype;
this.frames = [];
};
tree.mixin.Definition.prototype = {
toCSS: function () { return "" },
variable: function (name) { return this.parent.variable.call(this, name) },
find: function () { return this.parent.find.apply(this, arguments) },
rulesets: function () { return this.parent.rulesets.apply(this) },
eval: function (args, env) {
var frame = new(tree.Ruleset)(null, []), context;
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)));
} else {
throw { message: "wrong number of arguments for " + this.name +
' (' + args.length + ' for ' + this.arity + ')' };
}
}
}
return new(tree.Ruleset)(null, this.rules).evalRules({
frames: [this, frame].concat(this.frames, env.frames)
});
},
match: function (args, env) {
var argsLength = (args && args.length) || 0;
if (argsLength < this.required) {
return false;
}
for (var i = 0; i < Math.min(argsLength, this.arity); i++) {
if (!this.params[i].name) {
if (args[i].wildcard) { continue }
else if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
return false;
}
}
}
return true;
}
};
})(require('less/tree'));