durusmail: quixote-users: Generalizing form/widget API a bit
Generalizing form/widget API a bit
2003-11-25
2003-11-25
2003-11-25
2003-11-25
2003-11-25
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-26
2003-11-29
2003-11-30
2003-11-26
2003-11-26
2003-11-26
Patch: add html_attrs keyword arg to widget classes
2003-11-30
Patch: add html_attrs keyword arg to widget classes
2003-12-01
Patch: add html_attrs keyword arg to widget classes
2003-12-01
Patch: add html_attrs keyword arg to widget classes
2003-12-01
2003-12-02
2003-12-03
2003-12-02
Patch: add html_attrs keyword arg to widget classes
2003-12-01
Patch: add html_attrs keyword arg to widget classes
2003-12-01
Generalizing form/widget API a bit
Greg Ward
2003-11-25
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!

reply