web/views/forms.py
branchstable
changeset 5368 d321e4b62a10
parent 5367 4176a50c81c9
child 5421 8167de96c523
equal deleted inserted replaced
5367:4176a50c81c9 5368:d321e4b62a10
     1 """some base form classes for CubicWeb web client
     1 # organization: Logilab
     2 
     2 # copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
     3 :organization: Logilab
     3 # contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     4 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
     4 # license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     5 """
     6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     6 Base form classes
       
     7 -----------------
       
     8 
       
     9 .. Note:
       
    10 
       
    11    Form is the glue that bind a context to a set of fields, and is rendered
       
    12    using a form renderer. No display is actually done here, though you'll find
       
    13    some attributes of form that are used to control the rendering process.
       
    14 
       
    15 Besides the automagic form we'll see later, they are barely two form
       
    16 classes in |cubicweb|:
       
    17 
       
    18 .. autoclass:: cubicweb.web.views.forms.FieldsForm
       
    19 .. autoclass:: cubicweb.web.views.forms.EntityFieldsForm
       
    20 
       
    21 As you have probably guessed, choosing between them is easy. Simply ask you the
       
    22 question 'I am editing an entity or not?'. If the answer is yes, use
       
    23 :class:`EntityFieldsForm`, else use :class:`FieldsForm`.
       
    24 
       
    25 Actually there exists a third form class:
       
    26 
       
    27 .. autoclass:: cubicweb.web.views.forms.CompositeForm
       
    28 
       
    29 but you'll use this one rarely.
     7 """
    30 """
     8 __docformat__ = "restructuredtext en"
    31 __docformat__ = "restructuredtext en"
     9 
    32 
    10 from warnings import warn
    33 from warnings import warn
    11 
    34 
    18 from cubicweb.web import uicfg, form, formwidgets as fwdgs
    41 from cubicweb.web import uicfg, form, formwidgets as fwdgs
    19 from cubicweb.web.formfields import relvoc_unrelated, guess_field
    42 from cubicweb.web.formfields import relvoc_unrelated, guess_field
    20 
    43 
    21 
    44 
    22 class FieldsForm(form.Form):
    45 class FieldsForm(form.Form):
    23     """base class for fields based forms.
    46     """This is the base class for fields based forms.
       
    47 
       
    48     **Attributes**
    24 
    49 
    25     The following attributes may be either set on subclasses or given on
    50     The following attributes may be either set on subclasses or given on
    26     form selection to customize the generated form:
    51     form selection to customize the generated form:
    27 
    52 
    28     * `needs_js`: sequence of javascript files that should be added to handle
    53     :attr:`needs_js`
    29       this form (through `req.add_js`)
    54       sequence of javascript files that should be added to handle this form
    30 
    55       (through :meth:`~cubicweb.web.request.Request.add_js`)
    31     * `needs_css`: sequence of css files that should be added to handle this
    56 
    32       form (through `req.add_css`)
    57     :attr:`needs_css`
    33 
    58       sequence of css files that should be added to handle this form (through
    34     * `domid`: value for the "id" attribute of the <form> tag
    59       :meth:`~cubicweb.web.request.Request.add_css`)
    35 
    60 
    36     * `action`: value for the "action" attribute of the <form> tag
    61     :attr:`domid`
    37 
    62       value for the "id" attribute of the <form> tag
    38     * `onsubmit`: value for the "onsubmit" attribute of the <form> tag
    63 
    39 
    64     :attr:`action`
    40     * `cssclass`: value for the "class" attribute of the <form> tag
    65       value for the "action" attribute of the <form> tag
    41 
    66 
    42     * `cssstyle`: value for the "style" attribute of the <form> tag
    67     :attr:`onsubmit`
    43 
    68       value for the "onsubmit" attribute of the <form> tag
    44     * `cwtarget`: value for the "cubicweb:target" attribute of the <form> tag
    69 
    45 
    70     :attr:`cssclass`
    46     * `redirect_path`: relative to redirect to after submitting the form
    71       value for the "class" attribute of the <form> tag
    47 
    72 
    48     * `copy_nav_params`: flag telling if navigation paramenters should be copied
    73     :attr:`cssstyle`
    49       back in hidden input
    74       value for the "style" attribute of the <form> tag
    50 
    75 
    51     * `form_buttons`:  form buttons sequence (button widgets instances)
    76     :attr:`cwtarget`
    52 
    77       value for the "cubicweb:target" attribute of the <form> tag
    53     * `form_renderer_id`: id of the form renderer to use to render the form
    78 
    54 
    79     :attr:`redirect_path`
    55     * `fieldsets_in_order`: fieldset name sequence, to control order
    80       relative to redirect to after submitting the form
       
    81 
       
    82     :attr:`copy_nav_params`
       
    83       flag telling if navigation parameters should be copied back in hidden
       
    84       inputs
       
    85 
       
    86     :attr:`form_buttons`
       
    87       sequence of form control (:class:`~cubicweb.web.formwidgets.Button`
       
    88       widgets instances)
       
    89 
       
    90     :attr:`form_renderer_id`
       
    91       identifier of the form renderer to use to render the form
       
    92 
       
    93     :attr:`fieldsets_in_order`
       
    94       sequence of fieldset names , to control order
       
    95 
       
    96     **Generic methods**
       
    97 
       
    98     .. automethod:: cubicweb.web.form.Form.field_by_name(name, role=None)
       
    99     .. automethod:: cubicweb.web.form.Form.fields_by_name(name, role=None)
       
   100 
       
   101     **Form construction methods**
       
   102 
       
   103     .. automethod:: cubicweb.web.form.Form.remove_field(field)
       
   104     .. automethod:: cubicweb.web.form.Form.append_field(field)
       
   105     .. automethod:: cubicweb.web.form.Form.insert_field_before(field, name, role=None)
       
   106     .. automethod:: cubicweb.web.form.Form.insert_field_after(field, name, role=None)
       
   107     .. automethod:: cubicweb.web.form.Form.add_hidden(name, value=None, **kwargs)
       
   108 
       
   109     **Form rendering methods**
       
   110 
       
   111     .. automethod:: cubicweb.web.views.forms.FieldsForm.render
       
   112 
    56     """
   113     """
    57     __regid__ = 'base'
   114     __regid__ = 'base'
    58 
   115 
    59 
   116 
    60     # attributes overrideable by subclasses or through __init__
   117     # attributes overrideable by subclasses or through __init__
    81             self._cw.add_js(self.needs_js)
   138             self._cw.add_js(self.needs_js)
    82         if self.needs_css:
   139         if self.needs_css:
    83             self._cw.add_css(self.needs_css)
   140             self._cw.add_css(self.needs_css)
    84 
   141 
    85     def render(self, formvalues=None, rendervalues=None, renderer=None, **kwargs):
   142     def render(self, formvalues=None, rendervalues=None, renderer=None, **kwargs):
    86         """render this form, using the renderer given in args or the default
   143         """Render this form, using the `renderer` given as argument or the
    87         FormRenderer()
   144         default according to :attr:`form_renderer_id`. The rendered form is
       
   145         returned as an unicode string.
       
   146 
       
   147         `formvalues` is an optional dictionary containing values that will be
       
   148         considered as field's value.
       
   149 
       
   150         Extra keyword arguments will be given to renderer's :meth:`render` method.
       
   151 
       
   152         `rendervalues` is deprecated.
    88         """
   153         """
    89         if rendervalues is not None:
   154         if rendervalues is not None:
    90             warn('[3.6] rendervalues argument is deprecated, all named arguments will be given instead',
   155             warn('[3.6] rendervalues argument is deprecated, all named arguments will be given instead',
    91                  DeprecationWarning, stacklevel=2)
   156                  DeprecationWarning, stacklevel=2)
    92             kwargs = rendervalues
   157             kwargs = rendervalues
   134 
   199 
   135 _AFF = uicfg.autoform_field
   200 _AFF = uicfg.autoform_field
   136 _AFF_KWARGS = uicfg.autoform_field_kwargs
   201 _AFF_KWARGS = uicfg.autoform_field_kwargs
   137 
   202 
   138 class EntityFieldsForm(FieldsForm):
   203 class EntityFieldsForm(FieldsForm):
       
   204     """This class is designed for forms used to edit some entities. It should
       
   205     handle for you all the underlying stuff necessary to properly work with the
       
   206     generic :class:`~cubicweb.web.views.editcontroller.EditController`.
       
   207     """
       
   208 
   139     __regid__ = 'base'
   209     __regid__ = 'base'
   140     __select__ = (match_kwargs('entity')
   210     __select__ = (match_kwargs('entity')
   141                   | (one_line_rset() & non_final_entity()))
   211                   | (one_line_rset() & non_final_entity()))
   142 
   212 
   143     internal_fields = FieldsForm.internal_fields + ('__type', 'eid', '__maineid')
   213     internal_fields = FieldsForm.internal_fields + ('__type', 'eid', '__maineid')
   253     def object_relation_vocabulary(self, rtype, limit=None):
   323     def object_relation_vocabulary(self, rtype, limit=None):
   254         return relvoc_unrelated(self.edited_entity, rtype, 'object', limit=None)
   324         return relvoc_unrelated(self.edited_entity, rtype, 'object', limit=None)
   255 
   325 
   256 
   326 
   257 class CompositeFormMixIn(object):
   327 class CompositeFormMixIn(object):
   258     """form composed of sub-forms"""
       
   259     __regid__ = 'composite'
   328     __regid__ = 'composite'
   260     form_renderer_id = __regid__
   329     form_renderer_id = __regid__
   261 
   330 
   262     def __init__(self, *args, **kwargs):
   331     def __init__(self, *args, **kwargs):
   263         super(CompositeFormMixIn, self).__init__(*args, **kwargs)
   332         super(CompositeFormMixIn, self).__init__(*args, **kwargs)
   273         for form in self.forms:
   342         for form in self.forms:
   274             form.build_context(formvalues)
   343             form.build_context(formvalues)
   275 
   344 
   276 
   345 
   277 class CompositeForm(CompositeFormMixIn, FieldsForm):
   346 class CompositeForm(CompositeFormMixIn, FieldsForm):
   278     pass
   347     """Form composed of sub-forms. Typical usage is edition of multiple entities
       
   348     at once.
       
   349     """
   279 
   350 
   280 class CompositeEntityForm(CompositeFormMixIn, EntityFieldsForm):
   351 class CompositeEntityForm(CompositeFormMixIn, EntityFieldsForm):
   281     pass # XXX why is this class necessary?
   352     pass # XXX why is this class necessary?