Rudimentary support for extend in selectors

This commit is contained in:
Luke Page
2012-11-27 12:36:17 +00:00
parent 4633f7cc4c
commit 97d0b0205b
6 changed files with 118 additions and 13 deletions

View File

@@ -525,7 +525,7 @@ less.Parser = function Parser(env) {
primary: function () {
var node, root = [];
while ((node = $(this.extend) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
$(this.mixin.call) || $(this.comment) || $(this.directive))
|| $(/^[\s\n]+/) || $(/^;+/)) {
node && root.push(node);
@@ -806,24 +806,35 @@ less.Parser = function Parser(env) {
restore();
},
//
// extend
// extend syntax - used to extend selectors
//
extend: function() {
extend: function(isRule) {
var elements = [], e, args, index = i;
if (!$(/^&:extend\(/)) { return; }
if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; }
while (e = $(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)) {
elements.push(new(tree.Element)(null, e, i));
}
expect(/^\);/);
expect(/^\)/);
if (isRule) {
expect(/^;/);
}
return new(tree.Extend)(elements, index);
},
//
// extendRule - used in a rule to extend all the parent selectors
//
extendRule: function() {
return this.extend(true);
},
//
// Mixins
//
@@ -1096,15 +1107,20 @@ less.Parser = function Parser(env) {
// Selectors are made out of one or more Elements, see above.
//
selector: function () {
var sel, e, elements = [], c, match;
var sel, e, elements = [], c, match, extend;
while (e = $(this.element)) {
while ((extend = $(this.extend)) || (e = $(this.element))) {
if (!e) {
break;
}
c = input.charAt(i);
elements.push(e)
e = null;
if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') { break }
}
if (elements.length > 0) { return new(tree.Selector)(elements) }
if (elements.length > 0) { return new(tree.Selector)(elements, extend) }
if (extend) { error("Extend must be used to extend a selector"); }
},
attribute: function () {
var attr = '', key, val, op;

View File

@@ -5,8 +5,8 @@ tree.Extend = function Extend(elements, index) {
this.index = index;
};
tree.Extend.prototype.eval = function Extend_eval(env) {
var selfSelectors = findSelfSelectors(env.selectors),
tree.Extend.prototype.eval = function Extend_eval(env, selectors) {
var selfSelectors = findSelfSelectors(selectors || env.selectors),
targetValue = this.selector.elements[0].value;
env.frames.forEach(function(frame) {

View File

@@ -53,6 +53,14 @@ tree.Ruleset.prototype = {
ruleset.resetCache();
}
}
if (this.selectors) {
for (var i = 0; i < this.selectors.length; i++) {
if (this.selectors[i].extend) {
this.selectors[i].extend.eval(env, [[this.selectors[i]]].concat(env.selectors.slice(1)));
}
}
}
// Evaluate everything else
for (var i = 0, rule; i < ruleset.rules.length; i++) {

View File

@@ -1,7 +1,8 @@
(function (tree) {
tree.Selector = function (elements) {
tree.Selector = function (elements, extend) {
this.elements = elements;
this.extend = extend;
};
tree.Selector.prototype.match = function (other) {
var elements = this.elements,
@@ -27,7 +28,7 @@ tree.Selector.prototype.match = function (other) {
tree.Selector.prototype.eval = function (env) {
return new(tree.Selector)(this.elements.map(function (e) {
return e.eval(env);
}));
}), this.extend);
};
tree.Selector.prototype.toCSS = function (env) {
if (this._css) { return this._css }

View File

@@ -0,0 +1,33 @@
.error,
.badError {
border: 1px #f00;
background: #fdd;
}
.error.intrusion,
.badError.intrusion {
font-size: 1.3em;
font-weight: bold;
}
.intrusion .error,
.intrusion .badError {
display: none;
}
.badError {
border-width: 3px;
}
.foo .bar,
.foo .baz,
.ext1 .ext2 .bar,
.ext1 .ext2 .baz,
.ext3 .bar,
.ext3 .baz,
.ext4 .bar,
.ext4 .baz {
display: none;
}
div.ext5,
.ext6 > .ext5,
div.ext7,
.ext6 > .ext7 {
width: 100px;
}

View File

@@ -0,0 +1,47 @@
.error {
border: 1px #f00;
background: #fdd;
}
.error.intrusion {
font-size: 1.3em;
font-weight: bold;
}
.intrusion .error {
display: none;
}
.badError:extend(.error) {
border-width: 3px;
}
.foo .bar, .foo .baz {
display: none;
}
.ext1 .ext2
:extend(.foo) {
}
.ext3:extend(.foo),
.ext4:extend(.foo) {
}
div.ext5,
.ext6 > .ext5 {
width: 100px;
}
.should-not-exist-in-output,
.ext7:extend(.ext5) {
}
// same as
// .a .c:extend(.ext)
// .b .c:extend(.ext)
// .a .c .d
// .b .c .d
.a, .b {
.c:extend(.ext) {
.d {
}
}
}