# HG changeset patch # User Aurelien Campeas # Date 1272964158 -7200 # Node ID 6e561796804ca91ca100402ac9b2addf94b6150f # Parent a5b96b98242c28d572940b30ca4dcacafc00480e [doc/book] regroup form/editcontroller stuff under an "edition control" chapter diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/controllers.rst --- a/doc/book/en/devweb/controllers.rst Tue May 04 11:04:54 2010 +0200 +++ b/doc/book/en/devweb/controllers.rst Tue May 04 11:09:18 2010 +0200 @@ -36,16 +36,16 @@ operations in response to a form being submitted; it works in close association with the Forms, to which it delegates some of the work -* the Form validator controller provides form validation from Ajax +* the ``Form validator controller`` provides form validation from Ajax context, using the Edit controller, to implement the classic form - handling loop (user edits, hits 'submit/apply', validation occurs + handling loop (user edits, hits `submit/apply`, validation occurs server-side by way of the Form validator controller, and the UI is decorated with failure information, either global or per-field , until it is valid) `Other`: -* the SendMail controller (web/views/basecontrollers.py) is reponsible +* the ``SendMail controller`` (web/views/basecontrollers.py) is reponsible for outgoing email notifications * the MailBugReport controller (web/views/basecontrollers.py) allows @@ -57,14 +57,16 @@ All controllers (should) live in the 'controllers' namespace within the global registry. -API -+++ +Concrete controllers +++++++++++++++++++++ Most API details should be resolved by source code inspection, as the -various controllers have differing goals. +various controllers have differing goals. See for instance the +:ref:`edit_controller` chapter. -`web/controller.py` contains the top-level abstract Controller class and -its (NotImplemented) entry point `publish(rset=None)` method. +:mod:`cubicweb.web.controller` contains the top-level abstract +Controller class and its unimplemented entry point +`publish(rset=None)` method. A handful of helpers are also provided there: @@ -77,125 +79,3 @@ implementations dealing with HTTP (thus, for instance, not the SendMail controller) may very well call this in their publication process. - - -.. _edit_controller: - -The `edit controller` -+++++++++++++++++++++ - -It can be found in (:mod:`cubicweb.web.views.editcontroller`). - -Editing control -~~~~~~~~~~~~~~~~ - -.. XXX this look obsolete - -The parameters related to entities to edit are specified as follows :: - - : - -where entity eid could be a letter in case of an entity to create. We -name those parameters as *qualified*. - -1. Retrieval of entities to edit by looking for the forms parameters - starting by `eid:` and also having a parameter `__type` associated - (also *qualified* by eid) - -2. For all the attributes and the relations of an entity to edit: - - 1. search for a parameter `edits-` or `edito-` - qualified in the case of a relation where the entity is object - 2. if found, the value returned is considered as the initial value - for this relaiton and we then look for the new value(s) in the parameter - (qualified) - 3. if the value returned is different from the initial value, an database update - request is done - -3. For each entity to edit: - - 1. if a qualified parameter `__linkto` is specified, its value has to be - a string (or a list of string) such as: :: - - :: - - where is either `subject` or `object` and each eid could be - separated from the others by a `_`. Target specifies if the *edited entity* - is subject or object of the relation and each relation specified will - be inserted. - - 2. if a qualified parameter `__clone_eid` is specified for an entity, the - relations of the specified entity passed as value of this parameter are - copied on the edited entity. - - 3. if a qualified parameter `__delete` is specified, its value must be - a string or a list of string such as follows: :: - - :: - - where each eid subject or object can be seperated from the other - by `_`. Each relation specified will be deleted. - - 4. if a qualified parameter `__insert` is specified, its value should - follow the same pattern as `__delete`, but each relation specified is - inserted. - -4. If the parameters `__insert` and/or `__delete` are found not qualified, - they are interpreted as explained above (independantly from the number - of entities edited). - -5. If no entity is edited but the form contains the parameters `__linkto` - and `eid`, this one is interpreted by using the value specified for `eid` - to designate the entity on which to add the relations. - - -.. note:: - - * If the parameter `__action_delete` is found, all the entities specified - as to be edited will be deleted. - - * If the parameter `__action_cancel` is found, no action is completed. - - * If the parameter `__action_apply` is found, the editing is - applied normally but the redirection is done on the form (see - :ref:`RedirectionControl`). - - * The parameter `__method` is also supported as for the main template - - * If no entity is found to be edited and if there is no parameter - `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or - `__insert`, an error is raised. - - * Using the parameter `__message` in the form will allow to use its value - as a message to provide the user once the editing is completed. - - -.. _RedirectionControl: - -Redirection control -~~~~~~~~~~~~~~~~~~~ -Once editing is completed, there is still an issue left: where should we go -now? If nothing is specified, the controller will do his job but it does not -mean we will be happy with the result. We can control that by using the -following parameters: - -* `__redirectpath`: path of the URL (relative to the root URL of the site, - no form parameters - -* `__redirectparams`: forms parameters to add to the path - -* `__redirectrql`: redirection RQL request - -* `__redirectvid`: redirection view identifier - -* `__errorurl`: initial form URL, used for redirecting in case a validation - error is raised during editing. If this one is not specified, an error page - is displayed instead of going back to the form (which is, if necessary, - responsible for displaying the errors) - -* `__form_id`: initial view form identifier, used if `__action_apply` is - found - -In general we use either `__redirectpath` and `__redirectparams` or -`__redirectrql` and `__redirectvid`. - diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/edition/editcontroller.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/devweb/edition/editcontroller.rst Tue May 04 11:09:18 2010 +0200 @@ -0,0 +1,117 @@ +.. _edit_controller: + +The `edit controller` ++++++++++++++++++++++ + +It can be found in (:mod:`cubicweb.web.views.editcontroller`). + +Editing control +~~~~~~~~~~~~~~~~ + +.. XXX this look obsolete + +The parameters related to entities to edit are specified as follows :: + + : + +where entity eid could be a letter in case of an entity to create. We +name those parameters as *qualified*. + +1. Retrieval of entities to edit by looking for the forms parameters + starting by `eid:` and also having a parameter `__type` associated + (also *qualified* by eid) + +2. For all the attributes and the relations of an entity to edit: + + 1. search for a parameter `edits-` or `edito-` + qualified in the case of a relation where the entity is object + 2. if found, the value returned is considered as the initial value + for this relaiton and we then look for the new value(s) in the parameter + (qualified) + 3. if the value returned is different from the initial value, an database update + request is done + +3. For each entity to edit: + + 1. if a qualified parameter `__linkto` is specified, its value has to be + a string (or a list of string) such as: :: + + :: + + where is either `subject` or `object` and each eid could be + separated from the others by a `_`. Target specifies if the *edited entity* + is subject or object of the relation and each relation specified will + be inserted. + + 2. if a qualified parameter `__clone_eid` is specified for an entity, the + relations of the specified entity passed as value of this parameter are + copied on the edited entity. + + 3. if a qualified parameter `__delete` is specified, its value must be + a string or a list of string such as follows: :: + + :: + + where each eid subject or object can be seperated from the other + by `_`. Each relation specified will be deleted. + + 4. if a qualified parameter `__insert` is specified, its value should + follow the same pattern as `__delete`, but each relation specified is + inserted. + +4. If the parameters `__insert` and/or `__delete` are found not qualified, + they are interpreted as explained above (independantly from the number + of entities edited). + +5. If no entity is edited but the form contains the parameters `__linkto` + and `eid`, this one is interpreted by using the value specified for `eid` + to designate the entity on which to add the relations. + + +.. note:: + + * if the parameter `__action_delete` is found, all the entities specified + as to be edited will be deleted. + + * if the parameter `__action_cancel` is found, no action is completed. + + * if the parameter `__action_apply` is found, the editing is + applied normally but the redirection is done on the form (see + :ref:`RedirectionControl`). + + * if no entity is found to be edited and if there is no parameter + `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or + `__insert`, an error is raised. + + * using the parameter `__message` in the form will allow to use its value + as a message to provide the user once the editing is completed. + + +.. _RedirectionControl: + +Redirection control +~~~~~~~~~~~~~~~~~~~ +Once editing is completed, there is still an issue left: where should we go +now? If nothing is specified, the controller will do his job but it does not +mean we will be happy with the result. We can control that by using the +following parameters: + +* `__redirectpath`: path of the URL (relative to the root URL of the site, + no form parameters + +* `__redirectparams`: forms parameters to add to the path + +* `__redirectrql`: redirection RQL request + +* `__redirectvid`: redirection view identifier + +* `__errorurl`: initial form URL, used for redirecting in case a validation + error is raised during editing. If this one is not specified, an error page + is displayed instead of going back to the form (which is, if necessary, + responsible for displaying the errors) + +* `__form_id`: initial view form identifier, used if `__action_apply` is + found + +In general we use either `__redirectpath` and `__redirectparams` or +`__redirectrql` and `__redirectvid`. diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/edition/form.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/devweb/edition/form.rst Tue May 04 11:09:18 2010 +0200 @@ -0,0 +1,220 @@ +HTML form construction +---------------------- + +CubicWeb provides the somewhat usual form / field / widget / renderer abstraction +to provide generic building blocks which will greatly help you in building forms +properly integrated with CubicWeb (coherent display, error handling, etc...), +while keeping things as flexible as possible. + +A ``form`` basically only holds a set of ``fields``, and has te be bound to a +``renderer`` which is responsible to layout them. Each field is bound to a +``widget`` that will be used to fill in value(s) for that field (at form +generation time) and 'decode' (fetch and give a proper Python type to) values +sent back by the browser. + +The ``field`` should be used according to the type of what you want to edit. +E.g. if you want to edit some date, you'll have to use the +:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple +widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a +bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple +calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery +calendar). You can of course also write your own widget. + + +.. automodule:: cubicweb.web.views.autoform + + +Example of ad-hoc fields form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We want to define a form doing something else than editing an entity. The idea is +to propose a form to send an email to entities in a resultset which implements +:class:`IEmailable`. Let's take a simplified version of what you'll find in +:mod:`cubicweb.web.views.massmailing`. + +Here is the source code: + +.. sourcecode:: python + + def sender_value(form): + return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email()) + + def recipient_choices(form, field): + return [(e.get_email(), e.eid) + for e in form.cw_rset.entities() + if e.get_email()] + + def recipient_value(form): + return [e.eid for e in form.cw_rset.entities() + if e.get_email()] + + class MassMailingForm(forms.FieldsForm): + __regid__ = 'massmailing' + + needs_js = ('cubicweb.widgets.js',) + domid = 'sendmail' + action = 'sendmail' + + sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}), + label=_('From:'), + value=sender_value) + + recipient = ff.StringField(widget=CheckBox(), + label=_('Recipients:'), + choices=recipient_choices, + value=recipients_value) + + subject = ff.StringField(label=_('Subject:'), max_length=256) + + mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField', + inputid='mailbody')) + + form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()", + _('send email'), 'SEND_EMAIL_ICON'), + ImgButton('cancelbutton', "javascript: history.back()", + stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')] + +Let's detail what's going on up there. Our form will hold four fields: + +* a sender field, which is disabled and will simply contains the user's name and + email + +* a recipients field, which will be displayed as a list of users in the context + result set with checkboxes so user can still choose who will receive his mailing + by checking or not the checkboxes. By default all of them will be checked since + field's value return a list containing same eids as those returned by the + vocabulary function. + +* a subject field, limited to 256 characters (hence we know a + :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in + :class:`~cubicweb.web.formfields.StringField`) + +* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`, + and whose definition won't be shown here. Notice though that we tell this form + need this javascript file by using `needs_js` + +Last but not least, we add two buttons control: one to post the form using +javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id +set to 'sendmail', which is our form DOM id as specified by its `domid` +attribute), another to cancel the form which will go back to the previous page +using another javascript call. Also we specify an image to use as button icon as a +resource identifier (see :ref:`external_resources`) given as last argument to +:class:`cubicweb.web.formwidgets.ImgButton`. + +To see this form, we still have to wrap it in a view. This is pretty simple: + +.. sourcecode:: python + + class MassMailingFormView(form.FormViewMixIn, EntityView): + __regid__ = 'massmailing' + __select__ = implements(IEmailable) & authenticated_user() + + def call(self): + form = self._cw.vreg['forms'].select('massmailing', self._cw, + rset=self.cw_rset) + self.w(form.render()) + +As you see, we simply define a view with proper selector so it only apply to a +result set containing :class:`IEmailable` entities, and so that only users in the +managers or users group can use it. Then in the `call()` method for this view we +simply select the above form and write what its `.render()` method returns. + +When this form is submitted, a controller with id 'sendmail' will be called (as +specified using `action`). This controller will be responsible to actually send +the mail to specified recipients. + +Here is what it looks like: + +.. sourcecode:: python + + class SendMailController(Controller): + __regid__ = 'sendmail' + __select__ = (authenticated_user() & + match_form_params('recipient', 'mailbody', 'subject')) + + def publish(self, rset=None): + body = self._cw.form['mailbody'] + subject = self._cw.form['subject'] + eids = self._cw.form['recipient'] + # eids may be a string if only one recipient was specified + if isinstance(eids, basestring): + rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids}) + else: + rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids))) + recipients = list(rset.entities()) + msg = format_mail({'email' : self._cw.user.get_email(), + 'name' : self._cw.user.dc_title()}, + recipients, body, subject) + if not self._cw.vreg.config.sendmails([(msg, recipients]): + msg = self._cw._('could not connect to the SMTP server') + else: + msg = self._cw._('emails successfully sent') + raise Redirect(self._cw.build_url(__message=msg)) + + +The entry point of a controller is the publish method. In that case we simply get +back post values in request's `form` attribute, get user instances according +to eids found in the 'recipient' form value, and send email after calling +:func:`format_mail` to get a proper email message. If we can't send email or +if we successfully sent email, we redirect to the index page with proper message +to inform the user. + +Also notice that our controller has a selector that deny access to it +to anonymous users (we don't want our instance to be used as a spam +relay), but also checks if the expected parameters are specified in +forms. That avoids later defensive programming (though it's not enough +to handle all possible error cases). + +To conclude our example, suppose we wish a different form layout and that existent +renderers are not satisfying (we would check that first of course :). We would then +have to define our own renderer: + +.. sourcecode:: python + + class MassMailingFormRenderer(formrenderers.FormRenderer): + __regid__ = 'massmailing' + + def _render_fields(self, fields, w, form): + w(u'') + for field in fields: + if field.name == 'mailbody': + w(u'
') + w(u'
') + w(u'
    ') + for button in form.form_buttons: + w(u'
  • %s
  • ' % button.render(form)) + w(u'
') + w(u'
') + w(u'
') + w(field.render(form, self)) + w(u'
') + else: + w(u'') + w(u'%s' % self.render_label(form, field)) + w(u'') + w(field.render(form, self)) + w(u'') + + def render_buttons(self, w, form): + pass + +We simply override the `_render_fields` and `render_buttons` method of the base form renderer +to arrange fields as we desire it: here we'll have first a two columns table with label and +value of the sender, recipients and subject field (form order respected), then form controls, +then a div containing the textarea for the email's content. + +To bind this renderer to our form, we should add to our form definition above: + +.. sourcecode:: python + + form_renderer_id = 'massmailing' + +API +~~~ + +.. automodule:: cubicweb.web.formfields +.. automodule:: cubicweb.web.formwidgets +.. automodule:: cubicweb.web.views.forms +.. automodule:: cubicweb.web.views.formrenderers + +.. Example of entity fields form diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/edition/index.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/devweb/edition/index.rst Tue May 04 11:09:18 2010 +0200 @@ -0,0 +1,13 @@ +Edition control +=============== + +This chapter covers the editing capabilities of |cubicweb|. It +explains html Form construction, the Edit Controller and their +interactions. + + +.. toctree:: + :maxdepth: 2 + + form + editcontroller diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/form.rst --- a/doc/book/en/devweb/form.rst Tue May 04 11:04:54 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -HTML form construction ----------------------- - -CubicWeb provides the somewhat usual form / field / widget / renderer abstraction -to provide generic building blocks which will greatly help you in building forms -properly integrated with CubicWeb (coherent display, error handling, etc...), -while keeping things as flexible as possible. - -A **form** basically only holds a set of **fields**, and has te be bound to a -**renderer** which is responsible to layout them. Each field is bound to a -**widget** that will be used to fill in value(s) for that field (at form -generation time) and 'decode' (fetch and give a proper Python type to) values -sent back by the browser. - -The **field** should be used according to the type of what you want to edit. -E.g. if you want to edit some date, you'll have to use the -:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple -widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a -bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple -calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery -calendar). You can of course also write your own widget. - - -.. automodule:: cubicweb.web.views.autoform - - -Example of bare fields form -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We want to define a form doing something else than editing an entity. The idea is -to propose a form to send an email to entities in a resultset which implements -:class:`IEmailable`. Let's take a simplified version of what you'll find in -:mod:`cubicweb.web.views.massmailing`. - -Here is the source code: - -.. sourcecode:: python - - def sender_value(form): - return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email()) - - def recipient_choices(form, field): - return [(e.get_email(), e.eid) for e in form.cw_rset.entities() - if e.get_email()] - - def recipient_value(form): - return [e.eid for e in form.cw_rset.entities() if e.get_email()] - - class MassMailingForm(forms.FieldsForm): - __regid__ = 'massmailing' - - needs_js = ('cubicweb.widgets.js',) - domid = 'sendmail' - action = 'sendmail' - - sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}), - label=_('From:'), - value=sender_value) - - recipient = ff.StringField(widget=CheckBox(), - label=_('Recipients:'), - choices=recipient_choices, - value=recipients_value) - - subject = ff.StringField(label=_('Subject:'), max_length=256) - - mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField', - inputid='mailbody')) - - form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()", - _('send email'), 'SEND_EMAIL_ICON'), - ImgButton('cancelbutton', "javascript: history.back()", - stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')] - -Let's detail what's going on up there. Our form will hold four fields: - -* a sender field, which is disabled and will simply contains the user's name and - email - -* a recipients field, which will be displayed as a list of users in the context - result set with checkboxes so user can still choose who will receive his mailing - by checking or not the checkboxes. By default all of them will be checked since - field's value return a list containing same eids as those returned by the - vocabulary function. - -* a subject field, limited to 256 characters (hence we know a - :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in - :class:`~cubicweb.web.formfields.StringField`) - -* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`, - and whose definition won't be shown here. Notice though that we tell this form - need this javascript file by using `needs_js` - -Last but not least, we add two buttons control: one to post the form using -javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id -set to 'sendmail', which is our form DOM id as specified by its `domid` -attribute), another to cancel the form which will go back to the previous page -using another javascript call. Also we specify an image to use as button icon as a -resource identifier (see :ref:`external_resources`) given as last argument to -:class:`cubicweb.web.formwidgets.ImgButton`. - -To see this form, we still have to wrap it in a view. This is pretty simple: - -.. sourcecode:: python - - class MassMailingFormView(form.FormViewMixIn, EntityView): - __regid__ = 'massmailing' - __select__ = implements(IEmailable) & authenticated_user() - - def call(self): - form = self._cw.vreg['forms'].select('massmailing', self._cw, - rset=self.cw_rset) - self.w(form.render()) - -As you see, we simply define a view with proper selector so it only apply to a -result set containing :class:`IEmailable` entities, and so that only users in the -managers or users group can use it. Then in the `call()` method for this view we -simply select the above form and write what its `.render()` method returns. - -When this form is submitted, a controller with id 'sendmail' will be called (as -specified using `action`). This controller will be responsible to actually send -the mail to specified recipients. - -Here is what it looks like: - -.. sourcecode:: python - - class SendMailController(Controller): - __regid__ = 'sendmail' - __select__ = authenticated_user() & match_form_params('recipient', 'mailbody', 'subject') - - def publish(self, rset=None): - body = self._cw.form['mailbody'] - subject = self._cw.form['subject'] - eids = self._cw.form['recipient'] - # eids may be a string if only one recipient was specified - if isinstance(eids, basestring): - rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids}) - else: - rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids))) - recipients = list(rset.entities()) - msg = format_mail({'email' : self._cw.user.get_email(), - 'name' : self._cw.user.dc_title()}, - recipients, body, subject) - if not self._cw.vreg.config.sendmails([(msg, recipients]): - msg = self._cw._('could not connect to the SMTP server') - else: - msg = self._cw._('emails successfully sent') - raise Redirect(self._cw.build_url(__message=msg)) - - -The entry point of a controller is the publish method. In that case we simply get -back post values in request's `form` attribute, get user instances according -to eids found in the 'recipient' form value, and send email after calling -:func:`format_mail` to get a proper email message. If we can't send email or -if we successfully sent email, we redirect to the index page with proper message -to inform the user. - -Also notice that our controller has a selector that deny access to it to -anonymous users (we don't want our instance to be used as a spam relay), but also -check expected parameters are specified in forms. That avoids later defensive -programming (though it's not enough to handle all possible error cases). - -To conclude our example, suppose we wish a different form layout and that existent -renderers are not satisfying (we would check that first of course :). We would then -have to define our own renderer: - -.. sourcecode:: python - - class MassMailingFormRenderer(formrenderers.FormRenderer): - __regid__ = 'massmailing' - - def _render_fields(self, fields, w, form): - w(u'') - for field in fields: - if field.name == 'mailbody': - w(u'
') - w(u'
') - w(u'
    ') - for button in form.form_buttons: - w(u'
  • %s
  • ' % button.render(form)) - w(u'
') - w(u'
') - w(u'
') - w(field.render(form, self)) - w(u'
') - else: - w(u'') - w(u'%s' % self.render_label(form, field)) - w(u'') - w(field.render(form, self)) - w(u'') - - def render_buttons(self, w, form): - pass - -We simply override the `_render_fields` and `render_buttons` method of the base form renderer -to arrange fields as we desire it: here we'll have first a two columns table with label and -value of the sender, recipients and subject field (form order respected), then form controls, -then a div containing the textarea for the email's content. - -To bind this renderer to our form, we should add to our form definition above: - -.. sourcecode:: python - - form_renderer_id = 'massmailing' - -API -~~~ - -.. automodule:: cubicweb.web.formfields -.. automodule:: cubicweb.web.formwidgets -.. automodule:: cubicweb.web.views.forms -.. automodule:: cubicweb.web.views.formrenderers - -.. Example of entity fields form diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/index.rst --- a/doc/book/en/devweb/index.rst Tue May 04 11:04:54 2010 +0200 +++ b/doc/book/en/devweb/index.rst Tue May 04 11:09:18 2010 +0200 @@ -14,7 +14,7 @@ rtags js css - form + edition/index facets internationalization .. property diff -r a5b96b98242c -r 6e561796804c doc/book/en/devweb/views/editforms.rst --- a/doc/book/en/devweb/views/editforms.rst Tue May 04 11:04:54 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -Standard forms --------------- - - (:mod:`cubicweb.web.views.editforms`) - -XXX feed me diff -r a5b96b98242c -r 6e561796804c req.py --- a/req.py Tue May 04 11:04:54 2010 +0200 +++ b/req.py Tue May 04 11:09:18 2010 +0200 @@ -106,10 +106,7 @@ return rset def empty_rset(self): - """return a result set for the given eid without doing actual query - (we have the eid, we can suppose it exists and user has access to the - entity) - """ + """ return a guaranteed empty result """ rset = ResultSet([], 'Any X WHERE X eid -1') rset.req = self return rset