carto/lib/less/tree/ruleset.js

157 lines
5.2 KiB
JavaScript
Raw Normal View History

if (typeof(require) !== 'undefined') { var tree = require('less/tree') }
2010-02-24 02:39:05 +08:00
tree.Ruleset = function Ruleset(selectors, rules) {
2010-02-24 02:39:05 +08:00
this.selectors = selectors;
this.rules = rules;
this._lookups = {};
2010-02-24 02:39:05 +08:00
};
tree.Ruleset.prototype = {
2010-03-08 07:50:58 +08:00
eval: function () { return this },
evalRules: function (context) {
var rules = [];
this.rules.forEach(function (rule) {
if (rule.evalRules) {
rules.push(rule.evalRules(context));
} else if (rule instanceof tree.mixin.Call) {
Array.prototype.push.apply(rules, rule.eval(context));
} else {
rules.push(rule.eval(context));
}
});
2010-04-23 01:47:01 +08:00
this.rules = rules;
return this;
},
2010-02-24 02:39:05 +08:00
variables: function () {
if (this._variables) { return this._variables }
else {
return this._variables = this.rules.filter(function (r) {
if (r instanceof tree.Rule && r.variable === true) { return r }
});
}
2010-02-24 02:39:05 +08:00
},
2010-03-08 12:11:20 +08:00
rulesets: function () {
if (this._rulesets) { return this._rulesets }
else {
return this._rulesets = this.rules.filter(function (r) {
if (r instanceof tree.Ruleset || r instanceof tree.mixin.Definition) { return r }
});
}
},
find: function (selector, self) {
self = self || this;
var rules = [], rule, match,
key = selector.toCSS();
if (key in this._lookups) { return this._lookups[key] }
2010-03-08 12:11:20 +08:00
this.rulesets().forEach(function (rule) {
if (rule !== self) {
for (var j = 0; j < rule.selectors.length; j++) {
if (match = selector.match(rule.selectors[j])) {
if (selector.elements.length > 1) {
Array.prototype.push.apply(rules, rule.find(
new(tree.Selector)(selector.elements.slice(1)), self));
} else {
rules.push(rule);
}
break;
}
}
}
2010-03-08 12:11:20 +08:00
});
return this._lookups[key] = rules;
},
2010-03-02 08:47:32 +08:00
//
// Entry point for code generation
//
2010-03-06 00:42:52 +08:00
// `context` holds an array of arrays.
//
toCSS: function (context, env) {
2010-03-02 08:47:32 +08:00
var css = [], // The CSS output
rules = [], // node.Rule instances
rulesets = [], // node.Ruleset instances
paths = [], // Current selectors
2010-03-06 00:42:52 +08:00
selector, // The fully rendered selector
rule;
2010-02-24 02:39:05 +08:00
if (! this.root) {
if (context.length === 0) {
paths = this.selectors.map(function (s) { return [s] });
} else {
for (var s = 0; s < this.selectors.length; s++) {
for (var c = 0; c < context.length; c++) {
paths.push(context[c].concat([this.selectors[s]]));
}
}
}
} else {
context = [], env = { frames: [] }
for (var i = 0; i < this.rules.length; i++) {
if (this.rules[i] instanceof tree.Import) {
Array.prototype.splice
.apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));
}
}
}
2010-03-06 00:42:52 +08:00
// push the current ruleset to the frames stack
2010-02-24 02:39:05 +08:00
env.frames.unshift(this);
2010-03-06 00:42:52 +08:00
// Evaluate mixins
for (var i = 0; i < this.rules.length; i++) {
if (this.rules[i] instanceof tree.mixin.Call) {
Array.prototype.splice
.apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));
}
}
2010-03-06 00:42:52 +08:00
// Evaluate rules and rulesets
2010-02-24 02:39:05 +08:00
for (var i = 0; i < this.rules.length; i++) {
2010-03-06 00:42:52 +08:00
rule = this.rules[i];
if (rule.rules) {
2010-03-06 00:42:52 +08:00
rulesets.push(rule.toCSS(paths, env));
2010-03-07 06:53:55 +08:00
} else if (rule instanceof tree.Comment) {
if (this.root) {
rulesets.push(rule.toCSS());
} else {
rules.push(rule.toCSS());
}
2010-02-24 02:39:05 +08:00
} else {
2010-03-06 00:42:52 +08:00
if (rule.toCSS && !rule.variable) {
rules.push(rule.toCSS(env));
} else if (rule.value && !rule.variable) {
rules.push(rule.value.toString());
2010-02-24 02:39:05 +08:00
}
}
}
rulesets = rulesets.join('');
2010-03-02 08:47:32 +08:00
// If this is the root node, we don't render
// a selector, or {}.
// Otherwise, only output if this ruleset has rules.
if (this.root) {
css.push(rules.join('\n'));
} else {
if (rules.length > 0) {
selector = paths.map(function (p) {
return p.map(function (s) {
return s.toCSS();
}).join('').trim();
}).join(paths.length > 3 ? ',\n' : ', ');
css.push(selector, " {\n " + rules.join('\n ') + "\n}\n");
2010-02-24 02:39:05 +08:00
}
}
css.push(rulesets);
2010-02-24 02:39:05 +08:00
2010-03-02 08:47:32 +08:00
// Pop the stack
env.frames.shift();
paths.forEach(function (p) { p.pop() });
2010-02-24 02:39:05 +08:00
return css.join('');
}
};