--- 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 ::
-
- <field name>:<entity eid>
-
-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-<relation name>` or `edito-<relation name>`
- 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
- <relation name> (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: ::
-
- <relation type>:<eids>:<target>
-
- where <target> 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: ::
-
- <ssubjects eids>:<relation type>:<objects eids>
-
- 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`.
-
--- /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 ::
+
+ <field name>:<entity eid>
+
+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-<relation name>` or `edito-<relation name>`
+ 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
+ <relation name> (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: ::
+
+ <relation type>:<eids>:<target>
+
+ where <target> 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: ::
+
+ <ssubjects eids>:<relation type>:<objects eids>
+
+ 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`.
--- /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'<table class="headersform">')
+ for field in fields:
+ if field.name == 'mailbody':
+ w(u'</table>')
+ w(u'<div id="toolbar">')
+ w(u'<ul>')
+ for button in form.form_buttons:
+ w(u'<li>%s</li>' % button.render(form))
+ w(u'</ul>')
+ w(u'</div>')
+ w(u'<div>')
+ w(field.render(form, self))
+ w(u'</div>')
+ else:
+ w(u'<tr>')
+ w(u'<td class="hlabel">%s</td>' % self.render_label(form, field))
+ w(u'<td class="hvalue">')
+ w(field.render(form, self))
+ w(u'</td></tr>')
+
+ 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
--- /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
--- 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'<table class="headersform">')
- for field in fields:
- if field.name == 'mailbody':
- w(u'</table>')
- w(u'<div id="toolbar">')
- w(u'<ul>')
- for button in form.form_buttons:
- w(u'<li>%s</li>' % button.render(form))
- w(u'</ul>')
- w(u'</div>')
- w(u'<div>')
- w(field.render(form, self))
- w(u'</div>')
- else:
- w(u'<tr>')
- w(u'<td class="hlabel">%s</td>' % self.render_label(form, field))
- w(u'<td class="hvalue">')
- w(field.render(form, self))
- w(u'</td></tr>')
-
- 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
--- 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
--- 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
--- 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