OK, here's a more complete patch for form2/widget.py. This one's
actually tested (a bit) and it seems to work. At least, I could put
annoying JavaScript code into my form with very little effort, and
css_class=... worked too. Woo-hoo.
Neil, I'm not sure this one's *quite* ready for checkin -- I'd
like a few people to test it first!
--- form2/widget.py.orig0 2003-11-16 16:09:37.000000000 -0500
+++ form2/widget.py 2003-11-24 21:44:41.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):
@@ -161,17 +158,10 @@
Instance attributes:
value : string
- cols : int
- rows : int
- wrap : string
- (see an HTML book for details on text widget wrap options)
"""
- def __init__(self, name, value=None, cols=None, rows=None, wrap=None):
- Widget.__init__(self, name, value)
- self.cols = cols
- self.rows = rows
- self.wrap = wrap
+ def __init__(self, name, value=None, **attrs):
+ Widget.__init__(self, name, value, **attrs)
def _parse(self, request):
Widget._parse(self, request)
@@ -179,10 +169,7 @@
self.value = self.value.replace("\r\n", "\n")
def render(self):
- return (htmltag("textarea", name=self.name,
- cols=self.cols,
- rows=self.rows,
- wrap=self.wrap) +
+ return (htmltag("textarea", name=self.name, **self.attrs) +
htmlescape(self.value or "") +
htmltext(""))
@@ -204,7 +191,8 @@
type="checkbox",
name=self.name,
value="yes",
- checked=self.value and ValuelessAttr or None)
+ checked=self.value and ValuelessAttr or None,
+ **self.attrs)
@@ -225,17 +213,16 @@
def __init__(self, name, value=None,
options=None,
- size=None,
sort=True,
- verify_selection=True):
+ verify_selection=True,
+ **attrs):
assert self.__class__ is not SelectWidget, "abstract class"
self.options = []
if options is not None:
assert options, 'cannot pass empty options list'
self.set_options(options, sort)
self.verify_selection = verify_selection
- self.size = size
- Widget.__init__(self, name, value)
+ Widget.__init__(self, name, value, **attrs)
def get_allowed_values(self):
return [item[0] for item in self.options]
@@ -371,13 +358,13 @@
multiple = ValuelessAttr
else:
multiple = None
- if self.SELECT_TYPE == "option_select":
- onchange = "submit()"
- else:
- onchange = None
- tags = [htmltag("select", name=self.name,
- multiple=multiple, onchange=onchange,
- size=self.size)]
+ if ('onchange' not in self.attrs and
+ self.SELECT_TYPE == "option_select"):
+ self.attrs['onchange'] = "submit()"
+ tags = [htmltag("select",
+ name=self.name,
+ multiple=multiple,
+ **self.attrs)]
for object, description, key in self.options:
if self.is_selected(object):
selected = ValuelessAttr
@@ -423,10 +410,12 @@
def __init__(self, name, value=None,
options=None,
- delim=None):
+ delim=None,
+ **attrs):
SingleSelectWidget.__init__(self, name,
value=value,
- options=options)
+ options=options,
+ **attrs)
if delim is None:
self.delim = "\n"
else:
@@ -443,7 +432,8 @@
type="radio",
name=self.name,
value=key,
- checked=checked)
+ checked=checked,
+ **attrs)
tags.append(r + htmlescape(description) + htmltext(''))
return htmlescape(self.delim).join(tags)
@@ -498,7 +488,7 @@
HTML_TYPE = "button"
- def __init__(self, name, value=None):
+ def __init__(self, name, value=None, **attrs):
self.name = name
self.error = None
# slightly different behavior here, we always render the
@@ -506,6 +496,7 @@
# attribute is a boolean that is true if the button's name appears
# in the request.
self.label = value
+ self.attrs = attrs
request = get_request()
if request.form:
self._parse(request)
@@ -518,7 +509,7 @@
def render(self):
value = (self.label and htmlescape(self.label) or None)
return htmltag("input", xml_end=True, type=self.HTML_TYPE,
- name=self.name, value=value)
+ name=self.name, value=value, **self.attrs)
def _parse(self, request):
self.value = request.form.has_key(self.name)
@@ -549,7 +540,8 @@
return htmltag("input", xml_end=True,
type="hidden",
name=self.name,
- value=value)
+ value=value,
+ **self.attrs)
# -- Derived widget types ----------------------------------------------
@@ -569,13 +561,13 @@
def __init__(self, name,
value=None,
- size=None, maxlength=None):
+ **attrs):
assert self.__class__ is not NumberWidget, "abstract class"
assert value is None or type(value) is self.TYPE_OBJECT, (
"form value '%s' not a %s: got %r" % (name,
self.TYPE_OBJECT,
value))
- StringWidget.__init__(self, name, value, size, maxlength)
+ StringWidget.__init__(self, name, value, **attrs)
def _parse(self, request):
StringWidget._parse(self, request)
--
Greg Ward http://www.gerg.ca/
Eschew obfuscation!