Monday, December 8, 2008

Adding Textile to Google App Engine

By default, App Engine includes a copy of Django that it pulls in components from. However, the integration points between App Engine and Django are fairly custom and not well documented. Trying to follow vanilla Django examples for installing Textile will not work in the context of App Engine. To get Textile to work will involve a number of steps.

To begin with, you will want to create a lib folder in your App Engine project's home directory.

~/Projects/Example$ mkdir lib

You will then want to download Textile and extract into your newly created lib folder.

~/Projects/Example$ cd lib
~/Projects/Example/lib$ curl -O http://pypi.python.org/packages/source/t/textile/textile-2.1.2.tar.gz
~/Projects/Example/lib$ tar xzf textile-2.1.2.tar.gz

The Django template library django.contrib.markup will attempt to import from the namespace textile. You need to let Python know to look inside directories in the lib directory for namespaces. To do this, you will need to modify your sys.path to include those directories. The way to do this is to add the following code to the top of the file or files that contain your main functions, such as main.py in some of the App Engine demos.

import os
import sys
import logging

DIR_PATH = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
LIB_PATH = os.path.join(DIR_PATH, "lib")
EXTRA_PATHS = []
for path in os.listdir(LIB_PATH):
fullpath = os.path.join(LIB_PATH, path)
if os.path.isdir(fullpath) and not path.startswith("."):
EXTRA_PATHS.append(fullpath)
sys.path = sys.path + EXTRA_PATHS

This will modify the sys.path and let Python know to look inside of your lib directory for namespaces to import.

Now that Textile is installed, you need to register the necessary Django template library with App Engine. To do this, you need to make the following call in your code before rendering a template. I put this call in my base controller, as the first line of my get and post functions.

def get(self):
template.register_template_library('django.contrib.markup.templatetags.markup')
# Do your template processing here.

At this point, you should be able to use the textile template tag in App Engine templates like so.

<span>{{someVar|textile}}</span>

Saturday, April 5, 2008

One Tag Solution: Simple CSS Ratings

The 4- or 5-star rating has become the default for conveying popularity or relevance across the web. There are many ways to render a rating using stars in HTML and CSS. However, I have not seen a solution that is simultaneously simple, optimized, semantic, and accessible. Therefore, I set to work to uncover my own. The result looks like this: (The image 'none.gif' is a 1x1 transparent gif file)

<img class="rating" alt="3.5" src="/none.gif" />



The initial goal was to start by rendering a rating using only a single HTML tag that both visually displays the rating and retains its numerical value. The tag to use was very obviously the <img> tag. It is meant to display visual information and the 'alt' attribute is the perfect way to convey the numerical value of the rating. For slow-loading webpages, the numerical value of the rating will be displayed until the images load in.

The next objective was to make use of image spriting to contain the stars so that only one image has to be loaded and cached for all ratings. There are several different approaches to this. The image sprite I chose to make use of looks like this:



The idea is to set the width of the image to be 5-stars wide and then slide this sprite around to get the desired rating.

Building the CSS for this is rather simple. I will demonstrate the intended, but IE6-incompatible approach first. IE6 is the only modern browser that does not support the attribute selector syntax.

img.rating {
background: transparent url(stars.gif) no-repeat scroll;
width: 100px;
height: 20px;
}
img.rating[alt="0.0"] { background-position: -100px 0; }
img.rating[alt="0.5"] { background-position: -80px -20px; }
img.rating[alt="1.0"] { background-position: -80px 0; }
img.rating[alt="1.5"] { background-position: -60px -20px; }
img.rating[alt="2.0"] { background-position: -60px 0; }
img.rating[alt="2.5"] { background-position: -40px -20px; }
img.rating[alt="3.0"] { background-position: -40px 0; }
img.rating[alt="3.5"] { background-position: -20px -20px; }
img.rating[alt="4.0"] { background-position: -20px 0; }
img.rating[alt="4.5"] { background-position: 0 -20px; }
img.rating[alt="5.0"] { background-position: 0 0; }

The less than desirable CSS solution that works with IE6 is to simply add an additional class to the image indicating which rating is being displayed.

img.rating {
background: transparent url(stars.gif) no-repeat scroll;
width: 100px;
height: 20px;
}
img.rating-0\.0 { background-position: -100px 0; }
img.rating-0\.5 { background-position: -80px -20px; }
img.rating-1\.0 { background-position: -80px 0; }
img.rating-1\.5 { background-position: -60px -20px; }
img.rating-2\.0 { background-position: -60px 0; }
img.rating-2\.5 { background-position: -40px -20px; }
img.rating-3\.0 { background-position: -40px 0; }
img.rating-3\.5 { background-position: -20px -20px; }
img.rating-4\.0 { background-position: -20px 0; }
img.rating-4\.5 { background-position: 0 -20px; }
img.rating-5\.0 { background-position: 0 0; }

The modified HTML code would look like:

<img class="rating rating-3.5" alt="3.5" src="/none.gif" />

In the end, the result is a simple, semantic rating in one tag and one image. For part 2, I will demonstrate how to turn this into a rating you can pick from.