From afd599dcb5aaeb9bab04efa0430c2d34f01692c9 Mon Sep 17 00:00:00 2001 From: James Foster Date: Fri, 20 May 2011 07:55:02 +0800 Subject: [PATCH] Implement parent selector --- lib/less/parser.js | 14 ++++++++++++- lib/less/tree/element.js | 5 ++++- lib/less/tree/ruleset.js | 44 +++++++++++++++++++++++++++++++++++----- test/css/selectors.css | 21 +++++++++++++++++++ test/less/selectors.less | 24 ++++++++++++++++++++++ 5 files changed, 101 insertions(+), 7 deletions(-) diff --git a/lib/less/parser.js b/lib/less/parser.js index 9cb2a30e..e828c23c 100644 --- a/lib/less/parser.js +++ b/lib/less/parser.js @@ -790,6 +790,10 @@ less.Parser = function Parser(env) { e = $(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/) || $('*') || $(this.attribute) || $(/^\([^)@]+\)/); if (e) { return new(tree.Element)(c, e) } + + if (c.value && c.value[0] === '&') { + return new(tree.Element)(c, null); + } }, // @@ -804,10 +808,18 @@ less.Parser = function Parser(env) { combinator: function () { var match, c = input.charAt(i); - if (c === '>' || c === '&' || c === '+' || c === '~') { + if (c === '>' || c === '+' || c === '~') { i++; while (input.charAt(i) === ' ') { i++ } return new(tree.Combinator)(c); + } else if (c === '&') { + match = '&'; + i++; + if(input.charAt(i) === ' ') { + match = '& '; + } + while (input.charAt(i) === ' ') { i++ } + return new(tree.Combinator)(match); } else if (c === ':' && input.charAt(i + 1) === ':') { i += 2; while (input.charAt(i) === ' ') { i++ } diff --git a/lib/less/tree/element.js b/lib/less/tree/element.js index acf5e205..27cf8228 100644 --- a/lib/less/tree/element.js +++ b/lib/less/tree/element.js @@ -3,7 +3,7 @@ tree.Element = function (combinator, value) { this.combinator = combinator instanceof tree.Combinator ? combinator : new(tree.Combinator)(combinator); - this.value = value.trim(); + this.value = value ? value.trim() : ""; }; tree.Element.prototype.toCSS = function (env) { return this.combinator.toCSS(env || {}) + this.value; @@ -12,6 +12,8 @@ tree.Element.prototype.toCSS = function (env) { tree.Combinator = function (value) { if (value === ' ') { this.value = ' '; + } else if (value === '& ') { + this.value = '& '; } else { this.value = value ? value.trim() : ""; } @@ -21,6 +23,7 @@ tree.Combinator.prototype.toCSS = function (env) { '' : '', ' ' : ' ', '&' : '', + '& ' : ' ', ':' : ' :', '::': '::', '+' : env.compress ? '+' : ' + ', diff --git a/lib/less/tree/ruleset.js b/lib/less/tree/ruleset.js index 4fbf1db8..246200fa 100644 --- a/lib/less/tree/ruleset.js +++ b/lib/less/tree/ruleset.js @@ -120,11 +120,7 @@ tree.Ruleset.prototype = { 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]])); - } - } + this.joinSelectors( paths, context, this.selectors ); } } @@ -174,6 +170,44 @@ tree.Ruleset.prototype = { css.push(rulesets); return css.join('') + (env.compress ? '\n' : ''); + }, + + joinSelectors: function( paths, context, selectors ) { + for (var s = 0; s < selectors.length; s++) { + this.joinSelector(paths, context, selectors[s]); + } + }, + + joinSelector: function( paths, context, selector ) { + var before = [], after = [], beforeElements = [], afterElements = [], hasParentSelector = false, el; + + for (var i = 0; i < selector.elements.length; i++) { + el = selector.elements[i]; + if (el.combinator.value[0] === '&') { + hasParentSelector = true; + } + if(!hasParentSelector) { + beforeElements.push(el); + } else { + afterElements.push(el); + } + } + + if(!hasParentSelector) { + afterElements = beforeElements; + beforeElements = []; + } + + if(beforeElements.length > 0) { + before.push(new (tree.Selector)(beforeElements)); + } + if(afterElements.length > 0) { + after.push(new (tree.Selector)(afterElements)); + } + + for (var c = 0; c < context.length; c++) { + paths.push(before.concat(context[c]).concat(after)); + } } }; })(require('less/tree')); diff --git a/test/css/selectors.css b/test/css/selectors.css index 85916c35..a384f938 100644 --- a/test/css/selectors.css +++ b/test/css/selectors.css @@ -30,3 +30,24 @@ td { td, input { line-height: 1em; } +a { + color: red; +} +a:hover { + color: blue; +} +div a { + color: green; +} +p a span { + color: yellow; +} +.foo .bar .qux, .foo .baz .qux { + display: block; +} +.qux .foo .bar, .qux .foo .baz { + display: inline; +} +.qux .foo .bar .biz, .qux .foo .baz .biz { + display: none; +} diff --git a/test/less/selectors.less b/test/less/selectors.less index 5691bb22..5bc2bb1f 100644 --- a/test/less/selectors.less +++ b/test/less/selectors.less @@ -22,3 +22,27 @@ td { td, input { line-height: 1em; } + +a { + color: red; + + &:hover { color: blue; } + + div & { color: green; } + + p & span { color: yellow; } +} + +.foo { + .bar, .baz { + & .qux { + display: block; + } + .qux & { + display: inline; + } + .qux & .biz { + display: none; + } + } +} \ No newline at end of file