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
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.

  Picture of a wild Foo
  
  

Quoting bugs are stopped dead in their tracks:

  htmltag("img", src="foo.gif", alt="1 & 3 < 5")

  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 Ward                          http://www.gerg.ca/
Heisenberg may have slept here.

reply