canOverride = Object.freeze(canOverride);
// Functions for breaking up shorthands to components
- var breakUp = {
- // Use this for properties with 4 unit values (like margin or padding)
- // NOTE: it handles shorter forms of these properties too (like, only 1, 2, or 3 units)
- fourUnits: function (token) {
+ var breakUp = {};
+ breakUp.takeCareOfFourValues = function (splitfunc) {
+ return function (token) {
var descriptor = processable[token.prop];
var result = [];
- var splitval = token.value.match(new RegExp(validator.cssUnitAnyRegexStr, 'gi'));
+ var splitval = splitfunc(token.value);
if (splitval.length === 0 || (splitval.length < descriptor.components.length && descriptor.components.length > 4)) {
// This token is malformed and we have no idea how to fix it. So let's just keep it intact
}
return result;
- },
- // Breaks up a background property value
- background: function (token) {
- // Default values
- var result = Token.makeDefaults(['background-color', 'background-image', 'background-repeat', 'background-position', 'background-attachment'], token.isImportant);
- var color = result[0], image = result[1], repeat = result[2], position = result[3], attachment = result[4];
-
- // Take care of inherit
- if (token.value === 'inherit') {
- // NOTE: 'inherit' is not a valid value for background-attachment so there we'll leave the default value
- color.value = image.value = repeat.value = position.value = attachment.value = 'inherit';
- return result;
+ };
+ };
+ // Use this for properties with 4 unit values (like margin or padding)
+ // NOTE: it handles shorter forms of these properties too (like, only 1, 2, or 3 units)
+ breakUp.fourUnits = breakUp.takeCareOfFourValues(function (val) {
+ return val.match(new RegExp(validator.cssUnitAnyRegexStr, 'gi'));
+ });
+ // Use this when you simply want to break up four values along spaces
+ breakUp.fourBySpaces = breakUp.takeCareOfFourValues(function (val) {
+ return val.split(' ').filter(function (v) { return v; });
+ });
+ // Use this for non-length values that can also contain functions
+ breakUp.fourBySpacesOrFunctions = breakUp.takeCareOfFourValues(function (val) {
+ var result = [];
+ var curr = '';
+ var parenthesisLevel = 0;
+
+ for (var i = 0; i < val.length; i++) {
+ var c = val[i];
+ curr += c;
+
+ if (c === '(') {
+ parenthesisLevel++;
+ }
+ else if (c === ')') {
+ parenthesisLevel--;
+ if (parenthesisLevel === 0) {
+ result.push(curr.trim());
+ curr = '';
+ }
}
-
- // Break the background up into parts
- var parts = token.value.split(' ');
- if (parts.length === 0) {
- return result;
+ else if (c === ' ' && parenthesisLevel === 0) {
+ result.push(curr.trim());
+ curr = '';
}
+ }
- // The trick here is that we start going through the parts from the end, then stop after background repeat,
- // then start from the from the beginning until we find a valid color value. What remains will be treated as background-image.
-
- var currentIndex = parts.length - 1;
- var current = parts[currentIndex];
- // Attachment
- if (validator.isValidBackgroundAttachment(current)) {
- // Found attachment
- attachment.value = current;
- currentIndex--;
- current = parts[currentIndex];
- }
- // Position
- var pos = parts[currentIndex - 1] + ' ' + parts[currentIndex];
- if (currentIndex >= 1 && validator.isValidBackgroundPosition(pos)) {
- // Found position (containing two parts)
- position.value = pos;
- currentIndex -= 2;
- current = parts[currentIndex];
- }
- else if (currentIndex >= 0 && validator.isValidBackgroundPosition(current)) {
- // Found position (containing just one part)
- position.value = current;
- currentIndex--;
- current = parts[currentIndex];
- }
- // Repeat
- if (currentIndex >= 0 && validator.isValidBackgroundRepeat(current)) {
- // Found repeat
- repeat.value = current;
- currentIndex--;
- current = parts[currentIndex];
- }
- // Color
- var fromBeginning = 0;
- if (validator.isValidColor(parts[0])) {
- // Found color
- color.value = parts[0];
- fromBeginning = 1;
- }
- // Image
- image.value = (parts.splice(fromBeginning, currentIndex - fromBeginning + 1).join(' ')) || 'none';
+ if (curr) {
+ result.push(curr.trim());
+ curr = '';
+ }
+ return result;
+ });
+ // Breaks up a background property value
+ breakUp.background = function (token) {
+ // Default values
+ var result = Token.makeDefaults(['background-color', 'background-image', 'background-repeat', 'background-position', 'background-attachment'], token.isImportant);
+ var color = result[0], image = result[1], repeat = result[2], position = result[3], attachment = result[4];
+
+ // Take care of inherit
+ if (token.value === 'inherit') {
+ // NOTE: 'inherit' is not a valid value for background-attachment so there we'll leave the default value
+ color.value = image.value = repeat.value = position.value = attachment.value = 'inherit';
return result;
- },
- // Breaks up a list-style property value
- listStyle: function (token) {
- // Default values
- var result = Token.makeDefaults(['list-style-type', 'list-style-position', 'list-style-image'], token.isImportant);
- var type = result[0], position = result[1], image = result[2];
-
- if (token.value === 'inherit') {
- type.value = position.value = image.value = 'inherit';
- return result;
- }
+ }
- var parts = token.value.split(' ');
- var ci = 0;
+ // Break the background up into parts
+ var parts = token.value.split(' ');
+ if (parts.length === 0) {
+ return result;
+ }
- // Type
- if (ci < parts.length && validator.isValidListStyleType(parts[ci])) {
- type.value = parts[ci];
- ci++;
- }
- // Position
- if (ci < parts.length && validator.isValidListStylePosition(parts[ci])) {
- position.value = parts[ci];
- ci++;
- }
- // Image
- if (ci < parts.length) {
- image.value = parts.splice(ci, parts.length - ci + 1).join(' ');
- }
+ // The trick here is that we start going through the parts from the end, then stop after background repeat,
+ // then start from the from the beginning until we find a valid color value. What remains will be treated as background-image.
+
+ var currentIndex = parts.length - 1;
+ var current = parts[currentIndex];
+ // Attachment
+ if (validator.isValidBackgroundAttachment(current)) {
+ // Found attachment
+ attachment.value = current;
+ currentIndex--;
+ current = parts[currentIndex];
+ }
+ // Position
+ var pos = parts[currentIndex - 1] + ' ' + parts[currentIndex];
+ if (currentIndex >= 1 && validator.isValidBackgroundPosition(pos)) {
+ // Found position (containing two parts)
+ position.value = pos;
+ currentIndex -= 2;
+ current = parts[currentIndex];
+ }
+ else if (currentIndex >= 0 && validator.isValidBackgroundPosition(current)) {
+ // Found position (containing just one part)
+ position.value = current;
+ currentIndex--;
+ current = parts[currentIndex];
+ }
+ // Repeat
+ if (currentIndex >= 0 && validator.isValidBackgroundRepeat(current)) {
+ // Found repeat
+ repeat.value = current;
+ currentIndex--;
+ current = parts[currentIndex];
+ }
+ // Color
+ var fromBeginning = 0;
+ if (validator.isValidColor(parts[0])) {
+ // Found color
+ color.value = parts[0];
+ fromBeginning = 1;
+ }
+ // Image
+ image.value = (parts.splice(fromBeginning, currentIndex - fromBeginning + 1).join(' ')) || 'none';
+ return result;
+ };
+ // Breaks up a list-style property value
+ breakUp.listStyle = function (token) {
+ // Default values
+ var result = Token.makeDefaults(['list-style-type', 'list-style-position', 'list-style-image'], token.isImportant);
+ var type = result[0], position = result[1], image = result[2];
+
+ if (token.value === 'inherit') {
+ type.value = position.value = image.value = 'inherit';
return result;
- },
- // Breaks up outline
- outline: function (token) {
- // Default values
- var result = Token.makeDefaults(['outline-color', 'outline-style', 'outline-width'], token.isImportant);
- var color = result[0], style = result[1], width = result[2];
-
- // Take care of inherit
- if (token.value === 'inherit' || token.value === 'inherit inherit inherit') {
- color.value = style.value = width.value = 'inherit';
- return result;
- }
+ }
- // NOTE: usually users don't follow the required order of parts in this shorthand,
- // so we'll try to parse it caring as little about order as possible
+ var parts = token.value.split(' ');
+ var ci = 0;
- var parts = token.value.split(' '), w;
+ // Type
+ if (ci < parts.length && validator.isValidListStyleType(parts[ci])) {
+ type.value = parts[ci];
+ ci++;
+ }
+ // Position
+ if (ci < parts.length && validator.isValidListStylePosition(parts[ci])) {
+ position.value = parts[ci];
+ ci++;
+ }
+ // Image
+ if (ci < parts.length) {
+ image.value = parts.splice(ci, parts.length - ci + 1).join(' ');
+ }
- if (parts.length === 0) {
- return result;
- }
+ return result;
+ };
+ // Breaks up outline
+ breakUp.outline = function (token) {
+ // Default values
+ var result = Token.makeDefaults(['outline-color', 'outline-style', 'outline-width'], token.isImportant);
+ var color = result[0], style = result[1], width = result[2];
+
+ // Take care of inherit
+ if (token.value === 'inherit' || token.value === 'inherit inherit inherit') {
+ color.value = style.value = width.value = 'inherit';
+ return result;
+ }
- if (parts.length >= 1) {
- // Try to find outline-width, excluding inherit because that can be anything
- w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineWidth(p); });
- if (w.length) {
- width.value = w[0];
- parts.splice(parts.indexOf(w[0]), 1);
- }
+ // NOTE: usually users don't follow the required order of parts in this shorthand,
+ // so we'll try to parse it caring as little about order as possible
+
+ var parts = token.value.split(' '), w;
+
+ if (parts.length === 0) {
+ return result;
+ }
+
+ if (parts.length >= 1) {
+ // Try to find outline-width, excluding inherit because that can be anything
+ w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineWidth(p); });
+ if (w.length) {
+ width.value = w[0];
+ parts.splice(parts.indexOf(w[0]), 1);
}
- if (parts.length >= 1) {
- // Try to find outline-style, excluding inherit because that can be anything
- w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineStyle(p); });
- if (w.length) {
- style.value = w[0];
- parts.splice(parts.indexOf(w[0]), 1);
- }
+ }
+ if (parts.length >= 1) {
+ // Try to find outline-style, excluding inherit because that can be anything
+ w = parts.filter(function(p) { return p !== 'inherit' && validator.isValidOutlineStyle(p); });
+ if (w.length) {
+ style.value = w[0];
+ parts.splice(parts.indexOf(w[0]), 1);
}
- if (parts.length >= 1) {
- // Find outline-color but this time can catch inherit
- w = parts.filter(function(p) { return validator.isValidOutlineColor(p); });
- if (w.length) {
- color.value = w[0];
- parts.splice(parts.indexOf(w[0]), 1);
- }
+ }
+ if (parts.length >= 1) {
+ // Find outline-color but this time can catch inherit
+ w = parts.filter(function(p) { return validator.isValidOutlineColor(p); });
+ if (w.length) {
+ color.value = w[0];
+ parts.splice(parts.indexOf(w[0]), 1);
}
-
- return result;
}
+
+ return result;
};
// Contains functions that can put together shorthands from their components
// Puts the shorthand together from its components.
//
var processable = {
- 'margin': {
- components: [
- 'margin-top',
- 'margin-right',
- 'margin-bottom',
- 'margin-left'
- ],
- breakUp: breakUp.fourUnits,
- putTogether: putTogether.takeCareOfInherit(putTogether.fourUnits),
- defaultValue: '0'
- },
- 'margin-top': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'margin-right': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'margin-bottom': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'margin-left': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'padding': {
- components: [
- 'padding-top',
- 'padding-right',
- 'padding-bottom',
- 'padding-left'
- ],
- breakUp: breakUp.fourUnits,
- putTogether: putTogether.takeCareOfInherit(putTogether.fourUnits),
- defaultValue: '0'
- },
- 'padding-top': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'padding-right': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'padding-bottom': {
- defaultValue: '0',
- canOverride: canOverride.unit
- },
- 'padding-left': {
- defaultValue: '0',
- canOverride: canOverride.unit
+ 'color': {
+ canOverride: canOverride.color,
+ defaultValue: 'transparent',
+ shortestValue: 'red'
},
+ // background ------------------------------------------------------------------------------
'background': {
components: [
'background-color',
defaultValue: '0 0',
shortestValue: '0'
},
- 'color': {
- canOverride: canOverride.color,
- defaultValue: 'transparent',
- shortestValue: 'red'
- },
'background-color': {
canOverride: canOverride.color,
defaultValue: 'transparent',
canOverride: canOverride.always,
defaultValue: 'scroll'
},
+ // list-style ------------------------------------------------------------------------------
'list-style': {
components: [
'list-style-type',
canOverride: canOverride.always,
defaultValue: 'none'
},
+ // outline ------------------------------------------------------------------------------
'outline': {
components: [
'outline-color',
defaultValue: 'medium',
shortestValue: '0'
}
- // TODO: add more
};
+ var addFourValueShorthand = function (prop, components, breakup, puttogether, canoverride, defaultValue, shortestValue) {
+ processable[prop] = {
+ components: components,
+ breakUp: breakup || breakUp.fourUnits,
+ putTogether: puttogether || putTogether.takeCareOfInherit(putTogether.fourUnits),
+ defaultValue: defaultValue || '0',
+ shortestValue: shortestValue
+ };
+ for (var i = 0; i < components.length; i++) {
+ processable[components[i]] = {
+ canOverride: canoverride || canOverride.unit,
+ defaultValue: defaultValue || '0',
+ shortestValue: shortestValue
+ };
+ }
+ };
+
+ addFourValueShorthand('border-radius', [
+ 'border-top-left-radius',
+ 'border-top-right-radius',
+ 'border-bottom-right-radius',
+ 'border-bottom-left-radius'
+ ]);
+
+ addFourValueShorthand('-moz-border-radius', [
+ '-moz-border-top-left-radius',
+ '-moz-border-top-right-radius',
+ '-moz-border-bottom-right-radius',
+ '-moz-border-bottom-left-radius'
+ ]);
+
+ addFourValueShorthand('-webkit-border-radius', [
+ '-webkit-border-top-left-radius',
+ '-webkit-border-top-right-radius',
+ '-webkit-border-bottom-right-radius',
+ '-webkit-border-bottom-left-radius'
+ ]);
+
+ addFourValueShorthand('-o-border-radius', [
+ '-o-border-top-left-radius',
+ '-o-border-top-right-radius',
+ '-o-border-bottom-right-radius',
+ '-o-border-bottom-left-radius'
+ ]);
+
+ addFourValueShorthand('border-color', [
+ 'border-top-color',
+ 'border-right-color',
+ 'border-bottom-color',
+ 'border-left-color'
+ ], breakUp.fourBySpacesOrFunctions, null, canOverride.color, 'currentColor', 'red');
+
+ addFourValueShorthand('border-style', [
+ 'border-top-style',
+ 'border-right-style',
+ 'border-bottom-style',
+ 'border-left-style'
+ ], breakUp.fourBySpaces, null, canOverride.always, 'none');
+
+ addFourValueShorthand('border-width', [
+ 'border-top-width',
+ 'border-right-width',
+ 'border-bottom-width',
+ 'border-left-width'
+ ], null, null, null, 'medium', '0');
+
+ addFourValueShorthand('padding', [
+ 'padding-top',
+ 'padding-right',
+ 'padding-bottom',
+ 'padding-left'
+ ]);
+
+ addFourValueShorthand('margin', [
+ 'margin-top',
+ 'margin-right',
+ 'margin-bottom',
+ 'margin-left'
+ ]);
+
// Set some stuff iteratively
for (var proc in processable) {
if (processable.hasOwnProperty(proc)) {