var wrapSingle = require('./wrap-for-optimizing').single;
var Splitter = require('../utils/splitter');
+var MULTIPLEX_SEPARATOR = ',';
function _colorFilter(validator) {
return function (value) {
}
if (clipSet && !originSet)
- origin.value = clip.value;
+ origin.value = clip.value.slice(0);
return components;
}
remainder.components = fourValues(remainder, compactable);
for (var j = 0; j < 4; j++) {
- target.components[j].value = [target.components[j].value, remainder.components[j].value];
+ target.components[j].multiplex = true;
+ target.components[j].value = target.components[j].value.concat([['/']]).concat(remainder.components[j].value);
}
return target.components;
return components;
}
-function multipleValues(splitWith) {
+function multiplex(splitWith) {
return function (property, compactable, validator) {
var splitsAt = [];
var values = property.value;
// group component values from each split
for (i = 0, l = components.length; i < l; i++) {
- components[i].value = [components[i].value];
components[i].multiplex = true;
for (j = 1, m = splitComponents.length; j < m; j++) {
- components[i].value.push(splitComponents[j][i].value);
+ components[i].value.push([MULTIPLEX_SEPARATOR]);
+ Array.prototype.push.apply(components[i].value, splitComponents[j][i].value);
}
}
borderRadius: borderRadius,
fourValues: fourValues,
listStyle: listStyle,
- multipleValues: multipleValues,
+ multiplex: multiplex,
outline: widthStyleColor
};
var cloned = shallow(property);
for (var i = property.components.length - 1; i >= 0; i--) {
var component = shallow(property.components[i]);
- component.value = property.components[i].value;
+ component.value = property.components[i].value.slice(0);
cloned.components.unshift(component);
}
cloned.dirty = true;
- cloned.value = property.value;
+ cloned.value = property.value.slice(0);
return cloned;
}
'background-clip',
'background-color'
],
- breakUp: breakUp.multipleValues(breakUp.background),
+ breakUp: breakUp.multiplex(breakUp.background),
defaultValue: '0 0',
- restore: restore.multipleValues(restore.background),
+ restore: restore.multiplex(restore.background),
shortestValue: '0',
shorthand: true
},
function overrideIntoMultiplex(property, by) {
by.unused = true;
- for (var i = 0, l = property.value.length; i < l; i++) {
- property.value[i] = by.value;
- }
+ turnIntoMultiplex(by, multiplexSize(property));
+ property.value = by.value;
}
function overrideByMultiplex(property, by) {
- // FIXME: we store component multiplex values and normal multiplex property values' differently
- // e.g [[['no-repeat']], [['no-repeat']]]
- // vs
- // [['no-repeat'], [','], ['no-repeat']]
- // We should rather use the latter as it's the standard way
-
by.unused = true;
- property.value = [];
-
- for (var i = 0, propertyIndex = 0, l = by.value.length; i < l; i++) {
- if (by.value[i] == MULTIPLEX_SEPARATOR) {
- propertyIndex++;
- continue;
- }
-
- property.value[propertyIndex] = property.value[propertyIndex] || [];
- property.value[propertyIndex].push(by.value[i]);
- }
+ property.multiplex = true;
+ property.value = by.value;
}
function overrideSimple(property, by) {
for (var i = 0, l = property.components.length; i < l; i++) {
var component = property.components[i];
- var value = component.value;
- component.value = [];
+ if (component.multiplex)
+ continue;
+
+ var value = component.value.slice(0);
- for (var j = 0; j < size; j++) {
- component.value.push(value);
+ for (var j = 1; j < size; j++) {
+ component.value.push([MULTIPLEX_SEPARATOR]);
+ Array.prototype.push.apply(component.value, value);
}
}
}
var size = 0;
for (var i = 0, l = component.value.length; i < l; i++) {
- if (component.value[i] == MULTIPLEX_SEPARATOR)
+ if (component.value[i][0] == MULTIPLEX_SEPARATOR)
size++;
}
property.components = descriptor.breakUp(property, compactable, validator);
if (property.components.length > 0)
- property.multiplex = Array.isArray(property.components[0].value[0][0]);
+ property.multiplex = property.components[0].multiplex;
else
property.unused = true;
}
var shallowClone = require('./clone').shallow;
+var MULTIPLEX_SEPARATOR = ',';
function background(property, compactable, lastInMultiplex) {
var components = property.components;
var component = property.components[i];
var horizontalComponent = shallowClone(property);
- horizontalComponent.value = component.value[0];
+ horizontalComponent.value = [component.value[0]];
horizontal.components.push(horizontalComponent);
var verticalComponent = shallowClone(property);
- verticalComponent.value = component.value[1];
+ verticalComponent.value = [component.value[2]];
vertical.components.push(verticalComponent);
}
}
}
-function multipleValues(restoreWith) {
+function multiplex(restoreWith) {
return function (property, compactable) {
if (!property.multiplex)
return restoreWith(property, compactable, true);
- var repeatCounts = property.components[0].value.length;
+ var multiplexSize = 0;
var restored = [];
+ var componentMultiplexSoFar = {};
+ var i, l;
- for (var i = 0; i < repeatCounts; i++) {
+ // At this point we don't know what's the multiplex size, e.g. how many background layers are there
+ for (i = 0, l = property.components[0].value.length; i < l; i++) {
+ if (property.components[0].value[i][0] == MULTIPLEX_SEPARATOR)
+ multiplexSize++;
+ }
+
+ for (i = 0; i <= multiplexSize; i++) {
var _property = shallowClone(property);
+ // We split multiplex into parts and restore them one by one
for (var j = 0, m = property.components.length; j < m; j++) {
- var _component = shallowClone(property.components[j]);
- _component.value = property.components[j].value[i];
+ var componentToClone = property.components[j];
+ var _component = shallowClone(componentToClone);
_property.components.push(_component);
+
+ // The trick is some properties has more than one value, so we iterate over values looking for
+ // a multiplex separator - a comma
+ for (var k = componentMultiplexSoFar[_component.name] || 0, n = componentToClone.value.length; k < n; k++) {
+ if (componentToClone.value[k][0] == MULTIPLEX_SEPARATOR) {
+ componentMultiplexSoFar[_component.name] = k + 1;
+ break;
+ }
+
+ _component.value.push(componentToClone.value[k]);
+ }
}
- var lastInMultiplex = i == repeatCounts - 1;
+ // No we can restore shorthand value
+ var lastInMultiplex = i == multiplexSize;
var _restored = restoreWith(_property, compactable, lastInMultiplex);
Array.prototype.push.apply(restored, _restored);
- if (i < repeatCounts - 1)
+ if (i < multiplexSize)
restored.push([',']);
}
background: background,
borderRadius: borderRadius,
fourValues: fourValues,
- multipleValues: multipleValues,
+ multiplex: multiplex,
withoutDefaults: withoutDefaults
};
},
'has border-top-left-radius': function (components) {
assert.equal(components[0].name, 'border-top-left-radius');
- assert.deepEqual(components[0].value, [[['0px']], [['1px']]]);
+ assert.deepEqual(components[0].value, [['0px'], ['/'], ['1px']]);
},
'has border-top-right-radius': function (components) {
assert.equal(components[1].name, 'border-top-right-radius');
- assert.deepEqual(components[1].value, [[['1px']], [['2px']]]);
+ assert.deepEqual(components[1].value, [['1px'], ['/'], ['2px']]);
},
'has border-bottom-right-radius': function (components) {
assert.equal(components[2].name, 'border-bottom-right-radius');
- assert.deepEqual(components[2].value, [[['2px']], [['3px']]]);
+ assert.deepEqual(components[2].value, [['2px'], ['/'], ['3px']]);
},
'has border-bottom-left': function (components) {
assert.equal(components[3].name, 'border-bottom-left-radius');
- assert.deepEqual(components[3].value, [[['3px']], [['4px']]]);
+ assert.deepEqual(components[3].value, [['3px'], ['/'], ['4px']]);
}
},
'vendor prefix asymetrical horizontal vertical split': {
},
'has border-top-left-radius': function (components) {
assert.equal(components[0].name, '-webkit-border-top-left-radius');
- assert.deepEqual(components[0].value, [[['0px']], [['1px']]]);
+ assert.deepEqual(components[0].value, [['0px'], ['/'], ['1px']]);
},
'has border-top-right-radius': function (components) {
assert.equal(components[1].name, '-webkit-border-top-right-radius');
- assert.deepEqual(components[1].value, [[['1px']], [['4px']]]);
+ assert.deepEqual(components[1].value, [['1px'], ['/'], ['4px']]);
},
'has border-bottom-right-radius': function (components) {
assert.equal(components[2].name, '-webkit-border-bottom-right-radius');
- assert.deepEqual(components[2].value, [[['2px']], [['1px']]]);
+ assert.deepEqual(components[2].value, [['2px'], ['/'], ['1px']]);
},
'has border-bottom-left': function (components) {
assert.equal(components[3].name, '-webkit-border-bottom-left-radius');
- assert.deepEqual(components[3].value, [[['1px']], [['4px']]]);
+ assert.deepEqual(components[3].value, [['1px'], ['/'], ['4px']]);
}
}
},
},
'has background-image': function (components) {
assert.deepEqual(components[0].name, 'background-image');
- assert.deepEqual(components[0].value, [[['__ESCAPED_URL_CLEAN_CSS0__']], [['url(image2.png)']]]);
+ assert.deepEqual(components[0].value, [['__ESCAPED_URL_CLEAN_CSS0__'], [','], ['url(image2.png)']]);
assert.isTrue(components[0].multiplex);
},
'has background-position': function (components) {
assert.deepEqual(components[1].name, 'background-position');
- assert.deepEqual(components[1].value, [[['0'], ['0']], [['2px'], ['3px']]]);
+ assert.deepEqual(components[1].value, [['0'], ['0'], [','], ['2px'], ['3px']]);
assert.isTrue(components[0].multiplex);
},
'has background-size': function (components) {
assert.deepEqual(components[2].name, 'background-size');
- assert.deepEqual(components[2].value, [[['auto']], [['50%'], ['60%']]]);
+ assert.deepEqual(components[2].value, [['auto'], [','], ['50%'], ['60%']]);
assert.isTrue(components[0].multiplex);
},
'has background-repeat': function (components) {
assert.deepEqual(components[3].name, 'background-repeat');
- assert.deepEqual(components[3].value, [[['repeat']], [['repeat'], ['no-repeat']]]);
+ assert.deepEqual(components[3].value, [['repeat'], [','], ['repeat'], ['no-repeat']]);
assert.isTrue(components[0].multiplex);
},
'has background-attachment': function (components) {
assert.deepEqual(components[4].name, 'background-attachment');
- assert.deepEqual(components[4].value, [[['scroll']], [['fixed']]]);
+ assert.deepEqual(components[4].value, [['scroll'], [','], ['fixed']]);
assert.isTrue(components[0].multiplex);
},
'has background-origin': function (components) {
assert.deepEqual(components[5].name, 'background-origin');
- assert.deepEqual(components[5].value, [[['padding-box']], [['content-box']]]);
+ assert.deepEqual(components[5].value, [['padding-box'], [','], ['content-box']]);
assert.isTrue(components[0].multiplex);
},
'has background-clip': function (components) {
assert.deepEqual(components[6].name, 'background-clip');
- assert.deepEqual(components[6].value, [[['border-box']], [['content-box']]]);
+ assert.deepEqual(components[6].value, [['border-box'], [','], ['content-box']]);
assert.isTrue(components[0].multiplex);
},
'has background-color': function (components) {
assert.deepEqual(components[7].name, 'background-color');
- assert.deepEqual(components[7].value, [[['#fff']], [['red']]]);
+ assert.deepEqual(components[7].value, [['#fff'], [','], ['red']]);
assert.isTrue(components[0].multiplex);
}
+ },
+ 'background - clip & origin': {
+ 'topic': function () {
+ return _breakUp([[['background'], ['__ESCAPED_URL_CLEAN_CSS0__'], ['no-repeat'], ['padding-box'], [','], ['repeat'], ['red']]]);
+ },
+ 'has background-origin': function (components) {
+ assert.deepEqual(components[5].value, [['padding-box'], [','], ['padding-box']]);
+ },
+ 'has background-clip': function (components) {
+ assert.deepEqual(components[6].value, [['padding-box'], [','], ['border-box']]);
+ }
}
},
'outline': {
var descriptor = compactable[property[0][0]];
var _property = wrapForOptimizing(property);
_property.components = descriptor.breakUp(_property, compactable, validator);
- _property.multiplex = Array.isArray(_property.components[0].value[0][0]);
+ _property.multiplex = _property.components[0].multiplex;
return _property;
}