Added support and tests for !merge() syntax #700

This commit is contained in:
Daniel Katz
2013-02-06 22:39:13 +02:00
committed by Luke Page
parent de27a6fd88
commit 5dde7b3381
6 changed files with 146 additions and 7 deletions

View File

@@ -425,7 +425,7 @@ less.Parser = function Parser(env) {
}
value = new(tree.Value)([value]);
}
return new(tree.Rule)('@' + k, value, false, 0);
return new(tree.Rule)('@' + k, value, false, null, 0);
});
evalEnv.frames = [new(tree.Ruleset)(null, variables)];
}
@@ -1230,7 +1230,7 @@ less.Parser = function Parser(env) {
}
},
rule: function (tryAnonymous) {
var name, value, c = input.charAt(i), important;
var name, value, c = input.charAt(i), important, merge, match;
save();
if (c === '.' || c === '#' || c === '&') { return }
@@ -1242,10 +1242,12 @@ less.Parser = function Parser(env) {
($(this.value) || $(this.anonymousValue)) :
($(this.anonymousValue) || $(this.value));
important = $(this.important);
merge = $(this.merge);
if (value && $(this.end)) {
return new(tree.Rule)(name, value, important, memo, env.currentFileInfo);
return new (tree.Rule)(name, value, important, merge, memo, env.currentFileInfo);
} else {
furthest = i;
restore();
@@ -1338,7 +1340,7 @@ less.Parser = function Parser(env) {
e = $(this.value);
if ($(')')) {
if (p && e) {
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, i, env.currentFileInfo, true)));
nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, null, i, env.currentFileInfo, true)));
} else if (e) {
nodes.push(new(tree.Paren)(e));
} else {
@@ -1495,6 +1497,20 @@ less.Parser = function Parser(env) {
return $(/^! *important/);
}
},
merge: function () {
var separator;
if (input.charAt(i) === '!') {
if ($(/^! *merge\(/)) {
if (input.charAt(i) === ")") {
separator = " ";
} else {
separator = $(/[^)]/);
}
expect(")");
}
}
return separator;
},
sub: function () {
var a, e;

View File

@@ -1,9 +1,10 @@
(function (tree) {
tree.Rule = function (name, value, important, index, currentFileInfo, inline) {
tree.Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
this.name = name;
this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
this.important = important ? ' ' + important.trim() : '';
this.merge = merge;
this.index = index;
this.currentFileInfo = currentFileInfo;
this.inline = inline || false;
@@ -43,6 +44,7 @@ tree.Rule.prototype = {
return new(tree.Rule)(this.name,
this.value.eval(env),
this.important,
this.merge,
this.index, this.currentFileInfo, this.inline);
}
finally {
@@ -55,6 +57,7 @@ tree.Rule.prototype = {
return new(tree.Rule)(this.name,
this.value,
"!important",
this.merge,
this.index, this.currentFileInfo, this.inline);
}
};

View File

@@ -178,6 +178,7 @@ tree.Ruleset.prototype = {
debugInfo, // Line number debugging
rule;
this.mergeRules();
// Compile rules and rulesets
for (var i = 0; i < this.rules.length; i++) {
rule = this.rules[i];
@@ -454,6 +455,41 @@ tree.Ruleset.prototype = {
sel.push(new(tree.Selector)(elements));
}
}
},
mergeRules: function () {
var groups = {},
parts,
rule,
key;
for (var i = 0; i < this.rules.length; i++) {
rule = this.rules[i];
if ((rule instanceof tree.Rule) && rule.merge) {
key = [rule.name,
rule.important ? "!" : "",
rule.merge].join(",");
if (!groups[key]) {
parts = groups[key] = [];
} else {
this.rules.splice(i--, 1);
}
parts.push(rule);
}
}
Object.keys(groups).map(function (k) {
parts = groups[k];
if (parts.length > 1) {
parts[0].value = new (tree.Value)(parts.map(function (p) {
return p.value;
}), rule.merge);
}
});
}
};
})(require('../tree'));

View File

@@ -1,7 +1,8 @@
(function (tree) {
tree.Value = function (value) {
tree.Value = function (value, separator) {
this.value = value;
this.separator = separator ? separator : ",";
};
tree.Value.prototype = {
type: "Value",
@@ -20,7 +21,7 @@ tree.Value.prototype = {
toCSS: function (env) {
return this.value.map(function (e) {
return e.toCSS(env);
}).join(env.compress ? ',' : ', ');
}).join(this.separator + ((env.compress || this.separator === " ") ? "" : " "));
}
};

26
test/css/merge.css Normal file
View File

@@ -0,0 +1,26 @@
.test1 {
transform: rotate(90deg) skew(30deg) scale(2, 4);
}
.test2 {
transform: rotate(90deg) skew(30deg);
transform: scaleX(45deg);
}
.test3 {
background: url(img1.png), url(img2.png);
}
.test4 {
transform: rotate(90deg) skew(30deg);
transform: scaleX(45deg);
}
.test5 {
transform: scaleX(45deg);
background: url(img1.png);
}
.test6 {
transform: rotate(90deg) skew(30deg);
transform: scale(2, 4) !important;
}
.test7 {
transform: rotate(90deg) skew(30deg);
transform: scale(2, 4) !important;
}

57
test/less/merge.less Normal file
View File

@@ -0,0 +1,57 @@
.first-transform() {
transform: rotate(90deg) skew(30deg) !merge();
}
.second-transform() {
transform: scale(2,4) !merge();
}
.third-transform() {
transform: scaleX(45deg);
}
.fourth-transform() {
transform: scaleX(45deg) !merge(,);
}
.fifth-transform() {
transform: scale(2,4) !important !merge();
}
.first-background() {
background: url(img1.png) !merge(,);
}
.second-background() {
background: url(img2.png) !merge(,);
}
.test1 {
// Can merge values with space separator
.first-transform();
.second-transform();
}
.test2 {
// Wont merge values without !merge directive, for backwards compatibility with css
.first-transform();
.third-transform();
}
.test3 {
// Can merge values with explicit separator
.first-background();
.second-background();
}
.test4 {
// Wont merge values from two sources with different seperators
.first-transform();
.fourth-transform();
}
.test5 {
// Wont merge values from two sources with the same seperators but different properties
.fourth-transform();
.first-background();
}
.test6 {
// Wont merge values from sources that merked as !important, for backwards compatibility with css
.first-transform();
.fifth-transform();
}
.test7 {
// Wont merge values from mixins that merked as !important, for backwards compatibility with css
.first-transform();
.second-transform() !important;
}