doc/book/en/devweb/edition/form.rst
author Aurelien Campeas <aurelien.campeas@logilab.fr>
Tue, 04 May 2010 15:46:36 +0200
branchstable
changeset 5462 a37127c8bf23
parent 5418 doc/book/en/devweb/form.rst@4f0047cfecb5
permissions -rw-r--r--
[doc/book] copious choices example
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
     1
HTML form construction
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
     2
----------------------
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     3
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
     4
CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
     5
to provide generic building blocks which will greatly help you in building forms
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
     6
properly integrated with CubicWeb (coherent display, error handling, etc...),
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
     7
while keeping things as flexible as possible.
4443
83ff2bb898a5 start documenting forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
     8
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
     9
A ``form`` basically only holds a set of ``fields``, and has te be bound to a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    10
``renderer`` which is responsible to layout them. Each field is bound to a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    11
``widget`` that will be used to fill in value(s) for that field (at form
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    12
generation time) and 'decode' (fetch and give a proper Python type to) values
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    13
sent back by the browser.
4443
83ff2bb898a5 start documenting forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
    14
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    15
The ``field`` should be used according to the type of what you want to edit.
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    16
E.g. if you want to edit some date, you'll have to use the
5400
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
    17
:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
    18
widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    19
bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    20
calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    21
calendar).  You can of course also write your own widget.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    22
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    23
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
    24
.. automodule:: cubicweb.web.views.autoform
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    25
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    26
Anatomy of a choices function
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    27
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    28
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    29
Let's have a look at the `ticket_done_in_choices` function given to
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    30
the `choices` parameter of the relation tag that is applied to the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    31
('Ticket', 'done_in', '*') relation definition, as it is both typical
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    32
and sophisticated enough. This is a code snippet from the `tracker`_
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    33
cube.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    34
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    35
.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    36
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    37
The ``Ticket`` entity type can be related to a ``Project`` and a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    38
``Version``, respectively through the ``concerns`` and ``done_in``
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    39
relations. When a user is about to edit a ticket, we want to fill the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    40
combo box for the ``done_in`` relation with values pertinent with
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    41
respect to the context. The important context here is:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    42
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    43
* creation or modification (we cannot fetch values the same way in
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    44
  either case)
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    45
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    46
* ``__linkto`` url parameter given in a creation context
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    47
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    48
.. sourcecode:: python
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    49
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    50
    from cubicweb.web import formfields
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    51
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    52
    def ticket_done_in_choices(form, field):
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    53
        entity = form.edited_entity
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    54
        # first see if its specified by __linkto form parameters
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    55
        linkedto = formfields.relvoc_linkedto(entity, 'done_in', 'subject')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    56
        if linkedto:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    57
            return linkedto
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    58
        # it isn't, get initial values
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    59
        vocab = formfields.relvoc_init(entity, 'done_in', 'subject')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    60
        veid = None
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    61
        # try to fetch the (already or pending) related version and project
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    62
        if not entity.has_eid():
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    63
            peids = entity.linked_to('concerns', 'subject')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    64
            peid = peids and peids[0]
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    65
        else:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    66
            peid = entity.project.eid
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    67
            veid = entity.done_in and entity.done_in[0].eid
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    68
        if peid:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    69
            # we can complete the vocabulary with relevant values
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    70
            rschema = form._cw.vreg.schema['done_in'].rdef('Ticket', 'Version')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    71
            rset = form._cw.execute(
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    72
                'Any V, VN ORDERBY version_sort_value(VN) '
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    73
                'WHERE V version_of P, P eid %(p)s, V num VN, '
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    74
                'V in_state ST, NOT ST name "published"', {'p': peid}, 'p')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    75
            vocab += [(v.view('combobox'), v.eid) for v in rset.entities()
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    76
                      if rschema.has_perm(form._cw, 'add', toeid=v.eid)
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    77
                      and v.eid != veid]
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    78
        return vocab
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    79
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    80
The first thing we have to do is fetch potential values from the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    81
``__linkto`` url parameter that is often found in entity creation
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    82
contexts (the creation action provides such a parameter with a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    83
predetermined value; for instance in this case, ticket creation could
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    84
occur in the context of a `Version` entity). The
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    85
:mod:`cubicweb.web.formfields` module provides a ``relvoc_linkedto``
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    86
utility function that gets a list suitably filled with vocabulary
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    87
values.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    88
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    89
.. sourcecode:: python
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    90
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    91
        linkedto = formfields.relvoc_linkedto(entity, 'done_in', 'subject')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    92
        if linkedto:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    93
            return linkedto
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    94
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    95
Then, if no ``__linkto`` argument was given, we must prepare the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    96
vocabulary with an initial empty value (because `done_in` is not
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    97
mandatory, we must allow the user to not select a verson) and already
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    98
linked values. This is done with the ``relvoc_init`` function.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
    99
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   100
.. sourcecode:: python
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   101
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   102
        vocab = formfields.relvoc_init(entity, 'done_in', 'subject')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   103
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   104
But then, we have to give more: if the ticket is related to a project,
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   105
we should provide all the non published versions of this project
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   106
(`Version` and `Project` can be related through the `version_of`
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   107
relation). Conversely, if we do not know yet the project, it would not
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   108
make sense to propose all existing versions as it could potentially
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   109
lead to incoherences. Even if these will be caught by some
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   110
RQLConstraint, it is wise not to tempt the user with error-inducing
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   111
candidate values.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   112
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   113
The "ticket is related to a project" part must be decomposed as:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   114
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   115
* this is a new ticket which is created is the context of a project
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   116
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   117
* this is an already existing ticket, linked to a project (through the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   118
  `concerns` relation)
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   119
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   120
* there is no related project (quite unlikely given the cardinality of
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   121
  the `concerns` relation, so it can only mean that we are creating a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   122
  new ticket, and a project is about to be selected but there is no
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   123
  ``__linkto`` argument)
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   124
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   125
.. note::
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   126
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   127
   the last situation could happen in several ways, but of course in a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   128
   polished application, the paths to ticket creation should be
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   129
   controlled so as to avoid a suboptimal end-user experience
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   130
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   131
Hence, we try to fetch the related project.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   132
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   133
.. sourcecode:: python
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   134
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   135
        veid = None
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   136
        if not entity.has_eid():
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   137
            peids = entity.linked_to('concerns', 'subject')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   138
            peid = peids and peids[0]
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   139
        else:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   140
            peid = entity.project.eid
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   141
            veid = entity.done_in and entity.done_in[0].eid
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   142
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   143
We distinguish between entity creation and entity modification using
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   144
the ``Entity.has_eid()`` method, which returns `False` on creation. At
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   145
creation time the only way to get a project is through the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   146
``__linkto`` parameter. Notice that we fetch the version in which the
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   147
ticket is `done_in` if any, for later.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   148
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   149
.. note::
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   150
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   151
  the implementation above assumes that if there is a ``__linkto``
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   152
  parameter, it is only about a project. While it makes sense most of
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   153
  the time, it is not an absolute. Depending on how an entity creation
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   154
  action action url is built, several outcomes could be possible
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   155
  there
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   156
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   157
If the ticket is already linked to a project, fetching it is
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   158
trivial. Then we add the relevant version to the initial vocabulary.
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   159
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   160
.. sourcecode:: python
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   161
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   162
        if peid:
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   163
            rschema = form._cw.vreg.schema['done_in'].rdef('Ticket', 'Version')
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   164
            rset = form._cw.execute(
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   165
                'Any V, VN ORDERBY version_sort_value(VN) '
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   166
                'WHERE V version_of P, P eid %(p)s, V num VN, '
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   167
                'V in_state ST, NOT ST name "published"', {'p': peid})
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   168
            vocab += [(v.view('combobox'), v.eid) for v in rset.entities()
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   169
                      if rschema.has_perm(form._cw, 'add', toeid=v.eid)
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   170
                      and v.eid != veid]
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   171
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   172
.. warning::
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   173
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   174
   we have to defend ourselves against lack of a project eid. Given
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   175
   the cardinality of the `concerns` relation, there *must* be a
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   176
   project, but this rule can only be enforced at validation time,
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   177
   which will happen of course only after form subsmission
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   178
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   179
Here, given a project eid, we complete the vocabulary with all
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   180
unpublished versions defined in the project (sorted by number) for
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   181
which the current user is allowed to establish the relation. Of
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   182
course, we take care *not* to provide a version the ticket is already
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   183
linked to (through ``done_in``).
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   184
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   185
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   186
Example of ad-hoc fields form
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   187
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   188
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   189
We want to define a form doing something else than editing an entity. The idea is
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   190
to propose a form to send an email to entities in a resultset which implements
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   191
:class:`IEmailable`.  Let's take a simplified version of what you'll find in
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   192
:mod:`cubicweb.web.views.massmailing`.
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   193
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   194
Here is the source code:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   195
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   196
.. sourcecode:: python
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   197
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   198
    def sender_value(form):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   199
	return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   200
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   201
    def recipient_choices(form, field):
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   202
	return [(e.get_email(), e.eid)
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   203
                 for e in form.cw_rset.entities()
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   204
		 if e.get_email()]
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   205
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   206
    def recipient_value(form):
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   207
	return [e.eid for e in form.cw_rset.entities()
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   208
                if e.get_email()]
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   209
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   210
    class MassMailingForm(forms.FieldsForm):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   211
	__regid__ = 'massmailing'
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   212
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   213
	needs_js = ('cubicweb.widgets.js',)
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   214
	domid = 'sendmail'
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   215
	action = 'sendmail'
4443
83ff2bb898a5 start documenting forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
   216
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   217
	sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   218
				label=_('From:'),
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   219
				value=sender_value)
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   220
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   221
	recipient = ff.StringField(widget=CheckBox(),
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   222
	                           label=_('Recipients:'),
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   223
				   choices=recipient_choices,
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   224
				   value=recipients_value)
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   225
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   226
	subject = ff.StringField(label=_('Subject:'), max_length=256)
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   227
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   228
	mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   229
						    inputid='mailbody'))
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   230
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   231
	form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   232
				  _('send email'), 'SEND_EMAIL_ICON'),
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   233
			ImgButton('cancelbutton', "javascript: history.back()",
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   234
				  stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   235
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   236
Let's detail what's going on up there. Our form will hold four fields:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   237
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   238
* a sender field, which is disabled and will simply contains the user's name and
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   239
  email
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   240
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   241
* a recipients field, which will be displayed as a list of users in the context
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   242
  result set with checkboxes so user can still choose who will receive his mailing
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   243
  by checking or not the checkboxes. By default all of them will be checked since
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   244
  field's value return a list containing same eids as those returned by the
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   245
  vocabulary function.
4465
18fb359f5c7a fix wrong autoclass inclusion
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4443
diff changeset
   246
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   247
* a subject field, limited to 256 characters (hence we know a
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   248
  :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   249
  :class:`~cubicweb.web.formfields.StringField`)
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   250
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   251
* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   252
  and whose definition won't be shown here. Notice though that we tell this form
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   253
  need this javascript file by using `needs_js`
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   254
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   255
Last but not least, we add two buttons control: one to post the form using
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   256
javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   257
set to 'sendmail', which is our form DOM id as specified by its `domid`
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   258
attribute), another to cancel the form which will go back to the previous page
5388
9167751463d4 [doc/book] rename images with non suffix dots to please latex
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5368
diff changeset
   259
using another javascript call. Also we specify an image to use as button icon as a
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   260
resource identifier (see :ref:`external_resources`) given as last argument to
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   261
:class:`cubicweb.web.formwidgets.ImgButton`.
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   262
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   263
To see this form, we still have to wrap it in a view. This is pretty simple:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   264
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   265
.. sourcecode:: python
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   266
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   267
    class MassMailingFormView(form.FormViewMixIn, EntityView):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   268
	__regid__ = 'massmailing'
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   269
	__select__ = implements(IEmailable) & authenticated_user()
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   270
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   271
	def call(self):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   272
	    form = self._cw.vreg['forms'].select('massmailing', self._cw,
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   273
	                                         rset=self.cw_rset)
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   274
	    self.w(form.render())
4443
83ff2bb898a5 start documenting forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
   275
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   276
As you see, we simply define a view with proper selector so it only apply to a
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   277
result set containing :class:`IEmailable` entities, and so that only users in the
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   278
managers or users group can use it. Then in the `call()` method for this view we
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   279
simply select the above form and write what its `.render()` method returns.
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   280
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   281
When this form is submitted, a controller with id 'sendmail' will be called (as
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   282
specified using `action`). This controller will be responsible to actually send
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   283
the mail to specified recipients.
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   284
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   285
Here is what it looks like:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   286
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   287
.. sourcecode:: python
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   288
5400
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   289
   class SendMailController(Controller):
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   290
       __regid__ = 'sendmail'
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   291
       __select__ = (authenticated_user() &
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   292
                     match_form_params('recipient', 'mailbody', 'subject'))
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   293
5400
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   294
       def publish(self, rset=None):
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   295
           body = self._cw.form['mailbody']
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   296
           subject = self._cw.form['subject']
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   297
           eids = self._cw.form['recipient']
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   298
           # eids may be a string if only one recipient was specified
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   299
           if isinstance(eids, basestring):
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   300
               rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   301
           else:
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   302
               rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   303
           recipients = list(rset.entities())
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   304
           msg = format_mail({'email' : self._cw.user.get_email(),
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   305
                              'name' : self._cw.user.dc_title()},
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   306
                             recipients, body, subject)
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   307
           if not self._cw.vreg.config.sendmails([(msg, recipients]):
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   308
               msg = self._cw._('could not connect to the SMTP server')
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   309
           else:
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   310
               msg = self._cw._('emails successfully sent')
b7ab099b128a [doc/book] various content fixes
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5394
diff changeset
   311
           raise Redirect(self._cw.build_url(__message=msg))
4443
83ff2bb898a5 start documenting forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
   312
83ff2bb898a5 start documenting forms
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2172
diff changeset
   313
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   314
The entry point of a controller is the publish method. In that case we simply get
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   315
back post values in request's `form` attribute, get user instances according
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   316
to eids found in the 'recipient' form value, and send email after calling
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   317
:func:`format_mail` to get a proper email message. If we can't send email or
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   318
if we successfully sent email, we redirect to the index page with proper message
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   319
to inform the user.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   320
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   321
Also notice that our controller has a selector that deny access to it
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   322
to anonymous users (we don't want our instance to be used as a spam
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   323
relay), but also checks if the expected parameters are specified in
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   324
forms. That avoids later defensive programming (though it's not enough
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   325
to handle all possible error cases).
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   326
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   327
To conclude our example, suppose we wish a different form layout and that existent
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   328
renderers are not satisfying (we would check that first of course :). We would then
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   329
have to define our own renderer:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   330
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   331
.. sourcecode:: python
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   332
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   333
    class MassMailingFormRenderer(formrenderers.FormRenderer):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   334
        __regid__ = 'massmailing'
4743
026a89520184 [book] a few autoclasses for renderers, misc tweaks
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 4465
diff changeset
   335
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   336
        def _render_fields(self, fields, w, form):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   337
            w(u'<table class="headersform">')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   338
            for field in fields:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   339
                if field.name == 'mailbody':
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   340
                    w(u'</table>')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   341
                    w(u'<div id="toolbar">')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   342
                    w(u'<ul>')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   343
                    for button in form.form_buttons:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   344
                        w(u'<li>%s</li>' % button.render(form))
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   345
                    w(u'</ul>')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   346
                    w(u'</div>')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   347
                    w(u'<div>')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   348
                    w(field.render(form, self))
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   349
                    w(u'</div>')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   350
                else:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   351
                    w(u'<tr>')
5462
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   352
                    w(u'<td class="hlabel">%s</td>' %
a37127c8bf23 [doc/book] copious choices example
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 5418
diff changeset
   353
                      self.render_label(form, field))
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   354
                    w(u'<td class="hvalue">')
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   355
                    w(field.render(form, self))
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   356
                    w(u'</td></tr>')
4743
026a89520184 [book] a few autoclasses for renderers, misc tweaks
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 4465
diff changeset
   357
5368
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   358
        def render_buttons(self, w, form):
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   359
            pass
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   360
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   361
We simply override the `_render_fields` and `render_buttons` method of the base form renderer
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   362
to arrange fields as we desire it: here we'll have first a two columns table with label and
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   363
value of the sender, recipients and subject field (form order respected), then form controls,
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   364
then a div containing the textarea for the email's content.
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   365
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   366
To bind this renderer to our form, we should add to our form definition above:
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   367
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   368
.. sourcecode:: python
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   369
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   370
    form_renderer_id = 'massmailing'
d321e4b62a10 [book] start documenting the HTML form system
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5350
diff changeset
   371
5418
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   372
API
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   373
~~~
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   374
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   375
.. automodule:: cubicweb.web.formfields
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   376
.. automodule:: cubicweb.web.formwidgets
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   377
.. automodule:: cubicweb.web.views.forms
4f0047cfecb5 [doc] reorganize for chapter structure
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 5400
diff changeset
   378
.. automodule:: cubicweb.web.views.formrenderers