Samstag, 22. August 2009

I've been doing a lot of work on Turbogears 2.0 recently. One of the things that really impressed me with Turbogears was how easy it is to re-use form components using e.g. Toscawidgets. Seeing as I also want to use the jquery javascript library to add coolness (yes, and usability), I was even more impressed to see that there is an official Toscawidgets jquery module - tw.jquery. However, it was a bit of a downer to see that there weren't all that many plugins packaged in there. Particularly, the one I needed wasn't there: http://plugins.jquery.com/project/comboselect

The way I see it, with Toscawidgets and Turbogears, you are either using widgets or you are not. Trying to sometimes include widgets, or to have only some widget form fields just doesn't work properly - it might be doable, but it's a pain. Especially when it comes to form validation. Thus, I thought it was time to bite into the sour apple and try to package the comboselect plugin myself. After some research and having a look at how other people accomplished this with jquery plugins, I managed to whack together something that works for me. Here's the class:

from tw.api import Widget, JSLink, CSSLink, js_function, js_callback
from tw.forms.fields import MultipleSelectField
from tw.jquery.base import *

jQuery = js_function('$')

jquery_selso_js = JSLink(
filename='static/javascript/jquery.selso.js',
javascript=[jquery_js],
modname=__name__)

jquery_comboselect_js = JSLink(
filename='static/javascript/jquery.comboselect.js',
javascript=[jquery_selso_js],
modname=__name__)

jquery_comboselect_css = CSSLink(
filename='static/css/jquery.comboselect.css',
modname=__name__)

class ComboSelect(MultipleSelectField):
javascript=[jquery_comboselect_js]
css=[jquery_comboselect_css]
def update_params(self,d):
super(ComboSelect,self).update_params(d)
self.update_attrs(d, "size")
d['attrs']['multiple'] = True
self.add_call("$(function(){$('#%s').comboselect({ sort: 'both', addbtn: '+',  rembtn: '-' });});"%d.id)


I added the above code to a new file "comboselect.py" in /usr/lib64/python2.6/site-packages/tw/jquery/ directory (yes, I edited this directly - I know, not elegant).

These additions were necessary to the /usr/lib64/python2.6/site-packages/tw/jquery/static/javascript/ directory:
This change was necessary to the /usr/lib64/python2.6/site-packages/tw/jquery/static/css directory:
When this is all done, you can create a widget in the normal manner, as per the standard TurboGears documentation:
"""Movie Form"""

from tw.api import WidgetsList,CSSLink
from tw.forms import TableForm, CalendarDatePicker, SingleSelectField, TextField, TextArea
from tg import url
from tw.jquery.comboselect import ComboSelect

class MovieForm(TableForm):

class fields(WidgetsList):
title = TextField()
year = TextField()
#release_date = CalendarDatePicker()
genre_options = enumerate((
'Action & Adventure', 'Animation', 'Comedy',
'Documentary', 'Drama', 'Sci-Fi & Fantasy'))
genre = ComboSelect(options=genre_options)
description = TextArea()

movie_form = MovieForm("create_movie_form")
Follow the rest of the documentation on the TurboGears documentation page referenced above and you should get something like this: