You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							303 lines
						
					
					
						
							9.6 KiB
						
					
					
				
			
		
		
	
	
							303 lines
						
					
					
						
							9.6 KiB
						
					
					
				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 | 
						|
};
 | 
						|
 |