Fixes #322 - adds background-size support to advanced optimizer.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 27 Jul 2014 12:42:08 +0000 (13:42 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Sun, 27 Jul 2014 13:31:22 +0000 (14:31 +0100)
History.md
lib/properties/processable.js
lib/properties/validator.js
test/data/issue-312-min.css
test/unit-test.js

index c53d533..3f921a2 100644 (file)
@@ -3,6 +3,7 @@
 
 * Improved performance of advanced mode validators.
 * Fixed issue [#307](https://github.com/GoalSmashers/clean-css/issues/307) - background-color in muliple backgrounds.
+* Fixed issue [#322](https://github.com/GoalSmashers/clean-css/issues/322) - adds background-size support.
 * Fixed issue [#323](https://github.com/GoalSmashers/clean-css/issues/323) - stripping variable references.
 * Fixed issue [#325](https://github.com/GoalSmashers/clean-css/issues/325) - removing invalid @charset declarations.
 
index bea5076..9d3e0ae 100644 (file)
@@ -163,17 +163,18 @@ module.exports = (function () {
   };
   breakUp.background = function (token) {
     // Default values
-    var result = Token.makeDefaults(['background-image', 'background-position', 'background-repeat', 'background-attachment', 'background-color'], token.isImportant);
+    var result = Token.makeDefaults(['background-image', 'background-position', 'background-size', 'background-repeat', 'background-attachment', 'background-color'], token.isImportant);
     var image = result[0];
     var position = result[1];
-    var repeat = result[2];
-    var attachment = result[3];
-    var color = result[4];
+    var size = result[2];
+    var repeat = result[3];
+    var attachment = result[4];
+    var color = result[5];
 
     // 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';
+      color.value = image.value =  repeat.value = position.value = size.value = attachment.value = 'inherit';
       return result;
     }
 
@@ -190,18 +191,32 @@ module.exports = (function () {
         attachment.value = currentPart;
       } else if (validator.isValidBackgroundRepeat(currentPart)) {
         repeat.value = currentPart;
-      } else if (validator.isValidBackgroundPosition(currentPart)) {
+      } else if (validator.isValidBackgroundPositionPart(currentPart) || validator.isValidBackgroundSizePart(currentPart)) {
         if (i > 0) {
-          var repeatedPosition = parts[i - 1] + ' ' + currentPart;
-          if (validator.isValidBackgroundPosition(repeatedPosition)) {
+          var previousPart = parts[i - 1];
+
+          if (previousPart.indexOf('/') > 0) {
+            var twoParts = new Splitter('/').split(previousPart);
+            size.value = twoParts.pop() + ' ' + currentPart;
+            parts[i - 1] = twoParts.pop();
+          } else if (i > 1 && parts[i - 2] == '/') {
+            size.value = previousPart + ' ' + currentPart;
+            i -= 2;
+          } else if (parts[i - 1] == '/') {
+            size.value = currentPart;
+            position.value = previousPart;
             i--;
-            position.value = repeatedPosition;
           } else {
-            position.value = currentPart;
+            position.value = previousPart + ' ' + currentPart;
+            i--;
           }
         } else {
           position.value = currentPart;
         }
+      } else if (validator.isValidBackgroundPositionAndSize(currentPart)) {
+        var sizeValue = new Splitter('/').split(currentPart);
+        size.value = sizeValue.pop();
+        position.value = sizeValue.pop();
       } else if (validator.isValidColor(currentPart)) {
         color.value = currentPart;
       } else if (validator.isValidUrl(currentPart) || validator.isValidFunction(currentPart)) {
@@ -429,7 +444,7 @@ module.exports = (function () {
         if (meta && meta.partsCount && meta.position < meta.partsCount - 1 && processable[token.prop].multiValueLastOnly)
           continue;
 
-        result.value += ' ' + token.value;
+        result.value += (processable[token.prop].prefixShorthandValueWith || ' ') + token.value;
       }
 
       result.value = result.value.trim();
@@ -596,6 +611,7 @@ module.exports = (function () {
       components: [
         'background-image',
         'background-position',
+        'background-size',
         'background-repeat',
         'background-attachment',
         'background-color'
@@ -626,6 +642,12 @@ module.exports = (function () {
       defaultValue: '0 0',
       shortestValue: '0'
     },
+    'background-size': {
+      canOverride: canOverride.always,
+      defaultValue: 'auto',
+      shortestValue: '0 0',
+      prefixShorthandValueWith: '/'
+    },
     'background-attachment': {
       canOverride: canOverride.always,
       defaultValue: 'scroll'
index 71149e0..be77c36 100644 (file)
@@ -1,6 +1,8 @@
 
 // Validates various CSS property values
 
+var Splitter = require('../text/splitter');
+
 module.exports = (function () {
   // Regexes used for stuff
   var widthKeywords = ['thin', 'thick', 'medium', 'inherit', 'initial'];
@@ -21,6 +23,7 @@ module.exports = (function () {
   var backgroundRepeatKeywords = ['repeat', 'no-repeat', 'repeat-x', 'repeat-y', 'inherit'];
   var backgroundAttachmentKeywords = ['inherit', 'scroll', 'fixed', 'local'];
   var backgroundPositionKeywords = ['center', 'top', 'bottom', 'left', 'right'];
+  var backgroundSizeKeywords = ['contain', 'cover'];
   var listStyleTypeKeywords = ['armenian', 'circle', 'cjk-ideographic', 'decimal', 'decimal-leading-zero', 'disc', 'georgian', 'hebrew', 'hiragana', 'hiragana-iroha', 'inherit', 'katakana', 'katakana-iroha', 'lower-alpha', 'lower-greek', 'lower-latin', 'lower-roman', 'none', 'square', 'upper-alpha', 'upper-latin', 'upper-roman'];
   var listStylePositionKeywords = ['inside', 'outside', 'inherit'];
   var outlineStyleKeywords = ['auto', 'inherit', 'hidden', 'none', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset'];
@@ -94,6 +97,16 @@ module.exports = (function () {
 
       return true;
     },
+    isValidBackgroundSizePart: function(s) {
+      return backgroundSizeKeywords.indexOf(s) >= 0 || cssUnitRegex.test(s) || validator.isValidVariable(s);
+    },
+    isValidBackgroundPositionAndSize: function(s) {
+      if (s.indexOf('/') < 0)
+        return false;
+
+      var twoParts = new Splitter('/').split(s);
+      return validator.isValidBackgroundSizePart(twoParts.pop()) && validator.isValidBackgroundPositionPart(twoParts.pop());
+    },
     isValidListStyleType: function (s) {
       return listStyleTypeKeywords.indexOf(s) >= 0 || validator.isValidVariable(s);
     },
index 7f63e0b..cf91df9 100644 (file)
@@ -1 +1 @@
-.envelope{background:url(one.png) top center repeat-x,url(one.png) bottom center repeat-x,url(two.png) 110% 10px no-repeat #eee;background-size:35px 4px,35px 4px,101px 61px}
+.envelope{background:url(one.png) top center/35px 4px repeat-x,url(one.png) bottom center/35px 4px repeat-x,url(two.png) 110% 10px/101px 61px no-repeat #eee}
index f885174..bad994b 100644 (file)
@@ -1788,15 +1788,15 @@ title']{display:block}",
   }),
   'shorthand properties': cssContext({
     'shorthand background #1' : [
-      'div{background-color:#111;background-image:url(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll}',
+      'div{background-color:#111;background-image:url(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto}',
       'div{background:url(aaa) #111}'
     ],
     'shorthand background #2' : [
-      'div{background-color:#111;background-image:url(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}',
+      'div{background-color:#111;background-image:url(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll;background-size:auto}',
       'div{background:url(aaa) no-repeat #111}'
     ],
     'shorthand important background' : [
-      'div{background-color:#111!important;background-image:url(aaa)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important}',
+      'div{background-color:#111!important;background-image:url(aaa)!important;background-repeat:repeat!important;background-position:0 0!important;background-attachment:scroll!important;background-size:auto!important}',
       'div{background:url(aaa) #111!important}'
     ],
     'shorthand border-width': [
@@ -1839,7 +1839,7 @@ title']{display:block}",
       'div{background-color:#111;background-image:linear-gradient(aaa);background-repeat:no-repeat;background-position:0 0;background-attachment:scroll}'
     ],
     'a background-image with a none and a linear-gradient should result in two shorthands' : [
-      'div{background-color:#111;background-image:none;background-image:linear-gradient(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll}',
+      'div{background-color:#111;background-image:none;background-image:linear-gradient(aaa);background-repeat:repeat;background-position:0 0;background-attachment:scroll;background-size:auto}',
       'div{background:#111;background:linear-gradient(aaa) #111}'
     ]
   }),
@@ -1922,7 +1922,7 @@ title']{display:block}",
       'p{margin:1px;margin-right:2px!important;margin-left:4px!important}'
     ],
     'should take into account important background-color and shorthand others into background': [
-      'p{background-color:#9fce00!important;background-image:url(hello);background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y}',
+      'p{background-color:#9fce00!important;background-image:url(hello);background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto}',
       'p{background-color:#9fce00!important;background:url(hello) 1px 2px repeat-y}'
     ],
     'should take into account important outline-color and default value of outline-width': [
@@ -1944,15 +1944,15 @@ title']{display:block}",
       'p{margin:inherit}'
     ],
     'merge multiple inherited background granular properties into one inherited shorthand': [
-      'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:inherit}',
+      'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:inherit;;background-size:inherit}',
       'p{background:inherit}'
     ],
     'when shorter, optimize inherited/non-inherited background granular properties into an inherited shorthand and some non-inherited granular properties': [
-      'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:repeat-y}',
+      'p{background-color:inherit;background-image:inherit;background-attachment:inherit;background-position:inherit;background-repeat:repeat-y;background-size:inherit}',
       'p{background:inherit;background-repeat:repeat-y}'
     ],
     'when shorter, optimize inherited/non-inherited background granular properties into a non-inherited shorthand and some inherited granular properties': [
-      'p{background-color:#9fce00;background-image:inherit;background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y}',
+      'p{background-color:#9fce00;background-image:inherit;background-attachment:scroll;background-position:1px 2px;background-repeat:repeat-y;background-size:auto}',
       'p{background:1px 2px repeat-y #9fce00;background-image:inherit}'
     ],
     'put inherit to the place where it consumes the least space': [
@@ -2007,6 +2007,18 @@ title']{display:block}",
     '@-o-viewport': '@-o-viewport{width:device-width}',
     '@viewport': '@viewport{width:device-width}'
   }),
+  'background size': cssContext({
+    'with background-position': 'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}',
+    'with background-position and spaces': [
+      'a{background:url(top.jpg) 50% 0 / auto 25% no-repeat}',
+      'a{background:url(top.jpg) 50% 0/auto 25% no-repeat}'
+    ],
+    'with background-position shorthands': 'a{background:url(top.jpg) 50px/25% no-repeat}',
+    'with background-position shorthands and spaces': [
+      'a{background:url(top.jpg) 0 / cover no-repeat}',
+      'a{background:url(top.jpg) 0/cover no-repeat}'
+    ]
+  }),
   'misc advanced': cssContext({
     'outline auto': [
       'a{outline:5px auto -webkit-focus-ring-color}',