diff -r 4176a50c81c9 -r d321e4b62a10 web/formwidgets.py
--- a/web/formwidgets.py Wed Apr 21 16:53:25 2010 +0200
+++ b/web/formwidgets.py Wed Apr 21 16:53:47 2010 +0200
@@ -1,9 +1,75 @@
-"""widget classes for form construction
+# organization: Logilab
+# copyright: 2009-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
+# contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+# license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
+"""
+Widgets
+~~~~~~~
+
+.. Note::
+ A widget is responsible for the display of a field. It may use more than one
+ HTML input tags. When the form is posted, a widget is also reponsible to give
+ back to the field something it can understand.
+
+ Of course you can not use any widget with any field...
+
+.. autoclass:: cubicweb.web.formwidgets.FieldWidget
+
+HTML based widgets
+''''''''''''''''''''''''''
+
+.. autoclass:: cubicweb.web.formwidgets.HiddenInput
+.. autoclass:: cubicweb.web.formwidgets.TextInput
+.. autoclass:: cubicweb.web.formwidgets.PasswordSingleInput
+.. autoclass:: cubicweb.web.formwidgets.FileInput
+.. autoclass:: cubicweb.web.formwidgets.ButtonInput
+
+Other standard HTML widgets
+'''''''''''''''''''''''''''
+
+.. autoclass:: cubicweb.web.formwidgets.TextArea
+.. autoclass:: cubicweb.web.formwidgets.Select
+.. autoclass:: cubicweb.web.formwidgets.CheckBox
+.. autoclass:: cubicweb.web.formwidgets.Radio
-:organization: Logilab
-:copyright: 2009-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
+Date and time widgets
+'''''''''''''''''''''
+
+.. autoclass:: cubicweb.web.formwidgets.DateTimePicker
+.. autoclass:: cubicweb.web.formwidgets.JQueryDateTimePicker
+.. autoclass:: cubicweb.web.formwidgets.JQueryDatePicker
+.. autoclass:: cubicweb.web.formwidgets.JQueryTimePicker
+
+Ajax / javascript widgets
+'''''''''''''''''''''''''
+
+.. autoclass:: cubicweb.web.formwidgets.FCKEditor
+.. autoclass:: cubicweb.web.formwidgets.AjaxWidget
+.. autoclass:: cubicweb.web.formwidgets.AutoCompletionWidget
+
+.. kill or document AddComboBoxWidget
+.. kill or document StaticFileAutoCompletionWidget
+.. kill or document LazyRestrictedAutoCompletionWidget
+.. kill or document RestrictedAutoCompletionWidget
+
+Other widgets
+'''''''''''''
+.. autoclass:: cubicweb.web.formwidgets.PasswordInput
+.. autoclass:: cubicweb.web.formwidgets.IntervalWidget
+.. autoclass:: cubicweb.web.formwidgets.HorizontalLayoutWidget
+.. autoclass:: cubicweb.web.formwidgets.EditableURLWidget
+
+Form controls
+'''''''''''''
+Those classes are not proper widget (they are not associated to
+field) but are used as form controls. Their API is similar
+to widgets except that `field` argument given to :meth:`render`
+will be `None`.
+
+.. autoclass:: cubicweb.web.formwidgets.Button
+.. autoclass:: cubicweb.web.formwidgets.SubmitButton
+.. autoclass:: cubicweb.web.formwidgets.ResetButton
+.. autoclass:: cubicweb.web.formwidgets.ImgButton
"""
__docformat__ = "restructuredtext en"
@@ -19,14 +85,50 @@
class FieldWidget(object):
- """abstract widget class"""
- # javascript / css files required by the widget
+ """The abstract base class for widgets.
+
+ **Attributes**
+
+ Here are standard attributes of a widget, that may be set on concret
+ class to override default behaviours:
+
+ :attr:`needs_js`
+ list of javascript files needed by the widget.
+ :attr:`needs_css`
+ list of css files needed by the widget.
+ :attr:`setdomid`
+ flag telling if HTML DOM identifier should be set on input.
+ :attr:`settabindex`
+ flag telling if HTML tabindex attribute of inputs should be set.
+ :attr:`suffix`
+ string to use a suffix when generating input, to ease usage as a
+ sub-widgets (eg widget used by another widget)
+ :attr:`vocabulary_widget`
+ flag telling if this widget expect a vocabulary
+
+ Also, widget instances takes as first argument a `attrs` dictionary which
+ will be stored in the attribute of the same name. It contains HTML
+ attributes that should be set in the widget's input tag (though concret
+ classes may ignore it).
+
+ .. currentmodule:: cubicweb.web.formwidgets
+
+ **Form generation methods**
+
+ .. automethod:: render
+ .. automethod:: _render
+ .. automethod:: values
+ .. automethod:: attributes
+
+ **Post handling methods**
+
+ .. automethod:: process_field_data
+
+ """
needs_js = ()
needs_css = ()
- # automatically set id and tabindex attributes ?
setdomid = True
settabindex = True
- # to ease usage as a sub-widgets (eg widget used by another widget)
suffix = None
# does this widget expect a vocabulary
vocabulary_widget = False
@@ -51,12 +153,19 @@
if self.needs_css:
form._cw.add_css(self.needs_css)
+ def render(self, form, field, renderer=None):
+ """Called to render the widget for the given `field` in the given
+ `form`. Return a unicode string containing the HTML snippet.
- def render(self, form, field, renderer=None):
+ You will usually prefer to override the :meth:`_render` method so you
+ don't have to handle addition of needed javascript / css files.
+ """
self.add_media(form)
return self._render(form, field, renderer)
def _render(self, form, field, renderer):
+ """This is the method you have to implement in concret widget classes.
+ """
raise NotImplementedError()
def format_value(self, form, field, value):
@@ -75,6 +184,30 @@
return attrs
def values(self, form, field):
+ """Return the current *string* values (i.e. for display in an HTML
+ string) for the given field. This method returns a list of values since
+ it's suitable for all kind of widgets, some of them taking multiple
+ values, but you'll get a single value in the list in most cases.
+
+ Those values are searched in:
+
+ 1. previously submitted form values if any (on validation error)
+
+ 2. req.form (specified using request parameters)
+
+ 3. extra form values given to form.render call (specified the code
+ generating the form)
+
+ 4. field's typed value (returned by its
+ :meth:`~cubicweb.web.formfields.Field.typed_value` method)
+
+ Values found in 1. and 2. are expected te be already some 'display
+ value' (eg a string) while those found in 3. and 4. are expected to be
+ correctly typed value.
+
+ 3 and 4 are handle by the :meth:`typed_value` method to ease reuse in
+ concret classes.
+ """
values = None
if not field.ignore_req_params:
qname = field.input_name(form, self.suffix)
@@ -112,6 +245,10 @@
return field.typed_value(form)
def process_field_data(self, form, field):
+ """Return process posted value(s) for widget and return something
+ understandable by the associated `field`. That value may be correctly
+ typed or a string that the field may parse.
+ """
posted = form._cw.form
val = posted.get(field.input_name(form, self.suffix))
if isinstance(val, basestring):
@@ -152,13 +289,29 @@
# basic html widgets ###########################################################
class TextInput(Input):
- """"""
+ """Simple , will return an unicode string."""
type = 'text'
+class PasswordSingleInput(Input):
+ """Simple , will return an utf-8 encoded string.
+
+ You may prefer using the :class:`~cubicweb.web.formwidgets.PasswordInput`
+ widget which handles password confirmation.
+ """
+ type = 'password'
+
+ def process_field_data(self, form, field):
+ value = super(PasswordSingleInput, self).process_field_data(form, field)
+ if value is not None:
+ return value.encode('utf-8')
+ return value
+
+
class PasswordInput(Input):
- """ and its confirmation field (using
- -confirm as name)
+ """ and a confirmation input. Form processing will
+ fail if password and confirmation differs, else it will return the password
+ as an utf-8 encoded string.
"""
type = 'password'
@@ -186,19 +339,11 @@
raise ProcessFormError(form._cw._("password and confirmation don't match"))
-class PasswordSingleInput(Input):
- """ without a confirmation field"""
- type = 'password'
-
- def process_field_data(self, form, field):
- value = super(PasswordSingleInput, self).process_field_data(form, field)
- if value is not None:
- return value.encode('utf-8')
- return value
-
-
class FileInput(Input):
- """"""
+ """Simple , will return a tuple (name, stream) where
+ name is the posted file name and stream a file like object containing the
+ posted file data.
+ """
type = 'file'
def values(self, form, field):
@@ -207,23 +352,25 @@
class HiddenInput(Input):
- """"""
+ """Simple for hidden value, will return an unicode
+ string.
+ """
type = 'hidden'
setdomid = False # by default, don't set id attribute on hidden input
settabindex = False
class ButtonInput(Input):
- """
+ """Simple , will return an unicode string.
- if you want a global form button, look at the Button, SubmitButton,
- ResetButton and ImgButton classes below.
+ If you want a global form button, look at the :class:`Button`,
+ :class:`SubmitButton`, :class:`ResetButton` and :class:`ImgButton` below.
"""
type = 'button'
class TextArea(FieldWidget):
- """