ruby-clean-css 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitmodules +3 -0
- data/EXAMPLE.md +25 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +19 -0
- data/README.md +106 -0
- data/lib/javascript/clean-css/.gitignore +4 -0
- data/lib/javascript/clean-css/.jshintignore +3 -0
- data/lib/javascript/clean-css/.jshintrc +14 -0
- data/lib/javascript/clean-css/.travis.yml +11 -0
- data/lib/javascript/clean-css/History.md +556 -0
- data/lib/javascript/clean-css/LICENSE +19 -0
- data/lib/javascript/clean-css/README.md +218 -0
- data/lib/javascript/clean-css/bin/cleancss +157 -0
- data/lib/javascript/clean-css/index.js +1 -0
- data/lib/javascript/clean-css/lib/clean.js +426 -0
- data/lib/javascript/clean-css/lib/colors/hsl-to-hex.js +64 -0
- data/lib/javascript/clean-css/lib/colors/long-to-short-hex.js +12 -0
- data/lib/javascript/clean-css/lib/colors/rgb-to-hex.js +14 -0
- data/lib/javascript/clean-css/lib/colors/shortener.js +174 -0
- data/lib/javascript/clean-css/lib/images/url-rebase.js +32 -0
- data/lib/javascript/clean-css/lib/images/url-rewriter.js +60 -0
- data/lib/javascript/clean-css/lib/imports/inliner.js +319 -0
- data/lib/javascript/clean-css/lib/properties/optimizer.js +276 -0
- data/lib/javascript/clean-css/lib/properties/override-compactor.js +116 -0
- data/lib/javascript/clean-css/lib/properties/processable.js +859 -0
- data/lib/javascript/clean-css/lib/properties/scanner.js +20 -0
- data/lib/javascript/clean-css/lib/properties/shorthand-compactor.js +244 -0
- data/lib/javascript/clean-css/lib/properties/token.js +184 -0
- data/lib/javascript/clean-css/lib/properties/validator.js +140 -0
- data/lib/javascript/clean-css/lib/selectors/empty-removal.js +30 -0
- data/lib/javascript/clean-css/lib/selectors/optimizer.js +341 -0
- data/lib/javascript/clean-css/lib/selectors/tokenizer.js +168 -0
- data/lib/javascript/clean-css/lib/text/comments.js +83 -0
- data/lib/javascript/clean-css/lib/text/escape-store.js +32 -0
- data/lib/javascript/clean-css/lib/text/expressions.js +73 -0
- data/lib/javascript/clean-css/lib/text/free.js +26 -0
- data/lib/javascript/clean-css/lib/text/name-quotes.js +37 -0
- data/lib/javascript/clean-css/lib/text/quote-scanner.js +91 -0
- data/lib/javascript/clean-css/lib/text/splitter.js +35 -0
- data/lib/javascript/clean-css/lib/text/urls.js +41 -0
- data/lib/javascript/clean-css/package.json +50 -0
- data/lib/javascript/clean-css/test/batch-test.js +56 -0
- data/lib/javascript/clean-css/test/bench.js +11 -0
- data/lib/javascript/clean-css/test/binary-test.js +323 -0
- data/lib/javascript/clean-css/test/data-bench/_partial.css +1 -0
- data/lib/javascript/clean-css/test/data-bench/complex.css +4 -0
- data/lib/javascript/clean-css/test/data/129-assets/assets/ui.css +2 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/bootstrap/css/bootstrap.css +3 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/bootstrap/images/glyphs.gif +0 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/css/style.css +6 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/images/next.gif +0 -0
- data/lib/javascript/clean-css/test/data/129-assets/components/jquery-ui/images/prev.gif +0 -0
- data/lib/javascript/clean-css/test/data/960-min.css +125 -0
- data/lib/javascript/clean-css/test/data/960.css +602 -0
- data/lib/javascript/clean-css/test/data/big-min.css +2984 -0
- data/lib/javascript/clean-css/test/data/big.css +13794 -0
- data/lib/javascript/clean-css/test/data/blueprint-min.css +245 -0
- data/lib/javascript/clean-css/test/data/blueprint.css +556 -0
- data/lib/javascript/clean-css/test/data/charset-mixed-with-fonts-min.css +3 -0
- data/lib/javascript/clean-css/test/data/charset-mixed-with-fonts.css +14 -0
- data/lib/javascript/clean-css/test/data/font-awesome-ie7-min.css +392 -0
- data/lib/javascript/clean-css/test/data/font-awesome-ie7.css +1203 -0
- data/lib/javascript/clean-css/test/data/font-awesome-min.css +319 -0
- data/lib/javascript/clean-css/test/data/font-awesome.css +540 -0
- data/lib/javascript/clean-css/test/data/imports-min.css +5 -0
- data/lib/javascript/clean-css/test/data/imports.css +4 -0
- data/lib/javascript/clean-css/test/data/issue-117-snippet-min.css +3 -0
- data/lib/javascript/clean-css/test/data/issue-117-snippet.css +19 -0
- data/lib/javascript/clean-css/test/data/issue-159-snippet-min.css +7 -0
- data/lib/javascript/clean-css/test/data/issue-159-snippet.css +7 -0
- data/lib/javascript/clean-css/test/data/issue-192-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-192.css +8 -0
- data/lib/javascript/clean-css/test/data/issue-198-min.css +3 -0
- data/lib/javascript/clean-css/test/data/issue-198.css +4 -0
- data/lib/javascript/clean-css/test/data/issue-232-min.css +2 -0
- data/lib/javascript/clean-css/test/data/issue-232.css +17 -0
- data/lib/javascript/clean-css/test/data/issue-241-min.css +2 -0
- data/lib/javascript/clean-css/test/data/issue-241.css +2 -0
- data/lib/javascript/clean-css/test/data/issue-304-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-304.css +4 -0
- data/lib/javascript/clean-css/test/data/issue-305-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-305.css +3 -0
- data/lib/javascript/clean-css/test/data/issue-308-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-308.css +5 -0
- data/lib/javascript/clean-css/test/data/issue-312-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-312.css +7 -0
- data/lib/javascript/clean-css/test/data/issue-337-min.css +1 -0
- data/lib/javascript/clean-css/test/data/issue-337.css +4 -0
- data/lib/javascript/clean-css/test/data/line-breaks-in-attributes-min.css +2 -0
- data/lib/javascript/clean-css/test/data/line-breaks-in-attributes.css +8 -0
- data/lib/javascript/clean-css/test/data/partials-absolute/base.css +3 -0
- data/lib/javascript/clean-css/test/data/partials-absolute/base2.css +1 -0
- data/lib/javascript/clean-css/test/data/partials-absolute/extra/sub.css +3 -0
- data/lib/javascript/clean-css/test/data/partials-relative/base.css +3 -0
- data/lib/javascript/clean-css/test/data/partials-relative/extra/included.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/comment.css +2 -0
- data/lib/javascript/clean-css/test/data/partials/extra/down.gif +0 -0
- data/lib/javascript/clean-css/test/data/partials/extra/four.css +3 -0
- data/lib/javascript/clean-css/test/data/partials/extra/three.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/five.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/four.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/one.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/three.css +1 -0
- data/lib/javascript/clean-css/test/data/partials/two.css +5 -0
- data/lib/javascript/clean-css/test/data/reset-min.css +12 -0
- data/lib/javascript/clean-css/test/data/reset.css +64 -0
- data/lib/javascript/clean-css/test/data/sample1-min.css +4 -0
- data/lib/javascript/clean-css/test/data/sample1.css +12 -0
- data/lib/javascript/clean-css/test/data/unsupported/selectors-ie7.css +20 -0
- data/lib/javascript/clean-css/test/data/unsupported/selectors-ie8.css +17 -0
- data/lib/javascript/clean-css/test/module-test.js +185 -0
- data/lib/javascript/clean-css/test/protocol-imports-test.js +409 -0
- data/lib/javascript/clean-css/test/text/splitter-test.js +20 -0
- data/lib/javascript/clean-css/test/unit-test.js +2071 -0
- data/lib/ruby-clean-css.rb +6 -0
- data/lib/ruby-clean-css/compressor.rb +142 -0
- data/lib/ruby-clean-css/exports.rb +258 -0
- data/lib/ruby-clean-css/railtie.rb +27 -0
- data/lib/ruby-clean-css/sprockets.rb +19 -0
- data/lib/ruby-clean-css/version.rb +5 -0
- data/ruby-clean-css.gemspec +30 -0
- data/test/test_compressor.rb +84 -0
- metadata +203 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
|
|
2
|
+
var processableInfo = require('./processable');
|
|
3
|
+
var overrideCompactor = require('./override-compactor');
|
|
4
|
+
var shorthandCompactor = require('./shorthand-compactor');
|
|
5
|
+
|
|
6
|
+
module.exports = function Optimizer(compatibility, aggressiveMerging) {
|
|
7
|
+
var overridable = {
|
|
8
|
+
'animation-delay': ['animation'],
|
|
9
|
+
'animation-direction': ['animation'],
|
|
10
|
+
'animation-duration': ['animation'],
|
|
11
|
+
'animation-fill-mode': ['animation'],
|
|
12
|
+
'animation-iteration-count': ['animation'],
|
|
13
|
+
'animation-name': ['animation'],
|
|
14
|
+
'animation-play-state': ['animation'],
|
|
15
|
+
'animation-timing-function': ['animation'],
|
|
16
|
+
'-moz-animation-delay': ['-moz-animation'],
|
|
17
|
+
'-moz-animation-direction': ['-moz-animation'],
|
|
18
|
+
'-moz-animation-duration': ['-moz-animation'],
|
|
19
|
+
'-moz-animation-fill-mode': ['-moz-animation'],
|
|
20
|
+
'-moz-animation-iteration-count': ['-moz-animation'],
|
|
21
|
+
'-moz-animation-name': ['-moz-animation'],
|
|
22
|
+
'-moz-animation-play-state': ['-moz-animation'],
|
|
23
|
+
'-moz-animation-timing-function': ['-moz-animation'],
|
|
24
|
+
'-o-animation-delay': ['-o-animation'],
|
|
25
|
+
'-o-animation-direction': ['-o-animation'],
|
|
26
|
+
'-o-animation-duration': ['-o-animation'],
|
|
27
|
+
'-o-animation-fill-mode': ['-o-animation'],
|
|
28
|
+
'-o-animation-iteration-count': ['-o-animation'],
|
|
29
|
+
'-o-animation-name': ['-o-animation'],
|
|
30
|
+
'-o-animation-play-state': ['-o-animation'],
|
|
31
|
+
'-o-animation-timing-function': ['-o-animation'],
|
|
32
|
+
'-webkit-animation-delay': ['-webkit-animation'],
|
|
33
|
+
'-webkit-animation-direction': ['-webkit-animation'],
|
|
34
|
+
'-webkit-animation-duration': ['-webkit-animation'],
|
|
35
|
+
'-webkit-animation-fill-mode': ['-webkit-animation'],
|
|
36
|
+
'-webkit-animation-iteration-count': ['-webkit-animation'],
|
|
37
|
+
'-webkit-animation-name': ['-webkit-animation'],
|
|
38
|
+
'-webkit-animation-play-state': ['-webkit-animation'],
|
|
39
|
+
'-webkit-animation-timing-function': ['-webkit-animation'],
|
|
40
|
+
'background-attachment': ['background'],
|
|
41
|
+
'background-clip': ['background'],
|
|
42
|
+
'background-color': ['background'],
|
|
43
|
+
'background-image': ['background'],
|
|
44
|
+
'background-origin': ['background'],
|
|
45
|
+
'background-position': ['background'],
|
|
46
|
+
'background-repeat': ['background'],
|
|
47
|
+
'background-size': ['background'],
|
|
48
|
+
'border-color': ['border'],
|
|
49
|
+
'border-style': ['border'],
|
|
50
|
+
'border-width': ['border'],
|
|
51
|
+
'border-bottom': ['border'],
|
|
52
|
+
'border-bottom-color': ['border-bottom', 'border-color', 'border'],
|
|
53
|
+
'border-bottom-style': ['border-bottom', 'border-style', 'border'],
|
|
54
|
+
'border-bottom-width': ['border-bottom', 'border-width', 'border'],
|
|
55
|
+
'border-left': ['border'],
|
|
56
|
+
'border-left-color': ['border-left', 'border-color', 'border'],
|
|
57
|
+
'border-left-style': ['border-left', 'border-style', 'border'],
|
|
58
|
+
'border-left-width': ['border-left', 'border-width', 'border'],
|
|
59
|
+
'border-right': ['border'],
|
|
60
|
+
'border-right-color': ['border-right', 'border-color', 'border'],
|
|
61
|
+
'border-right-style': ['border-right', 'border-style', 'border'],
|
|
62
|
+
'border-right-width': ['border-right', 'border-width', 'border'],
|
|
63
|
+
'border-top': ['border'],
|
|
64
|
+
'border-top-color': ['border-top', 'border-color', 'border'],
|
|
65
|
+
'border-top-style': ['border-top', 'border-style', 'border'],
|
|
66
|
+
'border-top-width': ['border-top', 'border-width', 'border'],
|
|
67
|
+
'font-family': ['font'],
|
|
68
|
+
'font-size': ['font'],
|
|
69
|
+
'font-style': ['font'],
|
|
70
|
+
'font-variant': ['font'],
|
|
71
|
+
'font-weight': ['font'],
|
|
72
|
+
'list-style-image': ['list-style'],
|
|
73
|
+
'list-style-position': ['list-style'],
|
|
74
|
+
'list-style-type': ['list-style'],
|
|
75
|
+
'margin-bottom': ['margin'],
|
|
76
|
+
'margin-left': ['margin'],
|
|
77
|
+
'margin-right': ['margin'],
|
|
78
|
+
'margin-top': ['margin'],
|
|
79
|
+
'outline-color': ['outline'],
|
|
80
|
+
'outline-style': ['outline'],
|
|
81
|
+
'outline-width': ['outline'],
|
|
82
|
+
'padding-bottom': ['padding'],
|
|
83
|
+
'padding-left': ['padding'],
|
|
84
|
+
'padding-right': ['padding'],
|
|
85
|
+
'padding-top': ['padding'],
|
|
86
|
+
'transition-delay': ['transition'],
|
|
87
|
+
'transition-duration': ['transition'],
|
|
88
|
+
'transition-property': ['transition'],
|
|
89
|
+
'transition-timing-function': ['transition'],
|
|
90
|
+
'-moz-transition-delay': ['-moz-transition'],
|
|
91
|
+
'-moz-transition-duration': ['-moz-transition'],
|
|
92
|
+
'-moz-transition-property': ['-moz-transition'],
|
|
93
|
+
'-moz-transition-timing-function': ['-moz-transition'],
|
|
94
|
+
'-o-transition-delay': ['-o-transition'],
|
|
95
|
+
'-o-transition-duration': ['-o-transition'],
|
|
96
|
+
'-o-transition-property': ['-o-transition'],
|
|
97
|
+
'-o-transition-timing-function': ['-o-transition'],
|
|
98
|
+
'-webkit-transition-delay': ['-webkit-transition'],
|
|
99
|
+
'-webkit-transition-duration': ['-webkit-transition'],
|
|
100
|
+
'-webkit-transition-property': ['-webkit-transition'],
|
|
101
|
+
'-webkit-transition-timing-function': ['-webkit-transition']
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
var IE_BACKSLASH_HACK = '\\9';
|
|
105
|
+
|
|
106
|
+
var overrides = {};
|
|
107
|
+
for (var granular in overridable) {
|
|
108
|
+
for (var i = 0; i < overridable[granular].length; i++) {
|
|
109
|
+
var coarse = overridable[granular][i];
|
|
110
|
+
var list = overrides[coarse];
|
|
111
|
+
|
|
112
|
+
if (list)
|
|
113
|
+
list.push(granular);
|
|
114
|
+
else
|
|
115
|
+
overrides[coarse] = [granular];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
var tokenize = function(body) {
|
|
120
|
+
var tokens = body.split(';');
|
|
121
|
+
var keyValues = [];
|
|
122
|
+
|
|
123
|
+
if (tokens.length === 0 || (tokens.length == 1 && tokens[0].indexOf(IE_BACKSLASH_HACK) == -1))
|
|
124
|
+
return;
|
|
125
|
+
|
|
126
|
+
for (var i = 0, l = tokens.length; i < l; i++) {
|
|
127
|
+
var token = tokens[i];
|
|
128
|
+
if (token === '')
|
|
129
|
+
continue;
|
|
130
|
+
|
|
131
|
+
var firstColon = token.indexOf(':');
|
|
132
|
+
keyValues.push([
|
|
133
|
+
token.substring(0, firstColon),
|
|
134
|
+
token.substring(firstColon + 1),
|
|
135
|
+
token.indexOf('!important') > -1,
|
|
136
|
+
token.indexOf(IE_BACKSLASH_HACK, firstColon + 1) === token.length - IE_BACKSLASH_HACK.length
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return keyValues;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
var optimize = function(tokens, allowAdjacent) {
|
|
144
|
+
var merged = [];
|
|
145
|
+
var properties = [];
|
|
146
|
+
var lastProperty = null;
|
|
147
|
+
var rescanTrigger = {};
|
|
148
|
+
|
|
149
|
+
var removeOverridenBy = function(property, isImportant) {
|
|
150
|
+
var overrided = overrides[property];
|
|
151
|
+
for (var i = 0, l = overrided.length; i < l; i++) {
|
|
152
|
+
for (var j = 0; j < properties.length; j++) {
|
|
153
|
+
if (properties[j] != overrided[i] || (merged[j][2] && !isImportant))
|
|
154
|
+
continue;
|
|
155
|
+
|
|
156
|
+
merged.splice(j, 1);
|
|
157
|
+
properties.splice(j, 1);
|
|
158
|
+
j -= 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
var mergeablePosition = function(position) {
|
|
164
|
+
if (allowAdjacent === false || allowAdjacent === true)
|
|
165
|
+
return allowAdjacent;
|
|
166
|
+
|
|
167
|
+
return allowAdjacent.indexOf(position) > -1;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
tokensLoop:
|
|
171
|
+
for (var i = 0, l = tokens.length; i < l; i++) {
|
|
172
|
+
var token = tokens[i];
|
|
173
|
+
var property = token[0];
|
|
174
|
+
var value = token[1];
|
|
175
|
+
var isImportant = token[2];
|
|
176
|
+
var isIEHack = token[3];
|
|
177
|
+
var _property = (property == '-ms-filter' || property == 'filter') ?
|
|
178
|
+
(lastProperty == 'background' || lastProperty == 'background-image' ? lastProperty : property) :
|
|
179
|
+
property;
|
|
180
|
+
var toOverridePosition = 0;
|
|
181
|
+
|
|
182
|
+
if (!compatibility && isIEHack)
|
|
183
|
+
continue;
|
|
184
|
+
|
|
185
|
+
// comment is necessary - we assume that if two properties are one after another
|
|
186
|
+
// then it is intentional way of redefining property which may not be widely supported
|
|
187
|
+
// e.g. a{display:inline-block;display:-moz-inline-box}
|
|
188
|
+
// however if `mergeablePosition` yields true then the rule does not apply
|
|
189
|
+
// (e.g merging two adjacent selectors: `a{display:block}a{display:block}`)
|
|
190
|
+
if (aggressiveMerging && _property != lastProperty || mergeablePosition(i)) {
|
|
191
|
+
while (true) {
|
|
192
|
+
toOverridePosition = properties.indexOf(_property, toOverridePosition);
|
|
193
|
+
if (toOverridePosition == -1)
|
|
194
|
+
break;
|
|
195
|
+
|
|
196
|
+
var lastToken = merged[toOverridePosition];
|
|
197
|
+
var wasImportant = lastToken[2];
|
|
198
|
+
var wasIEHack = lastToken[3];
|
|
199
|
+
|
|
200
|
+
if (wasImportant && !isImportant)
|
|
201
|
+
continue tokensLoop;
|
|
202
|
+
|
|
203
|
+
if (compatibility && !wasIEHack && isIEHack)
|
|
204
|
+
break;
|
|
205
|
+
|
|
206
|
+
var _info = processableInfo.processable[_property];
|
|
207
|
+
if (!isIEHack && !wasIEHack && _info && _info.canOverride && !_info.canOverride(tokens[toOverridePosition][1], value))
|
|
208
|
+
break;
|
|
209
|
+
|
|
210
|
+
merged.splice(toOverridePosition, 1);
|
|
211
|
+
properties.splice(toOverridePosition, 1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
merged.push(token);
|
|
216
|
+
properties.push(_property);
|
|
217
|
+
|
|
218
|
+
// certain properties (see values of `overridable`) should trigger removal of
|
|
219
|
+
// more granular properties (see keys of `overridable`)
|
|
220
|
+
if (rescanTrigger[_property])
|
|
221
|
+
removeOverridenBy(_property, isImportant);
|
|
222
|
+
|
|
223
|
+
// add rescan triggers - if certain property appears later in the list a rescan needs
|
|
224
|
+
// to be triggered, e.g 'border-top' triggers a rescan after 'border-top-width' and
|
|
225
|
+
// 'border-top-color' as they can be removed
|
|
226
|
+
for (var j = 0, list = overridable[_property] || [], m = list.length; j < m; j++)
|
|
227
|
+
rescanTrigger[list[j]] = true;
|
|
228
|
+
|
|
229
|
+
lastProperty = _property;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return merged;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
var rebuild = function(tokens) {
|
|
236
|
+
var flat = [];
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
for (var i = 0, l = tokens.length; i < l; i++) {
|
|
240
|
+
flat.push(tokens[i][0] + ':' + tokens[i][1]);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return flat.join(';');
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
var compact = function (input) {
|
|
247
|
+
var processable = processableInfo.processable;
|
|
248
|
+
var Token = processableInfo.Token;
|
|
249
|
+
|
|
250
|
+
var tokens = Token.tokenize(input);
|
|
251
|
+
|
|
252
|
+
tokens = overrideCompactor.compactOverrides(tokens, processable);
|
|
253
|
+
tokens = shorthandCompactor.compactShorthands(tokens, false, processable, Token);
|
|
254
|
+
tokens = shorthandCompactor.compactShorthands(tokens, true, processable, Token);
|
|
255
|
+
|
|
256
|
+
return Token.detokenize(tokens);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
process: function(body, allowAdjacent, skipCompacting) {
|
|
261
|
+
var result = body;
|
|
262
|
+
|
|
263
|
+
var tokens = tokenize(body);
|
|
264
|
+
if (tokens) {
|
|
265
|
+
var optimized = optimize(tokens, allowAdjacent);
|
|
266
|
+
result = rebuild(optimized);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!skipCompacting && processableInfo.implementedFor.test(result)) {
|
|
270
|
+
result = compact(result);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
|
|
2
|
+
// Compacts the given tokens according to their ability to override each other.
|
|
3
|
+
|
|
4
|
+
module.exports = (function () {
|
|
5
|
+
// Default override function: only allow overrides when the two values are the same
|
|
6
|
+
var sameValue = function (val1, val2) {
|
|
7
|
+
return val1 === val2;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
var compactOverrides = function (tokens, processable) {
|
|
11
|
+
var result, can, token, t, i, ii, oldResult, matchingComponent;
|
|
12
|
+
|
|
13
|
+
// Used when searching for a component that matches token
|
|
14
|
+
var nameMatchFilter1 = function (x) {
|
|
15
|
+
return x.prop === token.prop;
|
|
16
|
+
};
|
|
17
|
+
// Used when searching for a component that matches t
|
|
18
|
+
var nameMatchFilter2 = function (x) {
|
|
19
|
+
return x.prop === t.prop;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Go from the end and always take what the current token can't override as the new result set
|
|
23
|
+
// NOTE: can't cache result.length here because it will change with every iteration
|
|
24
|
+
for (result = tokens, i = 0; (ii = result.length - 1 - i) >= 0; i++) {
|
|
25
|
+
token = result[ii];
|
|
26
|
+
can = (processable[token.prop] && processable[token.prop].canOverride) || sameValue;
|
|
27
|
+
oldResult = result;
|
|
28
|
+
result = [];
|
|
29
|
+
|
|
30
|
+
// Special flag which indicates that the current token should be removed
|
|
31
|
+
var removeSelf = false;
|
|
32
|
+
var oldResultLength = oldResult.length;
|
|
33
|
+
|
|
34
|
+
for (var iii = 0; iii < oldResultLength; iii++) {
|
|
35
|
+
t = oldResult[iii];
|
|
36
|
+
|
|
37
|
+
// A token can't override itself (checked by reference, not by value)
|
|
38
|
+
// NOTE: except when we explicitly tell it to remove itself
|
|
39
|
+
if (t === token && !removeSelf) {
|
|
40
|
+
result.push(t);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Only an important token can even try to override tokens that come after it
|
|
45
|
+
if (iii > ii && !token.isImportant) {
|
|
46
|
+
result.push(t);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// A nonimportant token can never override an important one
|
|
51
|
+
if (t.isImportant && !token.isImportant) {
|
|
52
|
+
result.push(t);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (token.isShorthand && !t.isShorthand && t.isComponentOf(token)) {
|
|
57
|
+
// token (a shorthand) is trying to override t (a component)
|
|
58
|
+
|
|
59
|
+
// Find the matching component in the shorthand
|
|
60
|
+
matchingComponent = token.components.filter(nameMatchFilter2)[0];
|
|
61
|
+
can = (processable[t.prop] && processable[t.prop].canOverride) || sameValue;
|
|
62
|
+
if (!can(t.value, matchingComponent.value)) {
|
|
63
|
+
// The shorthand can't override the component
|
|
64
|
+
result.push(t);
|
|
65
|
+
}
|
|
66
|
+
} else if (t.isShorthand && !token.isShorthand && token.isComponentOf(t)) {
|
|
67
|
+
// token (a component) is trying to override a component of t (a shorthand)
|
|
68
|
+
|
|
69
|
+
// Find the matching component in the shorthand
|
|
70
|
+
matchingComponent = t.components.filter(nameMatchFilter1)[0];
|
|
71
|
+
if (can(matchingComponent.value, token.value)) {
|
|
72
|
+
// The component can override the matching component in the shorthand
|
|
73
|
+
|
|
74
|
+
if (!token.isImportant || token.isImportant && matchingComponent.isImportant) {
|
|
75
|
+
// The overriding component is non-important which means we can simply include it into the shorthand
|
|
76
|
+
// NOTE: stuff that can't really be included, like inherit, is taken care of at the final step, not here
|
|
77
|
+
matchingComponent.value = token.value;
|
|
78
|
+
// We use the special flag to get rid of the component
|
|
79
|
+
removeSelf = true;
|
|
80
|
+
} else {
|
|
81
|
+
// The overriding component is important; sadly we can't get rid of it,
|
|
82
|
+
// but we can still mark the matching component in the shorthand as irrelevant
|
|
83
|
+
matchingComponent.isIrrelevant = true;
|
|
84
|
+
}
|
|
85
|
+
t.isDirty = true;
|
|
86
|
+
}
|
|
87
|
+
result.push(t);
|
|
88
|
+
} else if (token.isShorthand && t.isShorthand && token.prop === t.prop) {
|
|
89
|
+
// token is a shorthand and is trying to override another instance of the same shorthand
|
|
90
|
+
|
|
91
|
+
// Can only override other shorthand when each of its components can override each of the other's components
|
|
92
|
+
for (var iiii = 0; iiii < t.components.length; iiii++) {
|
|
93
|
+
can = (processable[t.components[iiii].prop] && processable[t.components[iiii].prop].canOverride) || sameValue;
|
|
94
|
+
if (!can(t.components[iiii].value, token.components[iiii].value)) {
|
|
95
|
+
result.push(t);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else if (t.prop !== token.prop || !can(t.value, token.value)) {
|
|
100
|
+
// in every other case, use the override mechanism
|
|
101
|
+
result.push(t);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (removeSelf) {
|
|
105
|
+
i--;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return result;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
compactOverrides: compactOverrides
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
})();
|
|
@@ -0,0 +1,859 @@
|
|
|
1
|
+
|
|
2
|
+
// Contains the interpretation of CSS properties, as used by the property optimizer
|
|
3
|
+
|
|
4
|
+
module.exports = (function () {
|
|
5
|
+
|
|
6
|
+
var tokenModule = require('./token');
|
|
7
|
+
var validator = require('./validator');
|
|
8
|
+
var Splitter = require('../text/splitter');
|
|
9
|
+
|
|
10
|
+
// Functions that decide what value can override what.
|
|
11
|
+
// The main purpose is to disallow removing CSS fallbacks.
|
|
12
|
+
// A separate implementation is needed for every different kind of CSS property.
|
|
13
|
+
// -----
|
|
14
|
+
// The generic idea is that properties that have wider browser support are 'more understandable'
|
|
15
|
+
// than others and that 'less understandable' values can't override more understandable ones.
|
|
16
|
+
var canOverride = {
|
|
17
|
+
// Use when two tokens of the same property can always be merged
|
|
18
|
+
always: function () {
|
|
19
|
+
// NOTE: We could have (val1, val2) parameters here but jshint complains because we don't use them
|
|
20
|
+
return true;
|
|
21
|
+
},
|
|
22
|
+
// Use when two tokens of the same property can only be merged if they have the same value
|
|
23
|
+
sameValue: function(val1, val2) {
|
|
24
|
+
return val1 === val2;
|
|
25
|
+
},
|
|
26
|
+
sameFunctionOrValue: function(val1, val2) {
|
|
27
|
+
// Functions with the same name can override each other
|
|
28
|
+
if (validator.areSameFunction(val1, val2)) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return val1 === val2;
|
|
33
|
+
},
|
|
34
|
+
// Use for properties containing CSS units (margin-top, padding-left, etc.)
|
|
35
|
+
unit: function(val1, val2) {
|
|
36
|
+
// The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa
|
|
37
|
+
// Understandability: (unit without functions) > (same functions | standard functions) > anything else
|
|
38
|
+
// NOTE: there is no point in having different vendor-specific functions override each other or standard functions,
|
|
39
|
+
// or having standard functions override vendor-specific functions, but standard functions can override each other
|
|
40
|
+
// NOTE: vendor-specific property values are not taken into consideration here at the moment
|
|
41
|
+
|
|
42
|
+
if (validator.isValidUnitWithoutFunction(val2))
|
|
43
|
+
return true;
|
|
44
|
+
if (validator.isValidUnitWithoutFunction(val1))
|
|
45
|
+
return false;
|
|
46
|
+
|
|
47
|
+
// Standard non-vendor-prefixed functions can override each other
|
|
48
|
+
if (validator.isValidFunctionWithoutVendorPrefix(val2) && validator.isValidFunctionWithoutVendorPrefix(val1)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Functions with the same name can override each other; same values can override each other
|
|
53
|
+
return canOverride.sameFunctionOrValue(val1, val2);
|
|
54
|
+
},
|
|
55
|
+
// Use for color properties (color, background-color, border-color, etc.)
|
|
56
|
+
color: function(val1, val2) {
|
|
57
|
+
// The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa
|
|
58
|
+
// Understandability: (hex | named) > (rgba | hsla) > (same function name) > anything else
|
|
59
|
+
// NOTE: at this point rgb and hsl are replaced by hex values by clean-css
|
|
60
|
+
|
|
61
|
+
// (hex | named)
|
|
62
|
+
if (validator.isValidNamedColor(val2) || validator.isValidHexColor(val2))
|
|
63
|
+
return true;
|
|
64
|
+
if (validator.isValidNamedColor(val1) || validator.isValidHexColor(val1))
|
|
65
|
+
return false;
|
|
66
|
+
|
|
67
|
+
// (rgba|hsla)
|
|
68
|
+
if (validator.isValidRgbaColor(val2) || validator.isValidHslaColor(val2))
|
|
69
|
+
return true;
|
|
70
|
+
if (validator.isValidRgbaColor(val1) || validator.isValidHslaColor(val1))
|
|
71
|
+
return false;
|
|
72
|
+
|
|
73
|
+
// Functions with the same name can override each other; same values can override each other
|
|
74
|
+
return canOverride.sameFunctionOrValue(val1, val2);
|
|
75
|
+
},
|
|
76
|
+
// Use for background-image
|
|
77
|
+
backgroundImage: function(val1, val2) {
|
|
78
|
+
// The idea here is that 'more understandable' values override 'less understandable' values, but not vice versa
|
|
79
|
+
// Understandability: (none | url | inherit) > (same function) > (same value)
|
|
80
|
+
|
|
81
|
+
// (none | url)
|
|
82
|
+
if (val2 === 'none' || val2 === 'inherit' || validator.isValidUrl(val2))
|
|
83
|
+
return true;
|
|
84
|
+
if (val1 === 'none' || val1 === 'inherit' || validator.isValidUrl(val1))
|
|
85
|
+
return false;
|
|
86
|
+
|
|
87
|
+
// Functions with the same name can override each other; same values can override each other
|
|
88
|
+
return canOverride.sameFunctionOrValue(val1, val2);
|
|
89
|
+
},
|
|
90
|
+
border: function(val1, val2) {
|
|
91
|
+
var brokenUp1 = breakUp.border(Token.tokenizeOne(val1));
|
|
92
|
+
var brokenUp2 = breakUp.border(Token.tokenizeOne(val2));
|
|
93
|
+
|
|
94
|
+
return canOverride.color(brokenUp1[2].value, brokenUp2[2].value);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
canOverride = Object.freeze(canOverride);
|
|
98
|
+
|
|
99
|
+
// Functions for breaking up shorthands to components
|
|
100
|
+
var breakUp = {};
|
|
101
|
+
breakUp.takeCareOfFourValues = function (splitfunc) {
|
|
102
|
+
return function (token) {
|
|
103
|
+
var descriptor = processable[token.prop];
|
|
104
|
+
var result = [];
|
|
105
|
+
var splitval = splitfunc(token.value);
|
|
106
|
+
|
|
107
|
+
if (splitval.length === 0 || (splitval.length < descriptor.components.length && descriptor.components.length > 4)) {
|
|
108
|
+
// This token is malformed and we have no idea how to fix it. So let's just keep it intact
|
|
109
|
+
return [token];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Fix those that we do know how to fix
|
|
113
|
+
if (splitval.length < descriptor.components.length && splitval.length < 2) {
|
|
114
|
+
// foo{margin:1px} -> foo{margin:1px 1px}
|
|
115
|
+
splitval[1] = splitval[0];
|
|
116
|
+
}
|
|
117
|
+
if (splitval.length < descriptor.components.length && splitval.length < 3) {
|
|
118
|
+
// foo{margin:1px 2px} -> foo{margin:1px 2px 1px}
|
|
119
|
+
splitval[2] = splitval[0];
|
|
120
|
+
}
|
|
121
|
+
if (splitval.length < descriptor.components.length && splitval.length < 4) {
|
|
122
|
+
// foo{margin:1px 2px 3px} -> foo{margin:1px 2px 3px 2px}
|
|
123
|
+
splitval[3] = splitval[1];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Now break it up to its components
|
|
127
|
+
for (var i = 0; i < descriptor.components.length; i++) {
|
|
128
|
+
var t = new Token(descriptor.components[i], splitval[i], token.isImportant);
|
|
129
|
+
result.push(t);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return result;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
// Use this when you simply want to break up four values along spaces
|
|
136
|
+
breakUp.fourBySpaces = breakUp.takeCareOfFourValues(function (val) {
|
|
137
|
+
return new Splitter(' ').split(val).filter(function (v) { return v; });
|
|
138
|
+
});
|
|
139
|
+
// Breaks up a background property value
|
|
140
|
+
breakUp.commaSeparatedMulitpleValues = function (splitfunc) {
|
|
141
|
+
return function (token) {
|
|
142
|
+
if (token.value.indexOf(',') === -1)
|
|
143
|
+
return splitfunc(token);
|
|
144
|
+
|
|
145
|
+
var values = new Splitter(',').split(token.value);
|
|
146
|
+
var components = [];
|
|
147
|
+
|
|
148
|
+
for (var i = 0, l = values.length; i < l; i++) {
|
|
149
|
+
token.value = values[i];
|
|
150
|
+
components.push(splitfunc(token));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
for (var j = 0, m = components[0].length; j < m; j++) {
|
|
154
|
+
for (var k = 0, n = components.length, newValues = []; k < n; k++) {
|
|
155
|
+
newValues.push(components[k][j].value);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
components[0][j].value = newValues.join(',');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return components[0];
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
breakUp.background = function (token) {
|
|
165
|
+
// Default values
|
|
166
|
+
var result = Token.makeDefaults(['background-image', 'background-position', 'background-size', 'background-repeat', 'background-attachment', 'background-color'], token.isImportant);
|
|
167
|
+
var image = result[0];
|
|
168
|
+
var position = result[1];
|
|
169
|
+
var size = result[2];
|
|
170
|
+
var repeat = result[3];
|
|
171
|
+
var attachment = result[4];
|
|
172
|
+
var color = result[5];
|
|
173
|
+
|
|
174
|
+
// Take care of inherit
|
|
175
|
+
if (token.value === 'inherit') {
|
|
176
|
+
// NOTE: 'inherit' is not a valid value for background-attachment so there we'll leave the default value
|
|
177
|
+
color.value = image.value = repeat.value = position.value = size.value = attachment.value = 'inherit';
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Break the background up into parts
|
|
182
|
+
var parts = new Splitter(' ').split(token.value);
|
|
183
|
+
if (parts.length === 0)
|
|
184
|
+
return result;
|
|
185
|
+
|
|
186
|
+
// Iterate over all parts and try to fit them into positions
|
|
187
|
+
for (var i = parts.length - 1; i >= 0; i--) {
|
|
188
|
+
var currentPart = parts[i];
|
|
189
|
+
|
|
190
|
+
if (validator.isValidBackgroundAttachment(currentPart)) {
|
|
191
|
+
attachment.value = currentPart;
|
|
192
|
+
} else if (validator.isValidBackgroundRepeat(currentPart)) {
|
|
193
|
+
repeat.value = currentPart;
|
|
194
|
+
} else if (validator.isValidBackgroundPositionPart(currentPart) || validator.isValidBackgroundSizePart(currentPart)) {
|
|
195
|
+
if (i > 0) {
|
|
196
|
+
var previousPart = parts[i - 1];
|
|
197
|
+
|
|
198
|
+
if (previousPart.indexOf('/') > 0) {
|
|
199
|
+
var twoParts = new Splitter('/').split(previousPart);
|
|
200
|
+
size.value = twoParts.pop() + ' ' + currentPart;
|
|
201
|
+
parts[i - 1] = twoParts.pop();
|
|
202
|
+
} else if (i > 1 && parts[i - 2] == '/') {
|
|
203
|
+
size.value = previousPart + ' ' + currentPart;
|
|
204
|
+
i -= 2;
|
|
205
|
+
} else if (parts[i - 1] == '/') {
|
|
206
|
+
size.value = currentPart;
|
|
207
|
+
position.value = previousPart;
|
|
208
|
+
i--;
|
|
209
|
+
} else {
|
|
210
|
+
position.value = previousPart + ' ' + currentPart;
|
|
211
|
+
i--;
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
position.value = currentPart;
|
|
215
|
+
}
|
|
216
|
+
} else if (validator.isValidBackgroundPositionAndSize(currentPart)) {
|
|
217
|
+
var sizeValue = new Splitter('/').split(currentPart);
|
|
218
|
+
size.value = sizeValue.pop();
|
|
219
|
+
position.value = sizeValue.pop();
|
|
220
|
+
} else if ((color.value == processable[color.prop].defaultValue || color.value == 'none') && validator.isValidColor(currentPart)) {
|
|
221
|
+
color.value = currentPart;
|
|
222
|
+
} else if (validator.isValidUrl(currentPart) || validator.isValidFunction(currentPart)) {
|
|
223
|
+
image.value = currentPart;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return result;
|
|
228
|
+
};
|
|
229
|
+
// Breaks up a list-style property value
|
|
230
|
+
breakUp.listStyle = function (token) {
|
|
231
|
+
// Default values
|
|
232
|
+
var result = Token.makeDefaults(['list-style-type', 'list-style-position', 'list-style-image'], token.isImportant);
|
|
233
|
+
var type = result[0], position = result[1], image = result[2];
|
|
234
|
+
|
|
235
|
+
if (token.value === 'inherit') {
|
|
236
|
+
type.value = position.value = image.value = 'inherit';
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
var parts = new Splitter(' ').split(token.value);
|
|
241
|
+
var ci = 0;
|
|
242
|
+
|
|
243
|
+
// Type
|
|
244
|
+
if (ci < parts.length && validator.isValidListStyleType(parts[ci])) {
|
|
245
|
+
type.value = parts[ci];
|
|
246
|
+
ci++;
|
|
247
|
+
}
|
|
248
|
+
// Position
|
|
249
|
+
if (ci < parts.length && validator.isValidListStylePosition(parts[ci])) {
|
|
250
|
+
position.value = parts[ci];
|
|
251
|
+
ci++;
|
|
252
|
+
}
|
|
253
|
+
// Image
|
|
254
|
+
if (ci < parts.length) {
|
|
255
|
+
image.value = parts.splice(ci, parts.length - ci + 1).join(' ');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return result;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
breakUp._widthStyleColor = function(token, prefix, order) {
|
|
262
|
+
// Default values
|
|
263
|
+
var components = order.map(function(prop) {
|
|
264
|
+
return prefix + '-' + prop;
|
|
265
|
+
});
|
|
266
|
+
var result = Token.makeDefaults(components, token.isImportant);
|
|
267
|
+
var color = result[order.indexOf('color')];
|
|
268
|
+
var style = result[order.indexOf('style')];
|
|
269
|
+
var width = result[order.indexOf('width')];
|
|
270
|
+
|
|
271
|
+
// Take care of inherit
|
|
272
|
+
if (token.value === 'inherit' || token.value === 'inherit inherit inherit') {
|
|
273
|
+
color.value = style.value = width.value = 'inherit';
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// NOTE: usually users don't follow the required order of parts in this shorthand,
|
|
278
|
+
// so we'll try to parse it caring as little about order as possible
|
|
279
|
+
|
|
280
|
+
var parts = new Splitter(' ').split(token.value), w;
|
|
281
|
+
|
|
282
|
+
if (parts.length === 0) {
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (parts.length >= 1) {
|
|
287
|
+
// Try to find -width, excluding inherit because that can be anything
|
|
288
|
+
w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineWidth(p); });
|
|
289
|
+
if (w.length) {
|
|
290
|
+
width.value = w[0];
|
|
291
|
+
parts.splice(parts.indexOf(w[0]), 1);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (parts.length >= 1) {
|
|
295
|
+
// Try to find -style, excluding inherit because that can be anything
|
|
296
|
+
w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineStyle(p); });
|
|
297
|
+
if (w.length) {
|
|
298
|
+
style.value = w[0];
|
|
299
|
+
parts.splice(parts.indexOf(w[0]), 1);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (parts.length >= 1) {
|
|
303
|
+
// Find -color but this time can catch inherit
|
|
304
|
+
w = parts.filter(function(p) { return validator.isValidOutlineColor(p); });
|
|
305
|
+
if (w.length) {
|
|
306
|
+
color.value = w[0];
|
|
307
|
+
parts.splice(parts.indexOf(w[0]), 1);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return result;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
breakUp.outline = function(token) {
|
|
315
|
+
return breakUp._widthStyleColor(token, 'outline', ['color', 'style', 'width']);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
breakUp.border = function(token) {
|
|
319
|
+
return breakUp._widthStyleColor(token, 'border', ['width', 'style', 'color']);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
breakUp.borderRadius = function(token) {
|
|
323
|
+
var parts = token.value.split('/');
|
|
324
|
+
if (parts.length == 1)
|
|
325
|
+
return breakUp.fourBySpaces(token);
|
|
326
|
+
|
|
327
|
+
var horizontalPart = token.clone();
|
|
328
|
+
var verticalPart = token.clone();
|
|
329
|
+
|
|
330
|
+
horizontalPart.value = parts[0];
|
|
331
|
+
verticalPart.value = parts[1];
|
|
332
|
+
|
|
333
|
+
var horizontalBreakUp = breakUp.fourBySpaces(horizontalPart);
|
|
334
|
+
var verticalBreakUp = breakUp.fourBySpaces(verticalPart);
|
|
335
|
+
|
|
336
|
+
for (var i = 0; i < 4; i++) {
|
|
337
|
+
horizontalBreakUp[i].value = [horizontalBreakUp[i].value, verticalBreakUp[i].value];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return horizontalBreakUp;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// Contains functions that can put together shorthands from their components
|
|
344
|
+
// NOTE: correct order of tokens is assumed inside these functions!
|
|
345
|
+
var putTogether = {
|
|
346
|
+
// Use this for properties which have four unit values (margin, padding, etc.)
|
|
347
|
+
// NOTE: optimizes to shorter forms too (that only specify 1, 2, or 3 values)
|
|
348
|
+
fourUnits: function (prop, tokens, isImportant) {
|
|
349
|
+
// See about irrelevant tokens
|
|
350
|
+
// NOTE: This will enable some crazy optimalizations for us.
|
|
351
|
+
if (tokens[0].isIrrelevant)
|
|
352
|
+
tokens[0].value = tokens[2].value;
|
|
353
|
+
if (tokens[2].isIrrelevant)
|
|
354
|
+
tokens[2].value = tokens[0].value;
|
|
355
|
+
if (tokens[1].isIrrelevant)
|
|
356
|
+
tokens[1].value = tokens[3].value;
|
|
357
|
+
if (tokens[3].isIrrelevant)
|
|
358
|
+
tokens[3].value = tokens[1].value;
|
|
359
|
+
|
|
360
|
+
if (tokens[0].isIrrelevant && tokens[2].isIrrelevant) {
|
|
361
|
+
if (tokens[1].value === tokens[3].value)
|
|
362
|
+
tokens[0].value = tokens[2].value = tokens[1].value;
|
|
363
|
+
else
|
|
364
|
+
tokens[0].value = tokens[2].value = '0';
|
|
365
|
+
}
|
|
366
|
+
if (tokens[1].isIrrelevant && tokens[3].isIrrelevant) {
|
|
367
|
+
if (tokens[0].value === tokens[2].value)
|
|
368
|
+
tokens[1].value = tokens[3].value = tokens[0].value;
|
|
369
|
+
else
|
|
370
|
+
tokens[1].value = tokens[3].value = '0';
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
var result = new Token(prop, tokens[0].value, isImportant);
|
|
374
|
+
result.granularValues = [];
|
|
375
|
+
result.granularValues[tokens[0].prop] = tokens[0].value;
|
|
376
|
+
result.granularValues[tokens[1].prop] = tokens[1].value;
|
|
377
|
+
result.granularValues[tokens[2].prop] = tokens[2].value;
|
|
378
|
+
result.granularValues[tokens[3].prop] = tokens[3].value;
|
|
379
|
+
|
|
380
|
+
// If all of them are irrelevant
|
|
381
|
+
if (tokens[0].isIrrelevant && tokens[1].isIrrelevant && tokens[2].isIrrelevant && tokens[3].isIrrelevant) {
|
|
382
|
+
result.value = processable[prop].shortestValue || processable[prop].defaultValue;
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 1-value short form: all four components are equal
|
|
387
|
+
if (tokens[0].value === tokens[1].value && tokens[0].value === tokens[2].value && tokens[0].value === tokens[3].value) {
|
|
388
|
+
return result;
|
|
389
|
+
}
|
|
390
|
+
result.value += ' ' + tokens[1].value;
|
|
391
|
+
// 2-value short form: first and third; second and fourth values are equal
|
|
392
|
+
if (tokens[0].value === tokens[2].value && tokens[1].value === tokens[3].value) {
|
|
393
|
+
return result;
|
|
394
|
+
}
|
|
395
|
+
result.value += ' ' + tokens[2].value;
|
|
396
|
+
// 3-value short form: second and fourth values are equal
|
|
397
|
+
if (tokens[1].value === tokens[3].value) {
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
// 4-value form (none of the above optimalizations could be accomplished)
|
|
401
|
+
result.value += ' ' + tokens[3].value;
|
|
402
|
+
return result;
|
|
403
|
+
},
|
|
404
|
+
// Puts together the components by spaces and omits default values (this is the case for most shorthands)
|
|
405
|
+
bySpacesOmitDefaults: function (prop, tokens, isImportant, meta) {
|
|
406
|
+
var result = new Token(prop, '', isImportant);
|
|
407
|
+
|
|
408
|
+
// Get irrelevant tokens
|
|
409
|
+
var irrelevantTokens = tokens.filter(function (t) { return t.isIrrelevant; });
|
|
410
|
+
|
|
411
|
+
// If every token is irrelevant, return shortest possible value, fallback to default value
|
|
412
|
+
if (irrelevantTokens.length === tokens.length) {
|
|
413
|
+
result.isIrrelevant = true;
|
|
414
|
+
result.value = processable[prop].shortestValue || processable[prop].defaultValue;
|
|
415
|
+
return result;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// This will be the value of the shorthand if all the components are default
|
|
419
|
+
var valueIfAllDefault = processable[prop].defaultValue;
|
|
420
|
+
|
|
421
|
+
// Go through all tokens and concatenate their values as necessary
|
|
422
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
423
|
+
var token = tokens[i];
|
|
424
|
+
|
|
425
|
+
// Set granular value so that other parts of the code can use this for optimalization opportunities
|
|
426
|
+
result.granularValues = result.granularValues || { };
|
|
427
|
+
result.granularValues[token.prop] = token.value;
|
|
428
|
+
|
|
429
|
+
// Use irrelevant tokens for optimalization opportunity
|
|
430
|
+
if (token.isIrrelevant) {
|
|
431
|
+
// Get shortest possible value, fallback to default value
|
|
432
|
+
var tokenShortest = processable[token.prop].shortestValue || processable[token.prop].defaultValue;
|
|
433
|
+
// If the shortest possible value of this token is shorter than the default value of the shorthand, use it instead
|
|
434
|
+
if (tokenShortest.length < valueIfAllDefault.length) {
|
|
435
|
+
valueIfAllDefault = tokenShortest;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Omit default / irrelevant value
|
|
440
|
+
if (token.isIrrelevant || (processable[token.prop] && processable[token.prop].defaultValue === token.value)) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (meta && meta.partsCount && meta.position < meta.partsCount - 1 && processable[token.prop].multiValueLastOnly)
|
|
445
|
+
continue;
|
|
446
|
+
|
|
447
|
+
var requiresPreceeding = processable[token.prop].shorthandFollows;
|
|
448
|
+
if (requiresPreceeding && (tokens[i - 1].value == processable[requiresPreceeding].defaultValue)) {
|
|
449
|
+
result.value += ' ' + tokens[i - 1].value;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
result.value += (processable[token.prop].prefixShorthandValueWith || ' ') + token.value;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
result.value = result.value.trim();
|
|
456
|
+
if (!result.value) {
|
|
457
|
+
result.value = valueIfAllDefault;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return result;
|
|
461
|
+
},
|
|
462
|
+
commaSeparatedMulitpleValues: function (assembleFunction) {
|
|
463
|
+
return function(prop, tokens, isImportant) {
|
|
464
|
+
var tokenSplitLengths = tokens.map(function (token) {
|
|
465
|
+
return new Splitter(',').split(token.value).length;
|
|
466
|
+
});
|
|
467
|
+
var partsCount = Math.max.apply(Math, tokenSplitLengths);
|
|
468
|
+
|
|
469
|
+
if (partsCount == 1)
|
|
470
|
+
return assembleFunction(prop, tokens, isImportant);
|
|
471
|
+
|
|
472
|
+
var merged = [];
|
|
473
|
+
|
|
474
|
+
for (var i = 0; i < partsCount; i++) {
|
|
475
|
+
merged.push([]);
|
|
476
|
+
|
|
477
|
+
for (var j = 0; j < tokens.length; j++) {
|
|
478
|
+
var split = new Splitter(',').split(tokens[j].value);
|
|
479
|
+
merged[i].push(split[i] || split[0]);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
var mergedValues = [];
|
|
484
|
+
var firstProcessed;
|
|
485
|
+
for (i = 0; i < partsCount; i++) {
|
|
486
|
+
for (var k = 0, n = merged[i].length; k < n; k++) {
|
|
487
|
+
tokens[k].value = merged[i][k];
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
var meta = {
|
|
491
|
+
partsCount: partsCount,
|
|
492
|
+
position: i
|
|
493
|
+
};
|
|
494
|
+
var processed = assembleFunction(prop, tokens, isImportant, meta);
|
|
495
|
+
mergedValues.push(processed.value);
|
|
496
|
+
|
|
497
|
+
if (!firstProcessed)
|
|
498
|
+
firstProcessed = processed;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
firstProcessed.value = mergedValues.join(',');
|
|
502
|
+
return firstProcessed;
|
|
503
|
+
};
|
|
504
|
+
},
|
|
505
|
+
// Handles the cases when some or all the fine-grained properties are set to inherit
|
|
506
|
+
takeCareOfInherit: function (innerFunc) {
|
|
507
|
+
return function (prop, tokens, isImportant, meta) {
|
|
508
|
+
// Filter out the inheriting and non-inheriting tokens in one iteration
|
|
509
|
+
var inheritingTokens = [];
|
|
510
|
+
var nonInheritingTokens = [];
|
|
511
|
+
var result2Shorthandable = [];
|
|
512
|
+
var i;
|
|
513
|
+
for (i = 0; i < tokens.length; i++) {
|
|
514
|
+
if (tokens[i].value === 'inherit') {
|
|
515
|
+
inheritingTokens.push(tokens[i]);
|
|
516
|
+
|
|
517
|
+
// Indicate that this property is irrelevant and its value can safely be set to anything else
|
|
518
|
+
var r2s = new Token(tokens[i].prop, tokens[i].isImportant);
|
|
519
|
+
r2s.isIrrelevant = true;
|
|
520
|
+
result2Shorthandable.push(r2s);
|
|
521
|
+
} else {
|
|
522
|
+
nonInheritingTokens.push(tokens[i]);
|
|
523
|
+
result2Shorthandable.push(tokens[i]);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (nonInheritingTokens.length === 0) {
|
|
528
|
+
// When all the tokens are 'inherit'
|
|
529
|
+
return new Token(prop, 'inherit', isImportant);
|
|
530
|
+
} else if (inheritingTokens.length > 0) {
|
|
531
|
+
// When some (but not all) of the tokens are 'inherit'
|
|
532
|
+
|
|
533
|
+
// Result 1. Shorthand just the inherit values and have it overridden with the non-inheriting ones
|
|
534
|
+
var result1 = [new Token(prop, 'inherit', isImportant)].concat(nonInheritingTokens);
|
|
535
|
+
|
|
536
|
+
// Result 2. Shorthand every non-inherit value and then have it overridden with the inheriting ones
|
|
537
|
+
var result2 = [innerFunc(prop, result2Shorthandable, isImportant, meta)].concat(inheritingTokens);
|
|
538
|
+
|
|
539
|
+
// Return whichever is shorter
|
|
540
|
+
var dl1 = Token.getDetokenizedLength(result1);
|
|
541
|
+
var dl2 = Token.getDetokenizedLength(result2);
|
|
542
|
+
|
|
543
|
+
return dl1 < dl2 ? result1 : result2;
|
|
544
|
+
} else {
|
|
545
|
+
// When none of tokens are 'inherit'
|
|
546
|
+
return innerFunc(prop, tokens, isImportant, meta);
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
},
|
|
550
|
+
borderRadius: function (prop, tokens, isImportant) {
|
|
551
|
+
var verticalTokens = [];
|
|
552
|
+
|
|
553
|
+
for (var i = 0, l = tokens.length; i < l; i++) {
|
|
554
|
+
var token = tokens[i];
|
|
555
|
+
if (!Array.isArray(token.value))
|
|
556
|
+
continue;
|
|
557
|
+
|
|
558
|
+
if (token.value.length > 1) {
|
|
559
|
+
verticalTokens.push({
|
|
560
|
+
prop: token.prop,
|
|
561
|
+
value: token.value[1],
|
|
562
|
+
isImportant: token.isImportant
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
token.value = token.value[0];
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
var result = putTogether.takeCareOfInherit(putTogether.fourUnits)(prop, tokens, isImportant);
|
|
570
|
+
if (verticalTokens.length > 0) {
|
|
571
|
+
var verticalResult = putTogether.takeCareOfInherit(putTogether.fourUnits)(prop, verticalTokens, isImportant);
|
|
572
|
+
if (result.value != verticalResult.value)
|
|
573
|
+
result.value += '/' + verticalResult.value;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return result;
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
// Properties to process
|
|
581
|
+
// Extend this object in order to add support for more properties in the optimizer.
|
|
582
|
+
//
|
|
583
|
+
// Each key in this object represents a CSS property and should be an object.
|
|
584
|
+
// Such an object contains properties that describe how the represented CSS property should be handled.
|
|
585
|
+
// Possible options:
|
|
586
|
+
//
|
|
587
|
+
// * components: array (Only specify for shorthand properties.)
|
|
588
|
+
// Contains the names of the granular properties this shorthand compacts.
|
|
589
|
+
//
|
|
590
|
+
// * canOverride: function (Default is canOverride.sameValue - meaning that they'll only be merged if they have the same value.)
|
|
591
|
+
// Returns whether two tokens of this property can be merged with each other.
|
|
592
|
+
// This property has no meaning for shorthands.
|
|
593
|
+
//
|
|
594
|
+
// * defaultValue: string
|
|
595
|
+
// Specifies the default value of the property according to the CSS standard.
|
|
596
|
+
// For shorthand, this is used when every component is set to its default value, therefore it should be the shortest possible default value of all the components.
|
|
597
|
+
//
|
|
598
|
+
// * shortestValue: string
|
|
599
|
+
// Specifies the shortest possible value the property can possibly have.
|
|
600
|
+
// (Falls back to defaultValue if unspecified.)
|
|
601
|
+
//
|
|
602
|
+
// * breakUp: function (Only specify for shorthand properties.)
|
|
603
|
+
// Breaks the shorthand up to its components.
|
|
604
|
+
//
|
|
605
|
+
// * putTogether: function (Only specify for shorthand properties.)
|
|
606
|
+
// Puts the shorthand together from its components.
|
|
607
|
+
//
|
|
608
|
+
var processable = {
|
|
609
|
+
'color': {
|
|
610
|
+
canOverride: canOverride.color,
|
|
611
|
+
defaultValue: 'transparent',
|
|
612
|
+
shortestValue: 'red'
|
|
613
|
+
},
|
|
614
|
+
// background ------------------------------------------------------------------------------
|
|
615
|
+
'background': {
|
|
616
|
+
components: [
|
|
617
|
+
'background-image',
|
|
618
|
+
'background-position',
|
|
619
|
+
'background-size',
|
|
620
|
+
'background-repeat',
|
|
621
|
+
'background-attachment',
|
|
622
|
+
'background-color'
|
|
623
|
+
],
|
|
624
|
+
breakUp: breakUp.commaSeparatedMulitpleValues(breakUp.background),
|
|
625
|
+
putTogether: putTogether.commaSeparatedMulitpleValues(
|
|
626
|
+
putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults)
|
|
627
|
+
),
|
|
628
|
+
defaultValue: '0 0',
|
|
629
|
+
shortestValue: '0'
|
|
630
|
+
},
|
|
631
|
+
'background-color': {
|
|
632
|
+
canOverride: canOverride.color,
|
|
633
|
+
defaultValue: 'transparent',
|
|
634
|
+
multiValueLastOnly: true,
|
|
635
|
+
shortestValue: 'red'
|
|
636
|
+
},
|
|
637
|
+
'background-image': {
|
|
638
|
+
canOverride: canOverride.backgroundImage,
|
|
639
|
+
defaultValue: 'none'
|
|
640
|
+
},
|
|
641
|
+
'background-repeat': {
|
|
642
|
+
canOverride: canOverride.always,
|
|
643
|
+
defaultValue: 'repeat'
|
|
644
|
+
},
|
|
645
|
+
'background-position': {
|
|
646
|
+
canOverride: canOverride.always,
|
|
647
|
+
defaultValue: '0 0',
|
|
648
|
+
shortestValue: '0'
|
|
649
|
+
},
|
|
650
|
+
'background-size': {
|
|
651
|
+
canOverride: canOverride.always,
|
|
652
|
+
defaultValue: 'auto',
|
|
653
|
+
shortestValue: '0 0',
|
|
654
|
+
prefixShorthandValueWith: '/',
|
|
655
|
+
shorthandFollows: 'background-position'
|
|
656
|
+
},
|
|
657
|
+
'background-attachment': {
|
|
658
|
+
canOverride: canOverride.always,
|
|
659
|
+
defaultValue: 'scroll'
|
|
660
|
+
},
|
|
661
|
+
'border': {
|
|
662
|
+
breakUp: breakUp.border,
|
|
663
|
+
canOverride: canOverride.border,
|
|
664
|
+
components: [
|
|
665
|
+
'border-width',
|
|
666
|
+
'border-style',
|
|
667
|
+
'border-color'
|
|
668
|
+
],
|
|
669
|
+
defaultValue: 'none',
|
|
670
|
+
putTogether: putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults)
|
|
671
|
+
},
|
|
672
|
+
'border-color': {
|
|
673
|
+
canOverride: canOverride.color,
|
|
674
|
+
defaultValue: 'none'
|
|
675
|
+
},
|
|
676
|
+
'border-style': {
|
|
677
|
+
canOverride: canOverride.always,
|
|
678
|
+
defaultValue: 'none'
|
|
679
|
+
},
|
|
680
|
+
'border-width': {
|
|
681
|
+
canOverride: canOverride.unit,
|
|
682
|
+
defaultValue: 'medium',
|
|
683
|
+
shortestValue: '0'
|
|
684
|
+
},
|
|
685
|
+
// list-style ------------------------------------------------------------------------------
|
|
686
|
+
'list-style': {
|
|
687
|
+
components: [
|
|
688
|
+
'list-style-type',
|
|
689
|
+
'list-style-position',
|
|
690
|
+
'list-style-image'
|
|
691
|
+
],
|
|
692
|
+
canOverride: canOverride.always,
|
|
693
|
+
breakUp: breakUp.listStyle,
|
|
694
|
+
putTogether: putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults),
|
|
695
|
+
defaultValue: 'outside', // can't use 'disc' because that'd override default 'decimal' for <ol>
|
|
696
|
+
shortestValue: 'none'
|
|
697
|
+
},
|
|
698
|
+
'list-style-type' : {
|
|
699
|
+
canOverride: canOverride.always,
|
|
700
|
+
shortestValue: 'none',
|
|
701
|
+
defaultValue: '__hack'
|
|
702
|
+
// NOTE: we can't tell the real default value here, it's 'disc' for <ul> and 'decimal' for <ol>
|
|
703
|
+
// -- this is a hack, but it doesn't matter because this value will be either overridden or it will disappear at the final step anyway
|
|
704
|
+
},
|
|
705
|
+
'list-style-position' : {
|
|
706
|
+
canOverride: canOverride.always,
|
|
707
|
+
defaultValue: 'outside',
|
|
708
|
+
shortestValue: 'inside'
|
|
709
|
+
},
|
|
710
|
+
'list-style-image' : {
|
|
711
|
+
canOverride: canOverride.always,
|
|
712
|
+
defaultValue: 'none'
|
|
713
|
+
},
|
|
714
|
+
// outline ------------------------------------------------------------------------------
|
|
715
|
+
'outline': {
|
|
716
|
+
components: [
|
|
717
|
+
'outline-color',
|
|
718
|
+
'outline-style',
|
|
719
|
+
'outline-width'
|
|
720
|
+
],
|
|
721
|
+
breakUp: breakUp.outline,
|
|
722
|
+
putTogether: putTogether.takeCareOfInherit(putTogether.bySpacesOmitDefaults),
|
|
723
|
+
defaultValue: '0'
|
|
724
|
+
},
|
|
725
|
+
'outline-color': {
|
|
726
|
+
canOverride: canOverride.color,
|
|
727
|
+
defaultValue: 'invert',
|
|
728
|
+
shortestValue: 'red'
|
|
729
|
+
},
|
|
730
|
+
'outline-style': {
|
|
731
|
+
canOverride: canOverride.always,
|
|
732
|
+
defaultValue: 'none'
|
|
733
|
+
},
|
|
734
|
+
'outline-width': {
|
|
735
|
+
canOverride: canOverride.unit,
|
|
736
|
+
defaultValue: 'medium',
|
|
737
|
+
shortestValue: '0'
|
|
738
|
+
},
|
|
739
|
+
// transform
|
|
740
|
+
'-moz-transform': {
|
|
741
|
+
canOverride: canOverride.sameFunctionOrValue
|
|
742
|
+
},
|
|
743
|
+
'-ms-transform': {
|
|
744
|
+
canOverride: canOverride.sameFunctionOrValue
|
|
745
|
+
},
|
|
746
|
+
'-webkit-transform': {
|
|
747
|
+
canOverride: canOverride.sameFunctionOrValue
|
|
748
|
+
},
|
|
749
|
+
'transform': {
|
|
750
|
+
canOverride: canOverride.sameFunctionOrValue
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
var addFourValueShorthand = function (prop, components, options) {
|
|
755
|
+
options = options || {};
|
|
756
|
+
processable[prop] = {
|
|
757
|
+
components: components,
|
|
758
|
+
breakUp: options.breakUp || breakUp.fourBySpaces,
|
|
759
|
+
putTogether: options.putTogether || putTogether.takeCareOfInherit(putTogether.fourUnits),
|
|
760
|
+
defaultValue: options.defaultValue || '0',
|
|
761
|
+
shortestValue: options.shortestValue
|
|
762
|
+
};
|
|
763
|
+
for (var i = 0; i < components.length; i++) {
|
|
764
|
+
processable[components[i]] = {
|
|
765
|
+
breakUp: options.breakUp || breakUp.fourBySpaces,
|
|
766
|
+
canOverride: options.canOverride || canOverride.unit,
|
|
767
|
+
defaultValue: options.defaultValue || '0',
|
|
768
|
+
shortestValue: options.shortestValue
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
['', '-moz-', '-o-', '-webkit-'].forEach(function (prefix) {
|
|
774
|
+
addFourValueShorthand(prefix + 'border-radius', [
|
|
775
|
+
prefix + 'border-top-left-radius',
|
|
776
|
+
prefix + 'border-top-right-radius',
|
|
777
|
+
prefix + 'border-bottom-right-radius',
|
|
778
|
+
prefix + 'border-bottom-left-radius'
|
|
779
|
+
], {
|
|
780
|
+
breakUp: breakUp.borderRadius,
|
|
781
|
+
putTogether: putTogether.borderRadius
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
addFourValueShorthand('border-color', [
|
|
786
|
+
'border-top-color',
|
|
787
|
+
'border-right-color',
|
|
788
|
+
'border-bottom-color',
|
|
789
|
+
'border-left-color'
|
|
790
|
+
], {
|
|
791
|
+
breakUp: breakUp.fourBySpaces,
|
|
792
|
+
canOverride: canOverride.color,
|
|
793
|
+
defaultValue: 'currentColor',
|
|
794
|
+
shortestValue: 'red'
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
addFourValueShorthand('border-style', [
|
|
798
|
+
'border-top-style',
|
|
799
|
+
'border-right-style',
|
|
800
|
+
'border-bottom-style',
|
|
801
|
+
'border-left-style'
|
|
802
|
+
], {
|
|
803
|
+
breakUp: breakUp.fourBySpaces,
|
|
804
|
+
canOverride: canOverride.always,
|
|
805
|
+
defaultValue: 'none'
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
addFourValueShorthand('border-width', [
|
|
809
|
+
'border-top-width',
|
|
810
|
+
'border-right-width',
|
|
811
|
+
'border-bottom-width',
|
|
812
|
+
'border-left-width'
|
|
813
|
+
], {
|
|
814
|
+
defaultValue: 'medium',
|
|
815
|
+
shortestValue: '0'
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
addFourValueShorthand('padding', [
|
|
819
|
+
'padding-top',
|
|
820
|
+
'padding-right',
|
|
821
|
+
'padding-bottom',
|
|
822
|
+
'padding-left'
|
|
823
|
+
]);
|
|
824
|
+
|
|
825
|
+
addFourValueShorthand('margin', [
|
|
826
|
+
'margin-top',
|
|
827
|
+
'margin-right',
|
|
828
|
+
'margin-bottom',
|
|
829
|
+
'margin-left'
|
|
830
|
+
]);
|
|
831
|
+
|
|
832
|
+
// Set some stuff iteratively
|
|
833
|
+
for (var proc in processable) {
|
|
834
|
+
if (!processable.hasOwnProperty(proc))
|
|
835
|
+
continue;
|
|
836
|
+
|
|
837
|
+
var currDesc = processable[proc];
|
|
838
|
+
|
|
839
|
+
if (!(currDesc.components instanceof Array) || currDesc.components.length === 0)
|
|
840
|
+
continue;
|
|
841
|
+
|
|
842
|
+
currDesc.isShorthand = true;
|
|
843
|
+
|
|
844
|
+
for (var cI = 0; cI < currDesc.components.length; cI++) {
|
|
845
|
+
if (!processable[currDesc.components[cI]]) {
|
|
846
|
+
throw new Error('"' + currDesc.components[cI] + '" is defined as a component of "' + proc + '" but isn\'t defined in processable.');
|
|
847
|
+
}
|
|
848
|
+
processable[currDesc.components[cI]].componentOf = proc;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
var Token = tokenModule.createTokenPrototype(processable);
|
|
853
|
+
|
|
854
|
+
return {
|
|
855
|
+
implementedFor: /background|border|color|list|margin|outline|padding|transform/,
|
|
856
|
+
processable: processable,
|
|
857
|
+
Token: Token
|
|
858
|
+
};
|
|
859
|
+
})();
|