Permalink
Browse files

Add new option --global-template and --each-template to tune the outp…

…ut css
  • Loading branch information...
1 parent 6a4c99a commit 15997abb6039d7018d985790e9d0175a7698c067 @jorgebastida committed Mar 20, 2012
Showing with 142 additions and 78 deletions.
  1. +6 −0 docs/changelog.rst
  2. +5 −3 docs/files.rst
  3. +36 −11 docs/options.rst
  4. +40 −26 glue.py
  5. +55 −38 tests.py
View
@@ -1,6 +1,12 @@
Changelog
=========
+0.2.1
+^^^^^^
+* New command line argument ``--global-template``.
+* New command line argument ``--each-template``.
+* ``-z`` and ``--no-size`` arguments are now deprecated.
+
0.2
^^^^^
* The default behaviour of glue is now the old ``--simple`` one.
View
@@ -53,9 +53,9 @@ Available configuration
This is all the available configuration you can add to your ``sprite.conf`` files.
-======================== =========================
+======================== ======================================================================================
name default value
-======================== =========================
+======================== ======================================================================================
padding '0'
algorithm 'maxside'
namespace 'sprite'
@@ -66,4 +66,6 @@ optipng False
ignore_filename_paddings False
size True
png8 False
-======================== =========================
+global_template '%(all_classes)s{background-image:url(%(sprite_url)s);background-repeat:no-repeat}\\n'
+each_template '%(class_name)s{background-position:%(x)s %(y)s;width:%(width)s;height:%(height)s;}\\n'
+======================== ======================================================================================
View
@@ -73,17 +73,6 @@ If you want to add the same padding around all images you can use the ``--paddin
$ glue source output --padding=10 20
$ glue source output --padding=10 20 30 40
--z --no-size
-------------
-If you don't want to add the ``width`` and ``height`` properties to the sprite CSS you can remove them using the flag ``--no-size`` from the command line or using the ``size`` property in the config files.
-
-.. code-block:: bash
-
- $ glue source output --no-size
-
-.. note::
- New in version 0.1.9
-
--css --img
-----------
Usually both CSS and PNG files reside on different folders, e.g. `css` and `img`. If you want to choose an individual folder for each type of file you can use the ``--img=<dir> --css=<dir>`` options together to customize where the output files will be created.
@@ -147,6 +136,42 @@ By using the flag ``png8`` the output image format will be png8 instead of png32
$ glue source output --ignore-filename-paddings
+--global-template
+------------------
+If you want to customize the output CSS you can use this option to tune the global section of the output CSS. This template is going to be only added **once per sprite**. Usually you'll not need to change this template.
+
+.. code-block:: bash
+
+ $ glue source output --global-template=<template>
+
+
+For example if you want to add quotes around the sprite image:
+
+.. code-block:: bash
+
+ $ glue source output --global-template="%(all_classes)s{background-image:url('%(sprite_url)s');background-repeat:no-repeat}"
+
+.. note::
+ New in version 0.2.1
+
+--each-template
+------------------
+If you want to customize the output CSS, you can use this option to tune the output CSS generated for each image. This template is going to be added **once per image** present in the sprite. Usually you'll change this template if you want to remove the block size from the output CSS or make any other fine tune.
+
+.. code-block:: bash
+
+ $ glue source output --each-template=<template>
+
+
+For example if you want to remove the block size from the output CSS (old ``--no-size`` option):
+
+.. code-block:: bash
+
+ $ glue source output --each-template="%(class_name)s{background-position:%(x)s %(y)s;}"
+
+.. note::
+ New in version 0.2.1
+
--optipng
---------
View
66 glue.py
@@ -11,7 +11,7 @@
from PIL import Image as PImage
-__version__ = '0.2'
+__version__ = '0.2.1'
TRANSPARENT = (255, 255, 255, 0)
@@ -28,8 +28,13 @@
'less': False,
'optipng': False,
'ignore_filename_paddings': False,
- 'size': True,
- 'png8': False}
+ 'png8': False,
+ 'global_template': ('%(all_classes)s{background-image:'
+ 'url(%(sprite_url)s);'
+ 'background-repeat:no-repeat}\n'),
+ 'each_template': ('%(class_name)s{'
+ 'background-position:%(x)s %(y)s;'
+ 'width:%(width)s;height:%(height)s;}\n')}
class MultipleImagesWithSameNameError(Exception):
@@ -530,31 +535,28 @@ def save_css(self):
css_file = open(css_filename, 'w')
# get all the class names and join them
- class_names = ['.%s' % i.class_name for i in self.images]
- class_names = ',\n'.join(class_names)
+ class_names = ',\n'.join(['.%s' % i.class_name for i in self.images])
- # create an unique style for all the sprites for less bloat
- style = "%s{background-image:url(%s);background-repeat:no-repeat;}\n"
- css_file.write(style % (class_names, self.image_url))
+ # add the global style for all the sprites for less bloat
+ template = self.config.global_template
+ css_file.write(template % {'all_classes': class_names,
+ 'sprite_url': self.image_url})
+ # compile one template for each file
for image in self.images:
- data = {'image_class_name': image.class_name,
- 'top': image.y * -1 if image.y else 0,
- 'left': image.x * -1 if image.x else 0,
- 'width': image.absolute_width,
- 'height': image.absolute_height}
-
- style = (".%(image_class_name)s{"
- "background-position:%(left)ipx %(top)ipx;")
-
- if self.config.size:
- # if it's required add the image size to the sprite
- style += "width:%(width)spx;height:%(height)spx;"
-
- style += "}\n"
-
- css_file.write(style % data)
+ x = '%spx' % (image.y * -1 if image.y else 0)
+ y = '%spx' % (image.x * -1 if image.x else 0)
+ height = '%spx' % image.absolute_height
+ width = '%spx' % image.absolute_width
+
+ template = self.config.each_template
+ css_file.write(template % {'class_name': '.%s' % image.class_name,
+ 'sprite_url': self.image_url,
+ 'height': height,
+ 'width': width,
+ 'y': y,
+ 'x': x})
css_file.close()
@property
@@ -839,8 +841,6 @@ def main():
help="suppress all normal output")
parser.add_option("-p", "--padding", dest="padding", default=None,
help="force this padding in all images")
- parser.add_option("-z", "--no-size", action="store_false", dest="size",
- help="don't add the image size to the sprite")
parser.add_option("-v", "--version", action="store_true", dest="version",
help="show program's version number and exit")
@@ -868,6 +868,20 @@ def main():
help="ignore filename paddings")
parser.add_option_group(group)
+ group = OptionGroup(parser, "Output CSS Template Options")
+ group.add_option("--global-template", dest="global_template",
+ help=("Customize the global section of the output CSS."
+ "This section will be added only once for each "
+ "sprite."),
+ metavar='TEMPLATE')
+
+ group.add_option("--each-template", dest="each_template",
+ help=("Customize each image output CSS."
+ "This section will be added once for each "
+ "image inside the sprite."),
+ metavar='TEMPLATE')
+ parser.add_option_group(group)
+
group = OptionGroup(parser, "Optipng Options",
"You need to install optipng before using these options")
group.add_option("--optipng", dest="optipng", action='store_true',
View
@@ -20,8 +20,7 @@
TRANSPARENT = (0, 0, 0, 0)
-EXPECTED_SIMPLE_CSS = """
-.sprite-simple-yellow,
+EXPECTED_SIMPLE_CSS = """.sprite-simple-yellow,
.sprite-simple-red,
.sprite-simple-pink,
.sprite-simple-green,
@@ -32,63 +31,65 @@
.sprite-simple-pink{background-position:-50px 0px;width:25px;height:25px;}
.sprite-simple-green{background-position:-75px 0px;width:25px;height:25px;}
.sprite-simple-cyan{background-position:-100px 0px;width:25px;height:25px;}
-.sprite-simple-blue{background-position:-125px 0px;width:25px;height:25px;}"""
+.sprite-simple-blue{background-position:-125px 0px;width:25px;height:25px;}
+"""
-EXPECTED_PROJECT_MIX_CSS = """
-.sprite-mix-yellow,
+EXPECTED_PROJECT_MIX_CSS = """.sprite-mix-yellow,
.sprite-mix-pink,
.sprite-mix-cyan{background-image:url(mix.png);background-repeat:no-repeat;}
.sprite-mix-yellow{background-position:0px 0px;width:25px;height:25px;}
.sprite-mix-pink{background-position:-25px 0px;width:25px;height:25px;}
-.sprite-mix-cyan{background-position:0px -25px;width:25px;height:25px;}"""
+.sprite-mix-cyan{background-position:0px -25px;width:25px;height:25px;}
+"""
-EXPECTED_PROJECT_RGB_CSS = """
-.sprite-rgb-red,
+EXPECTED_PROJECT_RGB_CSS = """.sprite-rgb-red,
.sprite-rgb-green,
.sprite-rgb-blue{background-image:url(rgb.png);background-repeat:no-repeat;}
.sprite-rgb-red{background-position:0px 0px;width:25px;height:25px;}
.sprite-rgb-green{background-position:-25px 0px;width:25px;height:25px;}
-.sprite-rgb-blue{background-position:0px -25px;width:25px;height:25px;}"""
+.sprite-rgb-blue{background-position:0px -25px;width:25px;height:25px;}
+"""
-EXPECTED_SIMPLE_CROP = """
-.sprite-crop-red_border,
+EXPECTED_SIMPLE_CROP = """.sprite-crop-red_border,
.sprite-crop-green_border,
.sprite-crop-blue_border{background-image:url(crop.png);background-repeat:no-repeat;}
.sprite-crop-red_border{background-position:0px 0px;width:25px;height:25px;}
.sprite-crop-green_border{background-position:-25px 0px;width:25px;height:25px;}
-.sprite-crop-blue_border{background-position:0px -25px;width:25px;height:25px;}"""
+.sprite-crop-blue_border{background-position:0px -25px;width:25px;height:25px;}
+"""
-EXPECTED_SIMPLE_PADDING = """
-.sprite-padding-red,
+EXPECTED_SIMPLE_PADDING = """.sprite-padding-red,
.sprite-padding-green,
.sprite-padding-blue{background-image:url(padding.png);background-repeat:no-repeat;}
.sprite-padding-red{background-position:0px 0px;width:45px;height:45px;}
.sprite-padding-green{background-position:-45px 0px;width:45px;height:35px;}
-.sprite-padding-blue{background-position:0px -45px;width:31px;height:29px;}"""
+.sprite-padding-blue{background-position:0px -45px;width:31px;height:29px;}
+"""
-EXPECTED_VERYSIMPLE_URL = """
-.sprite-verysimple-red,
+EXPECTED_VERYSIMPLE_URL = """.sprite-verysimple-red,
.sprite-verysimple-green,
.sprite-verysimple-blue{background-image:url(/static/verysimple.png);background-repeat:no-repeat;}
.sprite-verysimple-red{background-position:0px 0px;width:25px;height:25px;}
.sprite-verysimple-green{background-position:-25px 0px;width:25px;height:25px;}
-.sprite-verysimple-blue{background-position:0px -25px;width:25px;height:25px;}"""
+.sprite-verysimple-blue{background-position:0px -25px;width:25px;height:25px;}
+"""
EXPECTED_VERYSIMPLE_NOSIZE = """
.sprite-verysimple-red,
.sprite-verysimple-green,
.sprite-verysimple-blue{background-image:url(verysimple.png);background-repeat:no-repeat;}
.sprite-verysimple-red{background-position:0px 0px;}
.sprite-verysimple-green{background-position:-25px 0px;}
-.sprite-verysimple-blue{background-position:0px -25px;}"""
+.sprite-verysimple-blue{background-position:0px -25px;}
+"""
-EXPECTED_PADDING_NOPADDING = """
-.sprite-padding-red_10,
+EXPECTED_PADDING_NOPADDING = """.sprite-padding-red_10,
.sprite-padding-green_5-10,
.sprite-padding-blue_1-2-3-4{background-image:url(padding.png);background-repeat:no-repeat;}
.sprite-padding-red_10{background-position:0px 0px;width:25px;height:25px;}
.sprite-padding-green_5-10{background-position:-25px 0px;width:25px;height:25px;}
-.sprite-padding-blue_1-2-3-4{background-position:0px -25px;width:25px;height:25px;}"""
+.sprite-padding-blue_1-2-3-4{background-position:0px -25px;width:25px;height:25px;}
+"""
EXPECTED_VERYSIMPLE_NAMESPACE = """
@@ -97,15 +98,17 @@
.abc-verysimple-blue{background-image:url(verysimple.png);background-repeat:no-repeat;}
.abc-verysimple-red{background-position:0px 0px;width:25px;height:25px;}
.abc-verysimple-green{background-position:-25px 0px;width:25px;height:25px;}
-.abc-verysimple-blue{background-position:0px -25px;width:25px;height:25px;}"""
+.abc-verysimple-blue{background-position:0px -25px;width:25px;height:25px;}
+"""
EXPECTED_VERYSIMPLE_EMPTYNAMESPACE = """
.verysimple-red,
.verysimple-green,
.verysimple-blue{background-image:url(verysimple.png);background-repeat:no-repeat;}
.verysimple-red{background-position:0px 0px;width:25px;height:25px;}
.verysimple-green{background-position:-25px 0px;width:25px;height:25px;}
-.verysimple-blue{background-position:0px -25px;width:25px;height:25px;}"""
+.verysimple-blue{background-position:0px -25px;width:25px;height:25px;}
+"""
class SimpleCssCompiler(object):
@@ -300,7 +303,6 @@ def test_crop(self):
self.assertEqual(image.getpixel((25, 0)), GREEN)
self.assertEqual(image.getpixel((0, 25)), BLUE)
self.assertEqual(image.getpixel((25, 25)), TRANSPARENT)
-
self.assertEqualCSS(css.read(), EXPECTED_SIMPLE_CROP)
css.close()
@@ -373,19 +375,6 @@ def test_url(self):
self.assertEqualCSS(css.read(), EXPECTED_VERYSIMPLE_URL)
css.close()
- def test_nosize(self):
- manager = self.generate_manager(glue.SimpleSpriteManager,
- 'verysimple',
- {'size': False})
- manager.process()
-
- css_path = os.path.join(self.output_path, 'verysimple.css')
- self.assertTrue(os.path.isfile(css_path))
-
- css = open(css_path)
- self.assertEqualCSS(css.read(), EXPECTED_VERYSIMPLE_NOSIZE)
- css.close()
-
def test_ordering(self):
# Test maxside ordering
manager = self.generate_manager(glue.SimpleSpriteManager,
@@ -533,6 +522,34 @@ def test_png8(self):
self.assertTrue(all([t == 255 for t in transparency[:-1]]))
self.assertEqual(transparency[-1], 0)
+ def test_templates(self):
+ # Test empty templates
+ manager = self.generate_manager(glue.SimpleSpriteManager,
+ 'verysimple',
+ {'global_template': '',
+ 'each_template': ''})
+ manager.process()
+
+ css_path = os.path.join(self.output_path, 'verysimple.css')
+ self.assertTrue(os.path.isfile(css_path))
+
+ css = open(css_path)
+ self.assertEqualCSS(css.read(), '')
+ css.close()
+
+ # Test no-size template
+ manager = self.generate_manager(glue.SimpleSpriteManager,
+ 'verysimple',
+ {'each_template': ('%(class_name)s{background-position:%(x)s %(y)s;}\n')})
+ manager.process()
+
+ css_path = os.path.join(self.output_path, 'verysimple.css')
+ self.assertTrue(os.path.isfile(css_path))
+
+ css = open(css_path)
+ self.assertEqualCSS(css.read(), EXPECTED_VERYSIMPLE_NOSIZE)
+ css.close()
+
class TestConfigManager(unittest.TestCase):

0 comments on commit 15997ab

Please sign in to comment.