web/formwidgets.py
author Sylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 21 Jan 2010 10:42:37 +0100
changeset 4304 0b53e850cdb5
parent 4252 6c4f109c2b03
child 4305 3d731478d9a8
permissions -rw-r--r--
refactor field's value retreiving from the widget (eg 'display value' concept): * kill field's display_value method, since getting value specified in a previous post or in req.form should be the widget responsibility (the widget nows what inputs to display, not the field) * new typed_value / format_value on widgets, mainly to ease overriding
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     1
"""widget classes for form construction
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     2
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     3
:organization: Logilab
4212
ab6573088b4a update copyright: welcome 2010
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3993
diff changeset
     4
:copyright: 2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     5
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
1977
606923dff11b big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1970
diff changeset
     6
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     7
"""
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     8
__docformat__ = "restructuredtext en"
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
     9
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    10
from datetime import date
1966
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
    11
from warnings import warn
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    12
4160
3fbdeef9a610 cleanup
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4159
diff changeset
    13
from logilab.mtconverter import xml_escape
3fbdeef9a610 cleanup
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4159
diff changeset
    14
from logilab.common.deprecation import deprecated
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    15
4023
eae23c40627a drop common subpackage
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3998
diff changeset
    16
from cubicweb import tags, uilib
3387
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
    17
from cubicweb.web import stdmsgs, INTERNAL_FIELD_VALUE, ProcessFormError
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    18
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    19
class FieldWidget(object):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    20
    """abstract widget class"""
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    21
    # javascript / css files required by the widget
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    22
    needs_js = ()
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    23
    needs_css = ()
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    24
    # automatically set id and tabindex attributes ?
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    25
    setdomid = True
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    26
    settabindex = True
2091
a7ea618e5478 don't set select widget when a vocabulary widget is already specified on the field class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1989
diff changeset
    27
    # does this widget expect a vocabulary
a7ea618e5478 don't set select widget when a vocabulary widget is already specified on the field class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1989
diff changeset
    28
    vocabulary_widget = False
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    29
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    30
    def __init__(self, attrs=None, setdomid=None, settabindex=None):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    31
        if attrs is None:
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    32
            attrs = {}
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    33
        self.attrs = attrs
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    34
        if setdomid is not None:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    35
            # override class's default value
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    36
            self.setdomid = setdomid
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    37
        if settabindex is not None:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    38
            # override class's default value
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    39
            self.settabindex = settabindex
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    40
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    41
    def add_media(self, form):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    42
        """adds media (CSS & JS) required by this widget"""
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    43
        if self.needs_js:
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
    44
            form._cw.add_js(self.needs_js)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    45
        if self.needs_css:
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
    46
            form._cw.add_css(self.needs_css)
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    47
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
    48
    def render(self, form, field, renderer):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    49
        """render the widget for the given `field` of `form`.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    50
        To override in concrete class
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    51
        """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    52
        raise NotImplementedError
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    53
4304
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    54
    def typed_value(self, form, field):
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    55
        """return field's *typed* value specified in:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    56
        3. extra form values given to render()
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    57
        4. field's typed value
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    58
        """
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    59
        qname = field.input_name(form)
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    60
        for key in (field, qname):
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    61
            try:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    62
                return form.formvalues[key]
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    63
            except KeyError:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    64
                continue
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    65
        if field.name != qname and field.name in form.formvalues:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    66
            return form.formvalues[field.name]
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    67
        return field.typed_value(form)
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    68
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    69
    def format_value(self, form, field, value):
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    70
        return field.format_value(form._cw, value)
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    71
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
    72
    def values_and_attributes(self, form, field):
4304
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    73
        """found field's *string* value in:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    74
        1. previously submitted form values if any (eg on validation error)
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    75
        2. req.form
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    76
        3. extra form values given to render()
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    77
        4. field's typed value
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    78
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    79
        values found in 1. and 2. are expected te be already some 'display'
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    80
        value while those found in 3. and 4. are expected to be correctly typed.
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    81
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    82
        3 and 4 are handle by the .typed_value(form, field) method
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    83
        """
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    84
        qname = field.input_name(form)
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    85
        if qname in form.form_previous_values:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    86
            values = form.form_previous_values[qname]
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    87
        elif qname in form._cw.form:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    88
            values = form._cw.form[qname]
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    89
        elif field.name != qname and field.name in form._cw.form:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    90
            # compat: accept attr=value in req.form to specify value of attr-subject
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    91
            values = form._cw.form[field.name]
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    92
        else:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    93
            values = self.typed_value(form, field)
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    94
            if values != INTERNAL_FIELD_VALUE:
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
    95
                values = self.format_value(form, field, values)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    96
        if not isinstance(values, (tuple, list)):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    97
            values = (values,)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    98
        attrs = dict(self.attrs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    99
        if self.setdomid:
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   100
            attrs['id'] = field.dom_id(form)
1273
64e1db70161b don't set tabindex if already in attrs
sylvain.thenault@logilab.fr
parents: 1152
diff changeset
   101
        if self.settabindex and not 'tabindex' in attrs:
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   102
            attrs['tabindex'] = form._cw.next_tabindex()
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   103
        return values, attrs
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   104
3387
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   105
    def process_field_data(self, form, field):
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   106
        posted = form._cw.form
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   107
        val = posted.get(field.input_name(form))
4169
341d19ef7b7c strip string by default
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4163
diff changeset
   108
        if isinstance(val, basestring):
341d19ef7b7c strip string by default
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4163
diff changeset
   109
            val = val.strip() or None
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   110
        return val
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   111
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   112
    @deprecated('[3.6] use values_and_attributes')
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   113
    def _render_attrs(self, form, field):
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   114
        """return html tag name, attributes and a list of values for the field
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   115
        """
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   116
        values, attrs = self.values_and_attributes(form, field)
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   117
        return field.input_name(form), values, attrs
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   118
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   119
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   120
class Input(FieldWidget):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   121
    """abstract widget class for <input> tag based widgets"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   122
    type = None
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   123
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   124
    def render(self, form, field, renderer):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   125
        """render the widget for the given `field` of `form`.
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   126
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   127
        Generate one <input> tag for each field's value
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   128
        """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   129
        self.add_media(form)
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   130
        values, attrs = self.values_and_attributes(form, field)
1768
b59b7c422a8a ensure input widgets are displayed anyway if they get an empty list as values
sylvain.thenault@logilab.fr
parents: 1749
diff changeset
   131
        # ensure something is rendered
b59b7c422a8a ensure input widgets are displayed anyway if they get an empty list as values
sylvain.thenault@logilab.fr
parents: 1749
diff changeset
   132
        if not values:
b59b7c422a8a ensure input widgets are displayed anyway if they get an empty list as values
sylvain.thenault@logilab.fr
parents: 1749
diff changeset
   133
            values = (INTERNAL_FIELD_VALUE,)
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   134
        inputs = [tags.input(name=field.input_name(form), type=self.type,
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   135
                             value=value, **attrs)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   136
                  for value in values]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   137
        return u'\n'.join(inputs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   138
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   139
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   140
# basic html widgets ###########################################################
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   141
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   142
class TextInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   143
    """<input type='text'>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   144
    type = 'text'
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   145
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   146
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   147
class PasswordInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   148
    """<input type='password'> and its confirmation field (using
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   149
    <field's name>-confirm as name)
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   150
    """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   151
    type = 'password'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   152
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   153
    def render(self, form, field, renderer):
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   154
        self.add_media(form)
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   155
        values, attrs = self.values_and_attributes(form, field)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   156
        assert len(values) == 1
1110
c71997f514ba fix password widget: do not duplicate dom id, fix confirm field name
sylvain.thenault@logilab.fr
parents: 1096
diff changeset
   157
        id = attrs.pop('id')
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   158
        inputs = [tags.input(name=field.input_name(form),
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   159
                             value=values[0], type=self.type, id=id, **attrs),
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   160
                  '<br/>',
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   161
                  tags.input(name=field.input_name(form, '-confirm'),
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   162
                             value=values[0], type=self.type, **attrs),
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   163
                  '&#160;', tags.span(form._cw._('confirm password'),
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   164
                                      **{'class': 'emphasis'})]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   165
        return u'\n'.join(inputs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   166
3387
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   167
    def process_field_data(self, form, field):
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   168
        passwd1 = super(PasswordInput, self).process_field_data(form, field)
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   169
        passwd2 = form._cw.form.get(field.input_name(form, '-confirm'))
3387
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   170
        if passwd1 == passwd2:
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   171
            if passwd1 is None:
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   172
                return None
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   173
            return passwd1.encode('utf-8')
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   174
        raise ProcessFormError(form._cw._("password and confirmation don't match"))
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   175
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   176
1934
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   177
class PasswordSingleInput(Input):
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   178
    """<input type='password'> without a confirmation field"""
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   179
    type = 'password'
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   180
3387
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   181
    def process_field_data(self, form, field):
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   182
        value = super(PasswordSingleInput, self).process_field_data(form, field)
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   183
        if value is not None:
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   184
            return value.encode('utf-8')
a357d4147eee [forms] work-in-progress, big editcontroller refactoring: let fields/widgets process posted data
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 2549
diff changeset
   185
        return value
1934
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   186
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   187
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   188
class FileInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   189
    """<input type='file'>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   190
    type = 'file'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   191
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   192
    def values_and_attributes(self, form, field):
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   193
        # ignore value which makes no sense here (XXX even on form validation error?)
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   194
        values, attrs = super(FileInput, self).values_and_attributes(form, field)
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   195
        return ('',), attrs
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   196
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   197
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   198
class HiddenInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   199
    """<input type='hidden'>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   200
    type = 'hidden'
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   201
    setdomid = False # by default, don't set id attribute on hidden input
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   202
    settabindex = False
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   203
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   204
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   205
class ButtonInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   206
    """<input type='button'>
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   207
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   208
    if you want a global form button, look at the Button, SubmitButton,
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   209
    ResetButton and ImgButton classes below.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   210
    """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   211
    type = 'button'
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   212
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   213
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   214
class TextArea(FieldWidget):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   215
    """<textarea>"""
2366
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   216
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   217
    def render(self, form, field, renderer):
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   218
        values, attrs = self.values_and_attributes(form, field)
2131
00e6d1cb18ea [views] call autogrow only once per key event
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2091
diff changeset
   219
        attrs.setdefault('onkeyup', 'autogrow(this)')
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   220
        if not values:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   221
            value = u''
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   222
        elif len(values) == 1:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   223
            value = values[0]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   224
        else:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   225
            raise ValueError('a textarea is not supposed to be multivalued')
2366
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   226
        lines = value.splitlines()
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   227
        linecount = len(lines)
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   228
        for line in lines:
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   229
            linecount += len(line) / 80
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   230
        attrs.setdefault('cols', 80)
e4229723b824 [formwidgets] let the textarea height be dependant on the actual content (up to a limit)
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 2360
diff changeset
   231
        attrs.setdefault('rows', min(15, linecount + 2))
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   232
        return tags.textarea(value, name=field.input_name(form), **attrs)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   233
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   234
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   235
class FCKEditor(TextArea):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   236
    """FCKEditor enabled <textarea>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   237
    def __init__(self, *args, **kwargs):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   238
        super(FCKEditor, self).__init__(*args, **kwargs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   239
        self.attrs['cubicweb:type'] = 'wysiwyg'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   240
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   241
    def render(self, form, field, renderer):
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   242
        form._cw.fckeditor_config()
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   243
        return super(FCKEditor, self).render(form, field, renderer)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   244
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   245
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   246
class Select(FieldWidget):
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   247
    """<select>, for field having a specific vocabulary"""
2091
a7ea618e5478 don't set select widget when a vocabulary widget is already specified on the field class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1989
diff changeset
   248
    vocabulary_widget = True
a7ea618e5478 don't set select widget when a vocabulary widget is already specified on the field class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1989
diff changeset
   249
1562
e6d2c07c0c58 [forms/widgets] fix relation field not sorting its vocabulary, revert hack on Select widget
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 1541
diff changeset
   250
    def __init__(self, attrs=None, multiple=False):
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   251
        super(Select, self).__init__(attrs)
1541
ddddbb748355 [widgets] an option for Select to show sorted content
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 1538
diff changeset
   252
        self._multiple = multiple
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   253
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   254
    def render(self, form, field, renderer):
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   255
        curvalues, attrs = self.values_and_attributes(form, field)
1989
8c8dead642f7 set default select size to 1 into the widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1977
diff changeset
   256
        if not 'size' in attrs:
8c8dead642f7 set default select size to 1 into the widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1977
diff changeset
   257
            attrs['size'] = self._multiple and '5' or '1'
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   258
        options = []
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   259
        optgroup_opened = False
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   260
        for option in field.vocabulary(form):
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   261
            try:
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   262
                label, value, oattrs = option
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   263
            except ValueError:
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   264
                label, value = option
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   265
                oattrs = {}
1336
2e552353c42a insert an optgroup as separator on None values
sylvain.thenault@logilab.fr
parents: 1330
diff changeset
   266
            if value is None:
2e552353c42a insert an optgroup as separator on None values
sylvain.thenault@logilab.fr
parents: 1330
diff changeset
   267
                # handle separator
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   268
                if optgroup_opened:
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   269
                    options.append(u'</optgroup>')
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   270
                oattrs.setdefault('label', label or '')
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   271
                options.append(u'<optgroup %s>' % uilib.sgml_attributes(oattrs))
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   272
                optgroup_opened = True
1336
2e552353c42a insert an optgroup as separator on None values
sylvain.thenault@logilab.fr
parents: 1330
diff changeset
   273
            elif value in curvalues:
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   274
                options.append(tags.option(label, value=value,
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   275
                                           selected='selected', **oattrs))
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   276
            else:
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   277
                options.append(tags.option(label, value=value, **oattrs))
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   278
        if optgroup_opened:
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   279
            options.append(u'</optgroup>')
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   280
        return tags.select(name=field.input_name(form), multiple=self._multiple,
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   281
                           options=options, **attrs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   282
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   283
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   284
class CheckBox(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   285
    """<input type='checkbox'>, for field having a specific vocabulary. One
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   286
    input will be generated for each possible value.
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   287
    """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   288
    type = 'checkbox'
2091
a7ea618e5478 don't set select widget when a vocabulary widget is already specified on the field class
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1989
diff changeset
   289
    vocabulary_widget = True
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   290
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   291
    def render(self, form, field, renderer):
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   292
        curvalues, attrs = self.values_and_attributes(form, field)
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   293
        domid = attrs.pop('id', None)
2519
ac1a869e1e93 nicer checkbox widget implementation, avoid extra <br/> at the end
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2518
diff changeset
   294
        sep = attrs.pop('separator', u'<br/>\n')
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   295
        options = []
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   296
        for i, option in enumerate(field.vocabulary(form)):
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   297
            try:
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   298
                label, value, oattrs = option
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   299
            except ValueError:
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   300
                label, value = option
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   301
                oattrs = {}
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   302
            iattrs = attrs.copy()
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   303
            iattrs.update(oattrs)
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   304
            if i == 0 and domid is not None:
2518
38c28ee40138 allow vocabulary functions to return either label/value or label/value/dict (to use as attributes of the tag for this input)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2366
diff changeset
   305
                iattrs.setdefault('id', domid)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   306
            if value in curvalues:
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   307
                iattrs['checked'] = u'checked'
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   308
            tag = tags.input(name=field.input_name(form), type=self.type,
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   309
                             value=value, **iattrs)
2519
ac1a869e1e93 nicer checkbox widget implementation, avoid extra <br/> at the end
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2518
diff changeset
   310
            options.append(tag + label)
ac1a869e1e93 nicer checkbox widget implementation, avoid extra <br/> at the end
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2518
diff changeset
   311
        return sep.join(options)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   312
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   313
1832
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   314
class Radio(CheckBox):
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   315
    """<input type='radio'>, for field having a specific vocabulary. One
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   316
    input will be generated for each possible value.
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   317
    """
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   318
    type = 'radio'
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   319
2225
16826403affa cleanup
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2131
diff changeset
   320
2523
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   321
# compound widgets #############################################################
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   322
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   323
class IntervalWidget(FieldWidget):
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   324
    """custom widget to display an interval composed by 2 fields. This widget
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   325
    is expected to be used with a CompoundField containing the two actual
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   326
    fields.
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   327
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   328
    Exemple usage::
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   329
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   330
from uicfg import autoform_field, autoform_section
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   331
autoform_field.tag_attribute(('Concert', 'minprice'),
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   332
                              CompoundField(fields=(IntField(name='minprice'),
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   333
                                                    IntField(name='maxprice')),
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   334
                                            label=_('price'),
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   335
                                            widget=IntervalWidget()
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   336
                                            ))
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   337
# we've to hide the other field manually for now
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   338
autoform_section.tag_attribute(('Concert', 'maxprice'), 'generated')
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   339
    """
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   340
    def render(self, form, field, renderer):
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   341
        actual_fields = field.fields
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   342
        assert len(actual_fields) == 2
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   343
        return u'<div>%s %s %s %s</div>' % (
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   344
            form._cw._('from_interval_start'),
2523
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   345
            actual_fields[0].render(form, renderer),
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   346
            form._cw._('to_interval_end'),
2523
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   347
            actual_fields[1].render(form, renderer),
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   348
            )
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   349
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   350
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   351
class HorizontalLayoutWidget(FieldWidget):
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   352
    """custom widget to display a set of fields grouped together horizontally
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   353
    in a form. See `IntervalWidget` for example usage.
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   354
    """
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   355
    def render(self, form, field, renderer):
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   356
        if self.attrs.get('display_label', True):
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   357
            subst = self.attrs.get('label_input_substitution', '%(label)s %(input)s')
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   358
            fields = [subst % {'label': renderer.render_label(form, f),
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   359
                              'input': f.render(form, renderer)}
2549
3d8c62e5e2d4 [R forms] use a subfields(form) method to get a chance to adapt to context
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2523
diff changeset
   360
                      for f in field.subfields(form)]
2523
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   361
        else:
2549
3d8c62e5e2d4 [R forms] use a subfields(form) method to get a chance to adapt to context
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2523
diff changeset
   362
            fields = [f.render(form, renderer) for f in field.subfields(form)]
2523
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   363
        return u'<div>%s</div>' % ' '.join(fields)
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   364
1d245fbbeb90 some new field/widgets classes: CompoundField, IntervalWidget, HorizontalLayoutWidget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2522
diff changeset
   365
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   366
# javascript widgets ###########################################################
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   367
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   368
class DateTimePicker(TextInput):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   369
    """<input type='text' + javascript date/time picker for date or datetime
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   370
    fields
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   371
    """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   372
    monthnames = ('january', 'february', 'march', 'april',
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   373
                  'may', 'june', 'july', 'august',
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   374
                  'september', 'october', 'november', 'december')
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   375
    daynames = ('monday', 'tuesday', 'wednesday', 'thursday',
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   376
                'friday', 'saturday', 'sunday')
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   377
1311
4cc6e2723dc7 move ajax.js to base form class
sylvain.thenault@logilab.fr
parents: 1304
diff changeset
   378
    needs_js = ('cubicweb.calendar.js',)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   379
    needs_css = ('cubicweb.calendar_popup.css',)
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   380
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   381
    @classmethod
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   382
    def add_localized_infos(cls, req):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   383
        """inserts JS variables defining localized months and days"""
4023
eae23c40627a drop common subpackage
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3998
diff changeset
   384
        # import here to avoid dependancy from cubicweb to simplejson
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   385
        _ = req._
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   386
        monthnames = [_(mname) for mname in cls.monthnames]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   387
        daynames = [_(dname) for dname in cls.daynames]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   388
        req.html_headers.define_var('MONTHNAMES', monthnames)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   389
        req.html_headers.define_var('DAYNAMES', daynames)
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   390
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   391
    def render(self, form, field, renderer):
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   392
        txtwidget = super(DateTimePicker, self).render(form, field, renderer)
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   393
        self.add_localized_infos(form._cw)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   394
        cal_button = self._render_calendar_popup(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   395
        return txtwidget + cal_button
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   396
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   397
    def _render_calendar_popup(self, form, field):
4159
6b2b20c73d59 refactor form field value handling, to get a nicer api and an easier algorithm to get field's value
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4156
diff changeset
   398
        value = field.typed_value(form)
1392
d6279efff7b3 refactor the way field value/display value are handled to avoid getting a 'display' value when expected a 'typed' value
sylvain.thenault@logilab.fr
parents: 1389
diff changeset
   399
        if not value:
d6279efff7b3 refactor the way field value/display value are handled to avoid getting a 'display' value when expected a 'typed' value
sylvain.thenault@logilab.fr
parents: 1389
diff changeset
   400
            value = date.today()
4156
1bbb0ee42c8e drop form_field_name/form_field_id methods from form object, in favor of field.input_name(form) / field.dom_id(form)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4023
diff changeset
   401
        inputid = field.dom_id(form)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   402
        helperid = '%shelper' % inputid
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   403
        year, month = value.year, value.month
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   404
        return (u"""<a onclick="toggleCalendar('%s', '%s', %s, %s);" class="calhelper">
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   405
<img src="%s" title="%s" alt="" /></a><div class="calpopup hidden" id="%s"></div>"""
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   406
                % (helperid, inputid, year, month,
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   407
                   form._cw.external_resource('CALENDAR_ICON'),
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   408
                   form._cw._('calendar'), helperid) )
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   409
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   410
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   411
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   412
# ajax widgets ################################################################
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   413
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   414
def init_ajax_attributes(attrs, wdgtype, loadtype=u'auto'):
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   415
    try:
1344
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   416
        attrs['klass'] += u' widget'
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   417
    except KeyError:
1344
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   418
        attrs['klass'] = u'widget'
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   419
    attrs.setdefault('cubicweb:wdgtype', wdgtype)
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   420
    attrs.setdefault('cubicweb:loadtype', loadtype)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   421
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   422
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   423
class AjaxWidget(FieldWidget):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   424
    """simple <div> based ajax widget"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   425
    def __init__(self, wdgtype, inputid=None, **kwargs):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   426
        super(AjaxWidget, self).__init__(**kwargs)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   427
        init_ajax_attributes(self.attrs, wdgtype)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   428
        if inputid is not None:
1344
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   429
            self.attrs['cubicweb:inputid'] = inputid
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   430
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   431
    def render(self, form, field, renderer):
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   432
        self.add_media(form)
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   433
        attrs = self.values_and_attributes(form, field)[-1]
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   434
        return tags.div(**attrs)
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   435
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   436
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   437
class AutoCompletionWidget(TextInput):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   438
    """ajax widget for StringField, proposing matching existing values as you
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   439
    type.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   440
    """
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   441
    needs_js = ('cubicweb.widgets.js', 'jquery.autocomplete.js')
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   442
    needs_css = ('jquery.autocomplete.css',)
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   443
    wdgtype = 'SuggestField'
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   444
    loadtype = 'auto'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   445
1966
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   446
    def __init__(self, *args, **kwargs):
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   447
        try:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   448
            self.autocomplete_initfunc = kwargs.pop('autocomplete_initfunc')
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   449
        except KeyError:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   450
            warn('use autocomplete_initfunc argument of %s constructor '
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   451
                 'instead of relying on autocomplete_initfuncs dictionary on '
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   452
                 'the entity class' % self.__class__.__name__,
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   453
                 DeprecationWarning)
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   454
            self.autocomplete_initfunc = None
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   455
        super(AutoCompletionWidget, self).__init__(*args, **kwargs)
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   456
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   457
    def values_and_attributes(self, form, field):
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   458
        values, attrs = super(AutoCompletionWidget, self).values_and_attributes(form, field)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   459
        init_ajax_attributes(attrs, self.wdgtype, self.loadtype)
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   460
        # XXX entity form specific
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   461
        attrs['cubicweb:dataurl'] = self._get_url(form.edited_entity, field)
3993
8cf7c767b134 quick & dirty fix for auto completion widget
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3803
diff changeset
   462
        if not values:
8cf7c767b134 quick & dirty fix for auto completion widget
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 3803
diff changeset
   463
            values = ('',)
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   464
        return values, attrs
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   465
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   466
    def _get_url(self, entity, field):
1966
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   467
        if self.autocomplete_initfunc is None:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   468
            # XXX for bw compat
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   469
            fname = entity.autocomplete_initfuncs[field.name]
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   470
        else:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   471
            fname = self.autocomplete_initfunc
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   472
        return entity._cw.build_url('json', fname=fname, mode='remote',
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   473
                                    pageid=entity._cw.pageid)
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   474
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   475
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   476
class StaticFileAutoCompletionWidget(AutoCompletionWidget):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   477
    """XXX describe me"""
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   478
    wdgtype = 'StaticFileSuggestField'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   479
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   480
    def _get_url(self, entity, field):
1966
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   481
        if self.autocomplete_initfunc is None:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   482
            # XXX for bw compat
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   483
            fname = entity.autocomplete_initfuncs[field.name]
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   484
        else:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   485
            fname = self.autocomplete_initfunc
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   486
        return entity._cw.datadir_url + fname
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   487
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   488
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   489
class RestrictedAutoCompletionWidget(AutoCompletionWidget):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   490
    """XXX describe me"""
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   491
    wdgtype = 'RestrictedSuggestField'
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   492
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   493
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   494
class AddComboBoxWidget(Select):
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   495
    def values_and_attributes(self, form, field):
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   496
        values, attrs = super(AddComboBoxWidget, self).values_and_attributes(form, field)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   497
        init_ajax_attributes(self.attrs, 'AddComboBox')
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   498
        # XXX entity form specific
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   499
        entity = form.edited_entity
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   500
        attrs['cubicweb:etype_to'] = entity.e_schema
3689
deb13e88e037 follow yams 0.25 api changes to improve performance
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3106
diff changeset
   501
        etype_from = entity.e_schema.subjrels[field.name].objects(entity.e_schema)[0]
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   502
        attrs['cubicweb:etype_from'] = etype_from
4163
b2747ed057e6 substitute _render_attrs by values_and_attributes method, keeping bw compat
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4160
diff changeset
   503
        return values, attrs
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   504
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   505
    def render(self, form, field, renderer):
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   506
        return super(AddComboBoxWidget, self).render(form, field, renderer) + u'''
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   507
<div id="newvalue">
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   508
  <input type="text" id="newopt" />
2996
866a2c135c33 B #345282 xhtml requires to use &#160; instead of &nbsp;
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2549
diff changeset
   509
  <a href="javascript:noop()" id="add_newopt">&#160;</a></div>
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   510
'''
1359
bef6891393d7 backport some tests
sylvain.thenault@logilab.fr
parents: 1344
diff changeset
   511
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   512
# buttons ######################################################################
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   513
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   514
class Button(Input):
1389
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   515
    """<input type='button'>, base class for global form buttons
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   516
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   517
    note label is a msgid which will be translated at form generation time, you
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   518
    should not give an already translated string.
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   519
    """
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   520
    type = 'button'
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   521
    def __init__(self, label=stdmsgs.BUTTON_OK, attrs=None,
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   522
                 setdomid=None, settabindex=None,
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   523
                 name='', value='', onclick=None, cwaction=None):
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   524
        super(Button, self).__init__(attrs, setdomid, settabindex)
3803
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   525
        if isinstance(label, tuple):
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   526
            self.label = label[0]
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   527
            self.icon = label[1]
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   528
        else:
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   529
            self.label = label
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   530
            self.icon = None
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   531
        self.name = name
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   532
        self.value = ''
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   533
        self.onclick = onclick
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   534
        self.cwaction = cwaction
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   535
        self.attrs.setdefault('klass', 'validateButton')
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   536
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   537
    def render(self, form, field=None, renderer=None):
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   538
        label = form._cw._(self.label)
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   539
        attrs = self.attrs.copy()
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   540
        if self.cwaction:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   541
            assert self.onclick is None
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   542
            attrs['onclick'] = "postForm('__action_%s', \'%s\', \'%s\')" % (
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   543
                self.cwaction, self.label, form.domid)
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   544
        elif self.onclick:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   545
            attrs['onclick'] = self.onclick
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   546
        if self.name:
4250
39adce674a09 fix NameError
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 4212
diff changeset
   547
            attrs['name'] = self.name
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   548
            if self.setdomid:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   549
                attrs['id'] = self.name
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   550
        if self.settabindex and not 'tabindex' in attrs:
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   551
            attrs['tabindex'] = form._cw.next_tabindex()
3803
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   552
        if self.icon:
3890
d7a270f50f54 backport stable branch (one more time painfully)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3720 3803
diff changeset
   553
            img = tags.img(src=form._cw.external_resource(self.icon), alt=self.icon)
3803
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   554
        else:
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   555
            img = u''
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   556
        return tags.button(img + xml_escape(label), escapecontent=False,
414bb8439002 [web ui] decorate form buttons with icons (at last)
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 3689
diff changeset
   557
                           value=label, type=self.type, **attrs)
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   558
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   559
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   560
class SubmitButton(Button):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   561
    """<input type='submit'>, main button to submit a form"""
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   562
    type = 'submit'
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   563
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   564
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   565
class ResetButton(Button):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   566
    """<input type='reset'>, main button to reset a form.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   567
    You usually don't want this.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   568
    """
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   569
    type = 'reset'
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   570
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   571
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   572
class ImgButton(object):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   573
    """<img> wrapped into a <a> tag with href triggering something (usually a
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   574
    javascript call)
1389
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   575
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   576
    note label is a msgid which will be translated at form generation time, you
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   577
    should not give an already translated string.
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   578
    """
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   579
    def __init__(self, domid, href, label, imgressource):
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   580
        self.domid = domid
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   581
        self.href = href
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   582
        self.imgressource = imgressource
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   583
        self.label = label
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   584
2522
562f5dcf2345 widget.render now takes the renderer as third argument (keeping minimal bw compat)
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2519
diff changeset
   585
    def render(self, form, field=None, renderer=None):
3451
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   586
        label = form._cw._(self.label)
6b46d73823f5 [api] work in progress, use __regid__, cw_*, etc.
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 3388
diff changeset
   587
        imgsrc = form._cw.external_resource(self.imgressource)
1389
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   588
        return '<a id="%(domid)s" href="%(href)s">'\
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   589
               '<img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % {
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   590
            'label': label, 'imgsrc': imgsrc,
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   591
            'domid': self.domid, 'href': self.href}
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   592
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   593
4304
0b53e850cdb5 refactor field's value retreiving from the widget (eg 'display value' concept):
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4252
diff changeset
   594
# more widgets #################################################################
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   595
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   596
# XXX EntityLinkComboBoxWidget, [Raw]DynamicComboBoxWidget