WebWidgets Overview

Classes

Gadget

A collection of widgets. like a "directory" of HTML files. you add widgets to it with self.putWidget("name", WidgetInstance()). This widget will be rendered inside the Gadget-local page. Also, if you make a Gadget that is also a subclass of "Widget", then whenever the "index" (http://foo.com/foo/, "foo" being the Gadget/Widget resource) is requested, the object will be rendered as a Widget inside of the Gadget-local page. The Gadget-local page is the 'page' attribute of the gadget, which should be a class that takes a widget in it's constructor, and displays that Widget in some form. So in your __init__ method for your Gadget subclass, do self.page = SomeWidgetPageSubclass (see "WidgetPage" below) (note that it is _not_ an instance, but the actual class object).

Widget

A Widget is simply something that is renderable, using the display() method. This method is expected to return a list of HTML strings. (it can also contain instances of defer.Deferred -- but this is another story).

Presentation

This is a special Widget that you don't create a display() method for. You override the special 'template' variable, which is a string with interpolated python expressions. It should look something like: template = ''' <html><head><title>%%%%self.title%%%%</title></head> <body>%%%%self.getContent(request)%%%%</body></html> ''' As you can see, Python expressions are denoted with surrounding sets of 4 %'s. The expressions are evaluated in a special namespace with only 'self' and 'request' in it.

WidgetPage

A WidgetPage is a special Page/Presentation combination that allows you to pass a Widget object to it's constructor. The most common use of this class is for subclassing; you should have a subclass that defines a custom 'template' attribute. WidgetPage stores the widget you pass to it in it's 'widget' attribute, so remember that whenever you're making a customized template, use %%%%self.widget%%%% (see "Common Pitfalls: WidgetPage" below).

Common Pitfalls

WidgetPage

If you have a subclass of widgets.WidgetPage, make sure your template accesses the widget it's displaying with the 'self.widget' object. For example, if you want to get the title from the current widget you're displaying:

template = '''<html><head><title>%%%%self.widget.title%%%%</title></head></html>'''

instead of:

template = '''<html><head><title>%%%%title%%%%</title></head></html>'''

Adding Widgets to a Gadget

I had some code like this in one of my Gadgets:
self.putWidget("Foo", widgets.TitleBox(MyWidget())).
Later whenever trying to access this widget I got this traceback:

Traceback evaluating code in twisted.words.webwords.Page:Traceback (most recent call last):
  File "/usr/lib/python2.1/site-packages/twisted/web/widgets.py", line 86, in display
    x = eval(elem, namespace, namespace)
  File "<string>", line 0, in ?
AttributeError: TitleBox instance has no attribute 'getHeader'

Now remember, widgets that you add to a gadget with putWidget are rendered with self.page like so: self.page(theChildWidget). The problem is, theChildWidget in this case was actually TitleBox! and of course, TitleBox doesn't follow our template's protocol of having a 'getHeader' method. So, the lesson is: do not wrap your real widgets with other widgets when adding to a Gadget: do formatting either in a) the template or b) the widget's display() method.

Return values of display

If you ever get a traceback like this:

web.Server Traceback

Traceback (most recent call last):
  File "/home/punck/cvs/Twisted/twisted/web/server.py", line 215, in process
    body = resrc.render(self)
  File "/usr/lib/python2.1/site-packages/twisted/web/widgets.py", line 408, in render
    displayed = self.display(request)
  File "/usr/lib/python2.1/site-packages/twisted/web/widgets.py", line 97, in display
    tm.extend(val)
AttributeError: TitleBox instance has no attribute '__len__'

It's because you tried to put a widget in the list that display() returns! For now, just tack on '.display(request)' to all the widgets you want to return. This will be fixed later on, that is, you will be able to include Widget objects in the list that display() returns.