mirror of
https://github.com/less/less.js.git
synced 2026-05-01 03:00:22 -04:00
Rudimentary support for extend in selectors
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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 }
|
||||
|
||||
33
test/css/extend-selector.css
Normal file
33
test/css/extend-selector.css
Normal 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;
|
||||
}
|
||||
47
test/less/extend-selector.less
Normal file
47
test/less/extend-selector.less
Normal 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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user