Skip to content

Commit 5f9ee98

Browse files
committed
Added option (close #17)
1 parent d61fdfa commit 5f9ee98

13 files changed

Lines changed: 296 additions & 10 deletions

.csscomb.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"stick-brace": "\n",
1818
"strip-spaces": true,
1919
"unitless-zero": true,
20+
"vendor-prefix-align": true,
2021
"sort-order": [
2122
[
2223
"font",

lib/csscomb.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ var Comb = function() {
2626
'rule-indent',
2727
'block-indent',
2828
'unitless-zero',
29-
'sort-order'
29+
'sort-order',
30+
'vendor-prefix-align'
3031
];
3132
this._exclude = null;
3233
};

lib/options/vendor-prefix-align.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
module.exports = {
2+
3+
/**
4+
* Internal
5+
* Containt vendor-prefixes list
6+
*/
7+
_prefixesList: [
8+
'webkit',
9+
'moz',
10+
'ms',
11+
'o'
12+
],
13+
14+
/**
15+
* Internal
16+
*
17+
* Create object which contains info about vendor prefix used in propertyName
18+
* @param {String} propertyName property name
19+
* @returns {Object|undefined}
20+
*/
21+
_getPrefixInfo: function(propertyName) {
22+
if (!propertyName) return;
23+
24+
var result = { baseName: propertyName, prefixLength: 0 };
25+
26+
this._prefixesList.some(function(prefix) {
27+
prefix = '-' + prefix + '-';
28+
if (propertyName.indexOf(prefix) !== 0) return;
29+
result = {
30+
baseName: propertyName.substr(prefix.length),
31+
prefixLength: prefix.length
32+
};
33+
return true;
34+
});
35+
36+
return result;
37+
},
38+
39+
_walk: function(node, selector, payload) {
40+
node.forEach(function(item, i) {
41+
var info = this._getPrefixInfo(selector(item));
42+
if (!info) return;
43+
payload(info, i);
44+
}, this);
45+
},
46+
47+
_declName: function(item) {
48+
return item[0] === 'declaration' && item[1][1][1];
49+
},
50+
51+
_valName: function(item) {
52+
return item[0] === 'declaration' && item[2] && item[2][2] &&
53+
item[2][2][0] === 'funktion' && item[2][2][1][0] === 'ident' &&
54+
item[2][2][1][1];
55+
},
56+
57+
_updateDict: function(info, dict, whitespaceNode) {
58+
if (info.prefixLength === 0) return;
59+
60+
var indent = dict[info.baseName] || { prefixLength: 0, baseLength: 0 };
61+
62+
dict[info.baseName] = indent.prefixLength > info.prefixLength ?
63+
indent :
64+
{
65+
prefixLength: info.prefixLength,
66+
baseLength: whitespaceNode.substr(whitespaceNode.lastIndexOf('\n') + 1).length
67+
};
68+
},
69+
70+
_updateIndent: function(info, dict, whitespaceNode) {
71+
if (!dict[info.baseName])
72+
return whitespaceNode;
73+
74+
var firstPart = whitespaceNode.substr(0, whitespaceNode.lastIndexOf('\n') + 1 );
75+
var extraIndent = new Array(
76+
dict[info.baseName].prefixLength -
77+
info.prefixLength +
78+
dict[info.baseName].baseLength + 1).join(' ');
79+
80+
return firstPart.concat(extraIndent);
81+
},
82+
83+
/**
84+
* Sets handler value.
85+
*
86+
* @param {Array} value Option value
87+
* @returns {Object|undefined}
88+
*/
89+
setValue: function(value) {
90+
return value ? this : undefined;
91+
},
92+
93+
/**
94+
* Processes tree node.
95+
* @param {String} nodeType
96+
* @param {node} node
97+
*/
98+
process: function(nodeType, node) {
99+
if (nodeType !== 'block') return;
100+
101+
var dict = {};
102+
var _this = this;
103+
104+
// Gathering Info
105+
this._walk(node, this._declName, function(info, i) {
106+
_this._updateDict(info, dict, node[i - 1][1]);
107+
});
108+
this._walk(node, this._valName, function(info, i) {
109+
_this._updateDict(info, dict, node[i][2][1][1]);
110+
});
111+
112+
// Update nodes
113+
this._walk(node, this._declName, function(info, i) {
114+
node[i - 1][1] = _this._updateIndent(info, dict, node[i - 1][1]);
115+
});
116+
this._walk(node, this._valName, function(info, i) {
117+
node[i][2][1][1] = _this._updateIndent(info, dict, node[i][2][1][1]);
118+
});
119+
}
120+
121+
};

test/integral.expect.css

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,28 @@
55
{
66
background: rgba(0,0,0,.4);
77
background: -webkit-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
8-
background: -moz-linear-gradient(top, rgba(0,0,0,.2) 0, rgba(0,0,0,.4) 100%);
9-
background: -o-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
10-
background: linear-gradient(to bottom, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
8+
background: -moz-linear-gradient(top, rgba(0,0,0,.2) 0, rgba(0,0,0,.4) 100%);
9+
background: -o-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
10+
background: linear-gradient(to bottom, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
1111
-moz-box-shadow: 0 1px 0 rgba(0,0,0,.07);
12-
box-shadow: 0 1px 0 rgba(0,0,0,.07);
12+
box-shadow: 0 1px 0 rgba(0,0,0,.07);
1313
}
1414

1515
/* :after — фон */
1616
.radio-button_theme_normal .radio-button__radio:after
1717
{
1818
background: #fff;
1919
background: -webkit-linear-gradient(top, #fff 0,#eee 100%);
20-
background: -moz-linear-gradient(top, #fff 0, #eee 100%);
21-
background: -o-linear-gradient(top, #fff 0,#eee 100%);
22-
background: linear-gradient(to bottom, #fff 0,#eee 100%);
20+
background: -moz-linear-gradient(top, #fff 0, #eee 100%);
21+
background: -o-linear-gradient(top, #fff 0,#eee 100%);
22+
background: linear-gradient(to bottom, #fff 0,#eee 100%);
2323
}
2424

2525
/* _focused_yes */
2626
.radio-button_theme_normal .radio-button__radio_focused_yes:before
2727
{
2828
-moz-box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
29-
box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
29+
box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
3030
}
3131
}
3232

@@ -85,7 +85,7 @@ div p em
8585
.input__control
8686
{
8787
-moz-box-sizing: border-box;
88-
box-sizing: border-box;
88+
box-sizing: border-box;
8989
padding: .4em 0;
9090

9191
border: 0;

test/vendor-prefix-align.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
var Comb = require('../lib/csscomb');
2+
var fs = require('fs');
3+
var assert = require('assert');
4+
5+
describe('options/vendor-prefix-align', function() {
6+
var comb;
7+
8+
beforeEach(function() {
9+
var config = {
10+
'vendor-prefix-align': true
11+
};
12+
13+
comb = new Comb();
14+
comb.configure(config);
15+
});
16+
17+
it('Should correctly align prefixes in properties', function() {
18+
var input = fs.readFileSync('./test/vendor-prefix-align/property-align.css', 'utf8');
19+
var expected = fs.readFileSync('./test/vendor-prefix-align/property-align.expected.css', 'utf8');
20+
21+
assert.equal(comb.processString(input), expected);
22+
});
23+
24+
it('Should correctly align prefixes in values', function() {
25+
var input = fs.readFileSync('./test/vendor-prefix-align/value-align.css', 'utf8');
26+
var expected = fs.readFileSync('./test/vendor-prefix-align/value-align.expected.css', 'utf8');
27+
28+
assert.equal(comb.processString(input), expected);
29+
});
30+
31+
it('Should not touch already align prefixes', function() {
32+
var input = fs.readFileSync('./test/vendor-prefix-align/already-aligned.css', 'utf8');
33+
var expected = fs.readFileSync('./test/vendor-prefix-align/already-aligned.expected.css', 'utf8');
34+
35+
assert.equal(comb.processString(input), expected);
36+
});
37+
38+
it('Should always correctly align prefixes', function() {
39+
var input = fs.readFileSync('./test/vendor-prefix-align/complex.css', 'utf8');
40+
var expected = fs.readFileSync('./test/vendor-prefix-align/complex.expected.css', 'utf8');
41+
42+
assert.equal(comb.processString(input), expected);
43+
});
44+
45+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.radio-button_theme_normal .radio-button__radio:before
2+
{
3+
background: rgba(0,0,0,.4);
4+
background: -webkit-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
5+
background: -moz-linear-gradient(top, rgba(0,0,0,.2) 0, rgba(0,0,0,.4) 100%);
6+
background: -o-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
7+
background: linear-gradient(to bottom, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
8+
9+
-moz-box-shadow: 0 1px 0 rgba(0,0,0,.07);
10+
box-shadow: 0 1px 0 rgba(0,0,0,.07);
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.radio-button_theme_normal .radio-button__radio:before
2+
{
3+
background: rgba(0,0,0,.4);
4+
background: -webkit-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
5+
background: -moz-linear-gradient(top, rgba(0,0,0,.2) 0, rgba(0,0,0,.4) 100%);
6+
background: -o-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
7+
background: linear-gradient(to bottom, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
8+
9+
-moz-box-shadow: 0 1px 0 rgba(0,0,0,.07);
10+
box-shadow: 0 1px 0 rgba(0,0,0,.07);
11+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
@media all and (min-width:0)
2+
{
3+
.radio-button_theme_normal .radio-button__radio:before
4+
{
5+
background: rgba(0,0,0,.4);
6+
background: -webkit-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
7+
background: -moz-linear-gradient(top, rgba(0,0,0,.2) 0, rgba(0,0,0,.4) 100%);
8+
background: -o-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
9+
background: linear-gradient(to bottom, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
10+
-moz-box-shadow: 0 1px 0 rgba(0,0,0,.07);
11+
box-shadow: 0 1px 0 rgba(0,0,0,.07);
12+
}
13+
14+
/* :after — фон */
15+
.radio-button_theme_normal .radio-button__radio:after
16+
{
17+
background: #fff;
18+
background: -webkit-linear-gradient(top, #fff 0,#eee 100%);
19+
background: -moz-linear-gradient(top, #fff 0, #eee 100%);
20+
background: -o-linear-gradient(top, #fff 0,#eee 100%);
21+
background: linear-gradient(to bottom, #fff 0,#eee 100%);
22+
}
23+
24+
/* _focused_yes */
25+
.radio-button_theme_normal .radio-button__radio_focused_yes:before
26+
{
27+
-moz-box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
28+
box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
@media all and (min-width:0)
2+
{
3+
.radio-button_theme_normal .radio-button__radio:before
4+
{
5+
background: rgba(0,0,0,.4);
6+
background: -webkit-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
7+
background: -moz-linear-gradient(top, rgba(0,0,0,.2) 0, rgba(0,0,0,.4) 100%);
8+
background: -o-linear-gradient(top, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
9+
background: linear-gradient(to bottom, rgba(0,0,0,.2) 0,rgba(0,0,0,.4) 100%);
10+
-moz-box-shadow: 0 1px 0 rgba(0,0,0,.07);
11+
box-shadow: 0 1px 0 rgba(0,0,0,.07);
12+
}
13+
14+
/* :after — фон */
15+
.radio-button_theme_normal .radio-button__radio:after
16+
{
17+
background: #fff;
18+
background: -webkit-linear-gradient(top, #fff 0,#eee 100%);
19+
background: -moz-linear-gradient(top, #fff 0, #eee 100%);
20+
background: -o-linear-gradient(top, #fff 0,#eee 100%);
21+
background: linear-gradient(to bottom, #fff 0,#eee 100%);
22+
}
23+
24+
/* _focused_yes */
25+
.radio-button_theme_normal .radio-button__radio_focused_yes:before
26+
{
27+
-moz-box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
28+
box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
29+
}
30+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
a
2+
{
3+
color: #fff;
4+
5+
-webkit-border-radius: 3px;
6+
-moz-border-radius: 3px;
7+
border-radius: 3px;
8+
}

0 commit comments

Comments
 (0)