123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- var shallowClone = require('./clone').shallow;
-
- var Token = require('../../tokenizer/token');
- var Marker = require('../../tokenizer/marker');
-
- function isInheritOnly(values) {
- for (var i = 0, l = values.length; i < l; i++) {
- var value = values[i][1];
-
- if (value != 'inherit' && value != Marker.COMMA && value != Marker.FORWARD_SLASH)
- return false;
- }
-
- return true;
- }
-
- function background(property, compactable, lastInMultiplex) {
- var components = property.components;
- var restored = [];
- var needsOne, needsBoth;
-
- function restoreValue(component) {
- Array.prototype.unshift.apply(restored, component.value);
- }
-
- function isDefaultValue(component) {
- var descriptor = compactable[component.name];
-
- if (descriptor.doubleValues && descriptor.defaultValue.length == 1) {
- return component.value[0][1] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][1] == descriptor.defaultValue[0] : true);
- } else if (descriptor.doubleValues && descriptor.defaultValue.length != 1) {
- return component.value[0][1] == descriptor.defaultValue[0] && (component.value[1] ? component.value[1][1] : component.value[0][1]) == descriptor.defaultValue[1];
- } else {
- return component.value[0][1] == descriptor.defaultValue;
- }
- }
-
- for (var i = components.length - 1; i >= 0; i--) {
- var component = components[i];
- var isDefault = isDefaultValue(component);
-
- if (component.name == 'background-clip') {
- var originComponent = components[i - 1];
- var isOriginDefault = isDefaultValue(originComponent);
-
- needsOne = component.value[0][1] == originComponent.value[0][1];
-
- needsBoth = !needsOne && (
- (isOriginDefault && !isDefault) ||
- (!isOriginDefault && !isDefault) ||
- (!isOriginDefault && isDefault && component.value[0][1] != originComponent.value[0][1]));
-
- if (needsOne) {
- restoreValue(originComponent);
- } else if (needsBoth) {
- restoreValue(component);
- restoreValue(originComponent);
- }
-
- i--;
- } else if (component.name == 'background-size') {
- var positionComponent = components[i - 1];
- var isPositionDefault = isDefaultValue(positionComponent);
-
- needsOne = !isPositionDefault && isDefault;
-
- needsBoth = !needsOne &&
- (isPositionDefault && !isDefault || !isPositionDefault && !isDefault);
-
- if (needsOne) {
- restoreValue(positionComponent);
- } else if (needsBoth) {
- restoreValue(component);
- restored.unshift([Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]);
- restoreValue(positionComponent);
- } else if (positionComponent.value.length == 1) {
- restoreValue(positionComponent);
- }
-
- i--;
- } else {
- if (isDefault || compactable[component.name].multiplexLastOnly && !lastInMultiplex)
- continue;
-
- restoreValue(component);
- }
- }
-
- if (restored.length === 0 && property.value.length == 1 && property.value[0][1] == '0')
- restored.push(property.value[0]);
-
- if (restored.length === 0)
- restored.push([Token.PROPERTY_VALUE, compactable[property.name].defaultValue]);
-
- if (isInheritOnly(restored))
- return [restored[0]];
-
- return restored;
- }
-
- function borderRadius(property, compactable) {
- if (property.multiplex) {
- var horizontal = shallowClone(property);
- var vertical = shallowClone(property);
-
- for (var i = 0; i < 4; i++) {
- var component = property.components[i];
-
- var horizontalComponent = shallowClone(property);
- horizontalComponent.value = [component.value[0]];
- horizontal.components.push(horizontalComponent);
-
- var verticalComponent = shallowClone(property);
- // FIXME: only shorthand compactor (see breakup#borderRadius) knows that border radius
- // longhands have two values, whereas tokenizer does not care about populating 2nd value
- // if it's missing, hence this fallback
- verticalComponent.value = [component.value[1] || component.value[0]];
- vertical.components.push(verticalComponent);
- }
-
- var horizontalValues = fourValues(horizontal, compactable);
- var verticalValues = fourValues(vertical, compactable);
-
- if (horizontalValues.length == verticalValues.length &&
- horizontalValues[0][1] == verticalValues[0][1] &&
- (horizontalValues.length > 1 ? horizontalValues[1][1] == verticalValues[1][1] : true) &&
- (horizontalValues.length > 2 ? horizontalValues[2][1] == verticalValues[2][1] : true) &&
- (horizontalValues.length > 3 ? horizontalValues[3][1] == verticalValues[3][1] : true)) {
- return horizontalValues;
- } else {
- return horizontalValues.concat([[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]).concat(verticalValues);
- }
- } else {
- return fourValues(property, compactable);
- }
- }
-
- function font(property, compactable) {
- var components = property.components;
- var restored = [];
- var component;
- var componentIndex = 0;
- var fontFamilyIndex = 0;
-
- if (property.value[0][1].indexOf(Marker.INTERNAL) === 0) {
- property.value[0][1] = property.value[0][1].substring(Marker.INTERNAL.length);
- return property.value;
- }
-
- // first four components are optional
- while (componentIndex < 4) {
- component = components[componentIndex];
-
- if (component.value[0][1] != compactable[component.name].defaultValue) {
- Array.prototype.push.apply(restored, component.value);
- }
-
- componentIndex++;
- }
-
- // then comes font-size
- Array.prototype.push.apply(restored, components[componentIndex].value);
- componentIndex++;
-
- // then may come line-height
- if (components[componentIndex].value[0][1] != compactable[components[componentIndex].name].defaultValue) {
- Array.prototype.push.apply(restored, [[Token.PROPERTY_VALUE, Marker.FORWARD_SLASH]]);
- Array.prototype.push.apply(restored, components[componentIndex].value);
- }
-
- componentIndex++;
-
- // then comes font-family
- while (components[componentIndex].value[fontFamilyIndex]) {
- restored.push(components[componentIndex].value[fontFamilyIndex]);
-
- if (components[componentIndex].value[fontFamilyIndex + 1]) {
- restored.push([Token.PROPERTY_VALUE, Marker.COMMA]);
- }
-
- fontFamilyIndex++;
- }
-
- if (isInheritOnly(restored)) {
- return [restored[0]];
- }
-
- return restored;
- }
-
- function fourValues(property) {
- var components = property.components;
- var value1 = components[0].value[0];
- var value2 = components[1].value[0];
- var value3 = components[2].value[0];
- var value4 = components[3].value[0];
-
- if (value1[1] == value2[1] && value1[1] == value3[1] && value1[1] == value4[1]) {
- return [value1];
- } else if (value1[1] == value3[1] && value2[1] == value4[1]) {
- return [value1, value2];
- } else if (value2[1] == value4[1]) {
- return [value1, value2, value3];
- } else {
- return [value1, value2, value3, value4];
- }
- }
-
- function multiplex(restoreWith) {
- return function (property, compactable) {
- if (!property.multiplex)
- return restoreWith(property, compactable, true);
-
- var multiplexSize = 0;
- var restored = [];
- var componentMultiplexSoFar = {};
- var i, l;
-
- // 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][1] == Marker.COMMA)
- 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 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][1] == Marker.COMMA) {
- componentMultiplexSoFar[_component.name] = k + 1;
- break;
- }
-
- _component.value.push(componentToClone.value[k]);
- }
- }
-
- // No we can restore shorthand value
- var lastInMultiplex = i == multiplexSize;
- var _restored = restoreWith(_property, compactable, lastInMultiplex);
- Array.prototype.push.apply(restored, _restored);
-
- if (i < multiplexSize)
- restored.push([Token.PROPERTY_VALUE, Marker.COMMA]);
- }
-
- return restored;
- };
- }
-
- function withoutDefaults(property, compactable) {
- var components = property.components;
- var restored = [];
-
- for (var i = components.length - 1; i >= 0; i--) {
- var component = components[i];
- var descriptor = compactable[component.name];
-
- if (component.value[0][1] != descriptor.defaultValue || ('keepUnlessDefault' in descriptor) && !isDefault(components, compactable, descriptor.keepUnlessDefault)) {
- restored.unshift(component.value[0]);
- }
- }
-
- if (restored.length === 0)
- restored.push([Token.PROPERTY_VALUE, compactable[property.name].defaultValue]);
-
- if (isInheritOnly(restored))
- return [restored[0]];
-
- return restored;
- }
-
- function isDefault(components, compactable, propertyName) {
- var component;
- var i, l;
-
- for (i = 0, l = components.length; i < l; i++) {
- component = components[i];
-
- if (component.name == propertyName && component.value[0][1] == compactable[propertyName].defaultValue) {
- return true;
- }
- }
-
- return false;
- }
-
- module.exports = {
- background: background,
- borderRadius: borderRadius,
- font: font,
- fourValues: fourValues,
- multiplex: multiplex,
- withoutDefaults: withoutDefaults
- };
|