# HG changeset patch # User Aurelien Campeas # Date 1272993419 -7200 # Node ID c6c9a80ad1dd610a1409c7269551407723c30e8d # Parent 37a2455639b986464b5756e06d8c5fe06fab1452 [doc/book] dissection of a form chapter diff -r 37a2455639b9 -r c6c9a80ad1dd doc/book/en/devweb/edition/dissection.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/devweb/edition/dissection.rst Tue May 04 19:16:59 2010 +0200 @@ -0,0 +1,276 @@ + +Dissection of a Form +-------------------- + +This is done (again) with a vanilla instance of the `tracker`_ +cube. We will populate the database with a bunch of entities and see +what kind of job the automatic entity form does. + +.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker + +Patching the session object +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to play interactively with web side application objects, we +have to cheat a bit: we will decorate the session object with some +missing artifacts that should belong to a web request object. With +that we can instantiate and render forms interactively. + +The function below does the minimum to allow going through this +exercice. Some attributes or methods may be missing for other +purposes. It is nevertheless not complicated to enhance it if need +arises. + +.. sourcecode:: python + + def monkey_patch_session(session): + """ useful to use the cw shell session object + with web appobjects, which expect more than a plain + data repository session + """ + # for autoform selection + session.json_request = False + session.url = lambda: u'http://perdu.com' + session.session = session + session.form = {} + session.list_form_param = lambda *args: [] + # for render + session.use_fckeditor = lambda: False + session._ressources = [] + session.add_js = session.add_css = lambda *args: session._ressources.append(args) + session.external_resource = lambda x:{} + session._tabcount = 0 + def next_tabindex(): + session._tabcount += 1 + return session._tabcount + session.next_tabindex = next_tabindex + return session + +Populating the database +~~~~~~~~~~~~~~~~~~~~~~~ + +We should start by setting up a bit of context: a project with two +unpublished versions, and a ticket linked to the project and the first +version. + +.. sourcecode:: python + + >>> p = rql('INSERT Project P: P name "cubicweb"') + >>> for num in ('0.1.0', '0.2.0'): + ... rql('INSERT Version V: V num "%s", V version_of P WHERE P eid %%(p)s' % num, {'p': p[0][0]}) + ... + + + >>> t = rql('INSERT Ticket T: T title "let us write more doc", T done_in V, ' + 'T concerns P WHERE V num "0.1.0"', P eid %(p)s', {'p': p[0][0]}) + >>> commit() + +Now let's see what the edition form builds for us. + +.. sourcecode:: python + + >>> monkey_patch_session(session) + >>> form = session.vreg['forms'].select('edition', session, rset=rql('Ticket T')) + >>> html = form.render() + +This creates an automatic entity form. The ``.render()`` call yields +an html (unicode) string. The html output is shown below (with +internal fieldset omitted). + +Looking at the html output +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The form enveloppe +'''''''''''''''''' + +.. sourcecode:: html + +
main informations
+
+
+
validating...
+
+ + + + + + + + ... +
+
+
+ +The main fieldset encloses a set of hidden fields containing various +metadata, that will be used by the `edit controller` to process it +back correctly. + +The `freezeFormButtons(...)` javascript callback defined on the +``conlick`` event of the form element prevents accidental multiple +clicks in a row. + +The ``action`` of the form is mapped to the `validateform` controller +(situated in :mod:`cubicweb.web.views.basecontrollers`). + +The attributes section +'''''''''''''''''''''' + +We can have a look at some of the inner nodes of the form. Some fields +are omitted as they are redundant for our purposes. + +.. sourcecode:: html + +
+ + + + + + ... (description field omitted) ... + + + + + ... (type field omitted) ... + + + + + + + + +
+ +
+ +
importance
+
+ +
+ +
version in which this ticket will be / has been done
+
+
+ + +Note that the whole form layout has been computed by the form +renderer. It is the renderer which produces the table +structure. Otherwise, the fields html structure is emitted by their +associated widget. + +While it is called the `attributes` section of the form, it actually +contains attributes and *mandatory relations*. For each field, we +observe: + +* a dedicated row with a specific class, such as ``title_subject_row`` + (responsability of the form renderer) + +* an html widget (input, select, ...) with: + + * an id built from the ``rtype-role:eid`` pattern + + * a name built from the same pattern + + * possible values or preselected options + +The relations section +''''''''''''''''''''' + +.. sourcecode:: html + +
+ This ticket : + + + + +
+ + + + + + +
  
+ +
+
+
+ +The optional relations are grouped into a drop-down combo +box. Selection of an item triggers a javascript function which will: + +* show already related entities in the div of id `relatedentities` + using a two-colown layout, with an action to allow deletion of + individual relations (there are none in this example) + +* provide a relation selector in the div of id `relationSelector_EID` + to allow the user to set up relations and trigger dynamic action on + the last div + +* fill the div of id `unrelatedDivs_EID` with a dynamically computed + selection widget allowing direct selection of an unrelated (but + relatable) entity or a switch towards the `search mode` of + |cubicweb| which allows full browsing and selection of an entity + using a dedicated action situated in the left column boxes. + + +The buttons zone +'''''''''''''''' + +Finally comes the buttons zone. + +.. sourcecode:: html + + + + + + + + +
+ + + + +
+ +The most notable artifacts here are the ``postForm(...)`` calls +defined on click events on these buttons. This function basically +submits the form. XXX validateform vs validateForm, ajax or not ? diff -r 37a2455639b9 -r c6c9a80ad1dd doc/book/en/devweb/edition/form.rst --- a/doc/book/en/devweb/edition/form.rst Tue May 04 16:14:33 2010 +0200 +++ b/doc/book/en/devweb/edition/form.rst Tue May 04 19:16:59 2010 +0200 @@ -20,6 +20,38 @@ calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery calendar). You can of course also write your own widget. +Exploring the available forms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A small excursion into a |cubicweb| shell is the quickest way to +discover available forms (or application objects in general). + +.. sourcecode:: python + + >>> from pprint import pprint + >>> pprint( session.vreg['forms'] ) + {'base': [, + ], + 'changestate': [, + ], + 'composite': [, + ], + 'deleteconf': [], + 'edition': [, + , + ], + 'logform': [], + 'massmailing': [], + 'muledit': [], + 'sparql': []} + + +The two most important form families here (for all pracitcal purposes) +are `base` and `edition`. Most of the time one wants alterations of +the AutomaticEntityForm (from the `edition` category). + +The Automatic Entity Form +~~~~~~~~~~~~~~~~~~~~~~~~~ .. automodule:: cubicweb.web.views.autoform @@ -182,6 +214,7 @@ course, we take care *not* to provide a version the ticket is already linked to (through ``done_in``). + APIs ~~~~ diff -r 37a2455639b9 -r c6c9a80ad1dd doc/book/en/devweb/edition/index.rst --- a/doc/book/en/devweb/edition/index.rst Tue May 04 16:14:33 2010 +0200 +++ b/doc/book/en/devweb/edition/index.rst Tue May 04 19:16:59 2010 +0200 @@ -10,5 +10,6 @@ :maxdepth: 2 form + dissection editcontroller examples diff -r 37a2455639b9 -r c6c9a80ad1dd web/views/autoform.py --- a/web/views/autoform.py Tue May 04 16:14:33 2010 +0200 +++ b/web/views/autoform.py Tue May 04 19:16:59 2010 +0200 @@ -16,9 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """ -The automatic entity form -------------------------- - .. autodocstring:: cubicweb.web.views.autoform::AutomaticEntityForm Configuration through uicfg diff -r 37a2455639b9 -r c6c9a80ad1dd web/views/forms.py --- a/web/views/forms.py Tue May 04 16:14:33 2010 +0200 +++ b/web/views/forms.py Tue May 04 19:16:59 2010 +0200 @@ -25,8 +25,8 @@ using a form renderer. No display is actually done here, though you'll find some attributes of form that are used to control the rendering process. -Besides the automagic form we'll see later, they are barely two form -classes in |cubicweb|: +Besides the automagic form we'll see later, there are roughly two main +form classes in |cubicweb|: .. autoclass:: cubicweb.web.views.forms.FieldsForm .. autoclass:: cubicweb.web.views.forms.EntityFieldsForm