Skip to content

Commit 298750e

Browse files
committed
Implement parent selector
1 parent 05722ed commit 298750e

File tree

5 files changed

+101
-7
lines changed

5 files changed

+101
-7
lines changed

lib/less/parser.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,10 @@ less.Parser = function Parser(env) {
814814
e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/);
815815

816816
if (e) { return new(tree.Element)(c, e) }
817+
818+
if (c.value && c.value[0] === '&') {
819+
return new(tree.Element)(c, null);
820+
}
817821
},
818822

819823
//
@@ -828,10 +832,18 @@ less.Parser = function Parser(env) {
828832
combinator: function () {
829833
var match, c = input.charAt(i);
830834

831-
if (c === '>' || c === '&' || c === '+' || c === '~') {
835+
if (c === '>' || c === '+' || c === '~') {
832836
i++;
833837
while (input.charAt(i) === ' ') { i++ }
834838
return new(tree.Combinator)(c);
839+
} else if (c === '&') {
840+
match = '&';
841+
i++;
842+
if(input.charAt(i) === ' ') {
843+
match = '& ';
844+
}
845+
while (input.charAt(i) === ' ') { i++ }
846+
return new(tree.Combinator)(match);
835847
} else if (c === ':' && input.charAt(i + 1) === ':') {
836848
i += 2;
837849
while (input.charAt(i) === ' ') { i++ }

lib/less/tree/element.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
tree.Element = function (combinator, value) {
44
this.combinator = combinator instanceof tree.Combinator ?
55
combinator : new(tree.Combinator)(combinator);
6-
this.value = value.trim();
6+
this.value = value ? value.trim() : "";
77
};
88
tree.Element.prototype.toCSS = function (env) {
99
return this.combinator.toCSS(env || {}) + this.value;
@@ -12,6 +12,8 @@ tree.Element.prototype.toCSS = function (env) {
1212
tree.Combinator = function (value) {
1313
if (value === ' ') {
1414
this.value = ' ';
15+
} else if (value === '& ') {
16+
this.value = '& ';
1517
} else {
1618
this.value = value ? value.trim() : "";
1719
}
@@ -21,6 +23,7 @@ tree.Combinator.prototype.toCSS = function (env) {
2123
'' : '',
2224
' ' : ' ',
2325
'&' : '',
26+
'& ' : ' ',
2427
':' : ' :',
2528
'::': '::',
2629
'+' : env.compress ? '+' : ' + ',

lib/less/tree/ruleset.js

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,7 @@ tree.Ruleset.prototype = {
120120
if (context.length === 0) {
121121
paths = this.selectors.map(function (s) { return [s] });
122122
} else {
123-
for (var s = 0; s < this.selectors.length; s++) {
124-
for (var c = 0; c < context.length; c++) {
125-
paths.push(context[c].concat([this.selectors[s]]));
126-
}
127-
}
123+
this.joinSelectors( paths, context, this.selectors );
128124
}
129125
}
130126

@@ -174,6 +170,44 @@ tree.Ruleset.prototype = {
174170
css.push(rulesets);
175171

176172
return css.join('') + (env.compress ? '\n' : '');
173+
},
174+
175+
joinSelectors: function( paths, context, selectors ) {
176+
for (var s = 0; s < selectors.length; s++) {
177+
this.joinSelector(paths, context, selectors[s]);
178+
}
179+
},
180+
181+
joinSelector: function( paths, context, selector ) {
182+
var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el;
183+
184+
for (var i = 0; i < selector.elements.length; i++) {
185+
el = selector.elements[i];
186+
if (el.combinator.value[0] === '&') {
187+
hasParentSelector = true;
188+
}
189+
if(!hasParentSelector) {
190+
beforeElements.push(el);
191+
} else {
192+
afterElements.push(el);
193+
}
194+
}
195+
196+
if(!hasParentSelector) {
197+
afterElements = beforeElements;
198+
beforeElements = [];
199+
}
200+
201+
if(beforeElements.length > 0) {
202+
before.push(new (tree.Selector)(beforeElements));
203+
}
204+
if(afterElements.length > 0) {
205+
after.push(new (tree.Selector)(afterElements));
206+
}
207+
208+
for (var c = 0; c < context.length; c++) {
209+
paths.push(before.concat(context[c]).concat(after));
210+
}
177211
}
178212
};
179213
})(require('less/tree'));

test/css/selectors.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,24 @@ td {
3030
td, input {
3131
line-height: 1em;
3232
}
33+
a {
34+
color: red;
35+
}
36+
a:hover {
37+
color: blue;
38+
}
39+
div a {
40+
color: green;
41+
}
42+
p a span {
43+
color: yellow;
44+
}
45+
.foo .bar .qux, .foo .baz .qux {
46+
display: block;
47+
}
48+
.qux .foo .bar, .qux .foo .baz {
49+
display: inline;
50+
}
51+
.qux .foo .bar .biz, .qux .foo .baz .biz {
52+
display: none;
53+
}

test/less/selectors.less

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,27 @@ td {
2222
td, input {
2323
line-height: 1em;
2424
}
25+
26+
a {
27+
color: red;
28+
29+
&:hover { color: blue; }
30+
31+
div & { color: green; }
32+
33+
p & span { color: yellow; }
34+
}
35+
36+
.foo {
37+
.bar, .baz {
38+
& .qux {
39+
display: block;
40+
}
41+
.qux & {
42+
display: inline;
43+
}
44+
.qux & .biz {
45+
display: none;
46+
}
47+
}
48+
}

0 commit comments

Comments
 (0)