I've been thinking a bit about the right way to generalize the form/widget API to handle arbitrary HTML attributes. I'm pretty sure that adding support for "whatever is needed today" is the *wrong* approach; it's hard to predict what parts of HTML are universally useful, and it would be annoying to lock out obscure corners of the language that might be useful to someone. I think the right approach is to extend the style of quixote.html.htmltag(), ie. make Python keyword args correspond to HTML attributes. Right now, you can do this in your PTL code: from quixote.html import htmltag [...] htmltag("img", src="foo.gif", alt="Picture of a wild Foo") htmltag("a", href="/blah", target="blahwindow", css_class="mylink") jscode = "..." # put your hairy JavaScript code there htmltag("input", type="button", onclick=jscode) and Quixote will emit pretty much what you expect, ie. Quoting bugs are stopped dead in their tracks: htmltag("img", src="foo.gif", alt="1 & 3 < 5") Anyways, the Form and Widget classes use this function under the hood. I suspect 80% of the funky stuff people need to do, but can't do with quixote.form2 now, could be addressed by simply adding a "**attrs" argument to the constructor of Form and every Widget. In fact, I think it'll even make the code simpler. Here's an initial, entirely conceptual and untested crack at "fixing" Widget and StringWidget. ------------------------------------------------------------------------ --- widget.py.orig0 2003-11-16 16:09:37.000000000 -0500 +++ widget.py 2003-11-24 21:08:52.000000000 -0500 @@ -31,14 +31,18 @@ name : string value : any error : string + attrs : { string : any } + arbitrary HTML attribute values; will be added to the tag + used to render this widget Feel free to access these directly; to set them, use the 'set_*()' modifier methods. """ - def __init__(self, name, value=None): + def __init__(self, name, value=None, **attrs): assert self.__class__ is not Widget, "abstract class" self.name = name + self.attrs = attrs self.error = None request = get_request() if request.form: @@ -106,27 +110,20 @@ Instance attributes: value : string - size : int - maxlength : int """ # This lets PasswordWidget be a trivial subclass HTML_TYPE = "text" - def __init__(self, name, value=None, - size=None, maxlength=None): - Widget.__init__(self, name, value) - self.size = size - self.maxlength = maxlength + def __init__(self, name, value=None, **attrs): + Widget.__init__(self, name, value, **attrs) - def render(self, **attributes): + def render(self): return htmltag("input", xml_end=True, type=self.HTML_TYPE, name=self.name, - size=self.size, - maxlength=self.maxlength, value=self.value, - **attributes) + **self.attrs) class FileWidget(StringWidget): ------------------------------------------------------------------------ Notice how special-purpose knowledge -- the fact that 'size' and 'maxlength' are useful attributes of an tag -- disappears from StringWidget. You're just as free to specify 'size' and 'maxlength', but you can also specify 'css_class' (which htmltag() turns into 'class'), 'accesskey', 'tabindex', 'onfocus', or any of the other attributes specified by whichever version of HTML you happen to use. Now the code in the widget framework concentrates on what it *needs* to know, namely the name and value of every widget. (Those also translate into HTML attributes, but they should be treated specially since they are meaningful to the framework.) I like that. Extending this to the other Widget subclasses should be trivial, and I don't see any great difficulties in similarly modifying Form. Ideas? feedback? opinions? Greg -- Greg Wardhttp://www.gerg.ca/ Heisenberg may have slept here.