web/formwidgets.py
author Nicolas Chauvat <nicolas.chauvat@logilab.fr>
Thu, 04 Jun 2009 17:21:29 +0200
changeset 2039 6c036e4d9ad4
parent 1989 8c8dead642f7
child 2091 a7ea618e5478
permissions -rw-r--r--
Added tag cubicweb-debian-version-3_3_0-1 for changeset 07214e923e75
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
1977
606923dff11b big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1970
diff changeset
     4
:copyright: 2009 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
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    13
from cubicweb.common import tags
1735
07afba765926 no value, but something needs to be shown // needs review //
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 1650
diff changeset
    14
from cubicweb.web import stdmsgs, INTERNAL_FIELD_VALUE
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    15
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    16
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    17
class FieldWidget(object):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    18
    """abstract widget class"""
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    19
    # javascript / css files required by the widget
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    20
    needs_js = ()
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    21
    needs_css = ()
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    22
    # automatically set id and tabindex attributes ?
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    23
    setdomid = True
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    24
    settabindex = True
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    25
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    26
    def __init__(self, attrs=None, setdomid=None, settabindex=None):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    27
        if attrs is None:
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    28
            attrs = {}
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    29
        self.attrs = attrs
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    30
        if setdomid is not None:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    31
            # override class's default value
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    32
            self.setdomid = setdomid
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    33
        if settabindex is not None:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    34
            # override class's default value
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    35
            self.settabindex = settabindex
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    36
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    37
    def add_media(self, form):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    38
        """adds media (CSS & JS) required by this widget"""
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    39
        if self.needs_js:
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    40
            form.req.add_js(self.needs_js)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    41
        if self.needs_css:
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    42
            form.req.add_css(self.needs_css)
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    43
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    44
    def render(self, form, field):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    45
        """render the widget for the given `field` of `form`.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    46
        To override in concrete class
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    47
        """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    48
        raise NotImplementedError
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    49
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    50
    def _render_attrs(self, form, field):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    51
        """return html tag name, attributes and a list of values for the field
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    52
        """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    53
        name = form.context[field]['name']
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    54
        values = form.context[field]['value']
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    55
        if not isinstance(values, (tuple, list)):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    56
            values = (values,)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    57
        attrs = dict(self.attrs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    58
        if self.setdomid:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    59
            attrs['id'] = form.context[field]['id']
1273
64e1db70161b don't set tabindex if already in attrs
sylvain.thenault@logilab.fr
parents: 1152
diff changeset
    60
        if self.settabindex and not 'tabindex' in attrs:
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    61
            attrs['tabindex'] = form.req.next_tabindex()
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    62
        return name, values, attrs
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    63
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    64
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    65
class Input(FieldWidget):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    66
    """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
    67
    type = None
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    68
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    69
    def render(self, form, field):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    70
        """render the widget for the given `field` of `form`.
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    71
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    72
        Generate one <input> tag for each field's value
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    73
        """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    74
        self.add_media(form)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    75
        name, values, attrs = self._render_attrs(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
    76
        # 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
    77
        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
    78
            values = (INTERNAL_FIELD_VALUE,)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    79
        inputs = [tags.input(name=name, value=value, type=self.type, **attrs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    80
                  for value in values]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    81
        return u'\n'.join(inputs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    82
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    83
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    84
# basic html widgets ###########################################################
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    85
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    86
class TextInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    87
    """<input type='text'>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    88
    type = 'text'
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    89
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
    90
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    91
class PasswordInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    92
    """<input type='password'> and its confirmation field (using
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    93
    <field's name>-confirm as name)
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
    94
    """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    95
    type = 'password'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
    96
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    97
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    98
        self.add_media(form)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
    99
        name, values, attrs = self._render_attrs(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   100
        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
   101
        id = attrs.pop('id')
1328
c050f9f8672e password input may be used with non eidparam fields...
sylvain.thenault@logilab.fr
parents: 1311
diff changeset
   102
        try:
c050f9f8672e password input may be used with non eidparam fields...
sylvain.thenault@logilab.fr
parents: 1311
diff changeset
   103
            confirmname = '%s-confirm:%s' % tuple(name.rsplit(':', 1))
1329
9c7cc717bb17 fix error class
sylvain.thenault@logilab.fr
parents: 1328
diff changeset
   104
        except TypeError:
1328
c050f9f8672e password input may be used with non eidparam fields...
sylvain.thenault@logilab.fr
parents: 1311
diff changeset
   105
            confirmname = '%s-confirm' % name
1110
c71997f514ba fix password widget: do not duplicate dom id, fix confirm field name
sylvain.thenault@logilab.fr
parents: 1096
diff changeset
   106
        inputs = [tags.input(name=name, 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
   107
                  '<br/>',
1294
870bc725cc9a password widget should use the same value as main field for the confirm, else if we don't notice that we got a validation error while no password modification has been done
sylvain.thenault@logilab.fr
parents: 1273
diff changeset
   108
                  tags.input(name=confirmname, value=values[0], type=self.type, **attrs),
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   109
                  '&nbsp;', tags.span(form.req._('confirm password'),
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   110
                                      **{'class': 'emphasis'})]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   111
        return u'\n'.join(inputs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   112
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   113
1934
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   114
class PasswordSingleInput(Input):
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   115
    """<input type='password'> without a confirmation field"""
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   116
    type = 'password'
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   117
be86bb31c4c2 add single input password widget
Florent <florent@secondweb.fr>
parents: 1875
diff changeset
   118
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   119
class FileInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   120
    """<input type='file'>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   121
    type = 'file'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   122
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   123
    def _render_attrs(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   124
        # ignore value which makes no sense here (XXX even on form validation error?)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   125
        name, values, attrs = super(FileInput, self)._render_attrs(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   126
        return name, ('',), attrs
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   127
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   128
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   129
class HiddenInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   130
    """<input type='hidden'>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   131
    type = 'hidden'
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   132
    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
   133
    settabindex = False
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   134
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   135
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   136
class ButtonInput(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   137
    """<input type='button'>
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   138
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   139
    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
   140
    ResetButton and ImgButton classes below.
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
    type = 'button'
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   143
1096
e1fe98850bf7 cleanup
sylvain.thenault@logilab.fr
parents: 1081
diff changeset
   144
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   145
class TextArea(FieldWidget):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   146
    """<textarea>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   147
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   148
        name, values, attrs = self._render_attrs(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   149
        attrs.setdefault('onkeypress', 'autogrow(this)')
1557
d2d5428c7a38 fix StringField/TextField handling (XXX remove one of them?, ensure textarea has rows/cols attributes)
sylvain.thenault@logilab.fr
parents: 1541
diff changeset
   150
        attrs.setdefault('cols', 80)
d2d5428c7a38 fix StringField/TextField handling (XXX remove one of them?, ensure textarea has rows/cols attributes)
sylvain.thenault@logilab.fr
parents: 1541
diff changeset
   151
        attrs.setdefault('rows', 20)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   152
        if not values:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   153
            value = u''
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   154
        elif len(values) == 1:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   155
            value = values[0]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   156
        else:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   157
            raise ValueError('a textarea is not supposed to be multivalued')
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   158
        return tags.textarea(value, name=name, **attrs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   159
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   160
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   161
class FCKEditor(TextArea):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   162
    """FCKEditor enabled <textarea>"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   163
    def __init__(self, *args, **kwargs):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   164
        super(FCKEditor, self).__init__(*args, **kwargs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   165
        self.attrs['cubicweb:type'] = 'wysiwyg'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   166
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   167
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   168
        form.req.fckeditor_config()
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   169
        return super(FCKEditor, self).render(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   170
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   171
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   172
class Select(FieldWidget):
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   173
    """<select>, for field having a specific vocabulary"""
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
   174
    def __init__(self, attrs=None, multiple=False):
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   175
        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
   176
        self._multiple = multiple
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   177
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   178
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   179
        name, curvalues, attrs = self._render_attrs(form, field)
1989
8c8dead642f7 set default select size to 1 into the widget
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1977
diff changeset
   180
        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
   181
            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
   182
        options = []
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   183
        optgroup_opened = False
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
   184
        for label, value in field.vocabulary(form):
1336
2e552353c42a insert an optgroup as separator on None values
sylvain.thenault@logilab.fr
parents: 1330
diff changeset
   185
            if value is None:
2e552353c42a insert an optgroup as separator on None values
sylvain.thenault@logilab.fr
parents: 1330
diff changeset
   186
                # handle separator
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   187
                if optgroup_opened:
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   188
                    options.append(u'</optgroup>')
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   189
                options.append(u'<optgroup label="%s">' % (label or ''))
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   190
                optgroup_opened = True
1336
2e552353c42a insert an optgroup as separator on None values
sylvain.thenault@logilab.fr
parents: 1330
diff changeset
   191
            elif value in curvalues:
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   192
                options.append(tags.option(label, value=value, selected='selected'))
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   193
            else:
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   194
                options.append(tags.option(label, value=value))
1771
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   195
        if optgroup_opened:
bb9538d91465 fix <optgroup> tag cannot be empty according to DTD
Florent <florent@secondweb.fr>
parents: 1768
diff changeset
   196
            options.append(u'</optgroup>')
1541
ddddbb748355 [widgets] an option for Select to show sorted content
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 1538
diff changeset
   197
        return tags.select(name=name, multiple=self._multiple,
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   198
                           options=options, **attrs)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   199
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   200
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   201
class CheckBox(Input):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   202
    """<input type='checkbox'>, for field having a specific vocabulary. One
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   203
    input will be generated for each possible value.
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
    type = 'checkbox'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   206
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   207
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   208
        name, curvalues, attrs = self._render_attrs(form, field)
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   209
        domid = attrs.pop('id', None)
1874
Florent <florent@secondweb.fr>
parents: 1873
diff changeset
   210
        sep = attrs.pop('separator', u'<br/>')
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   211
        options = []
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   212
        for i, (label, value) in enumerate(field.vocabulary(form)):
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   213
            iattrs = attrs.copy()
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   214
            if i == 0 and domid is not None:
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   215
                iattrs['id'] = domid
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   216
            if value in curvalues:
1367
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   217
                iattrs['checked'] = u'checked'
01bb5b727fe3 set dom id on the first input of radio choices
sylvain.thenault@logilab.fr
parents: 1359
diff changeset
   218
            tag = tags.input(name=name, type=self.type, value=value, **iattrs)
1873
e96f50e52099 allow easy arbitrary separator between checkbox/ radio widgets
Florent <florent@secondweb.fr>
parents: 1832
diff changeset
   219
            options.append(tag + label + sep)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   220
        return '\n'.join(options)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   221
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   222
1832
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   223
class Radio(CheckBox):
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   224
    """<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
   225
    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
   226
    """
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   227
    type = 'radio'
3384264d25cc fix CheckBox multiple dom id and refactor with Radio
Florent <florent@secondweb.fr>
parents: 1771
diff changeset
   228
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   229
# javascript widgets ###########################################################
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   230
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   231
class DateTimePicker(TextInput):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   232
    """<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
   233
    fields
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   234
    """
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   235
    monthnames = ('january', 'february', 'march', 'april',
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   236
                  'may', 'june', 'july', 'august',
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   237
                  'september', 'october', 'november', 'december')
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   238
    daynames = ('monday', 'tuesday', 'wednesday', 'thursday',
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   239
                'friday', 'saturday', 'sunday')
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   240
1311
4cc6e2723dc7 move ajax.js to base form class
sylvain.thenault@logilab.fr
parents: 1304
diff changeset
   241
    needs_js = ('cubicweb.calendar.js',)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   242
    needs_css = ('cubicweb.calendar_popup.css',)
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   243
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   244
    @classmethod
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   245
    def add_localized_infos(cls, req):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   246
        """inserts JS variables defining localized months and days"""
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   247
        # import here to avoid dependancy from cubicweb-common to simplejson
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   248
        _ = req._
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   249
        monthnames = [_(mname) for mname in cls.monthnames]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   250
        daynames = [_(dname) for dname in cls.daynames]
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   251
        req.html_headers.define_var('MONTHNAMES', monthnames)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   252
        req.html_headers.define_var('DAYNAMES', daynames)
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   253
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   254
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   255
        txtwidget = super(DateTimePicker, self).render(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   256
        self.add_localized_infos(form.req)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   257
        cal_button = self._render_calendar_popup(form, field)
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   258
        return txtwidget + cal_button
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   259
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   260
    def _render_calendar_popup(self, form, field):
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
   261
        value = form.form_field_value(field)
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
   262
        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
   263
            value = date.today()
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   264
        inputid = form.context[field]['id']
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   265
        helperid = '%shelper' % inputid
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   266
        year, month = value.year, value.month
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   267
        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
   268
<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
   269
                % (helperid, inputid, year, month,
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
   270
                   form.req.external_resource('CALENDAR_ICON'),
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
   271
                   form.req._('calendar'), helperid) )
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   272
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   273
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   274
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   275
# ajax widgets ################################################################
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   276
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   277
def init_ajax_attributes(attrs, wdgtype, loadtype=u'auto'):
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   278
    try:
1344
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   279
        attrs['klass'] += u' widget'
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   280
    except KeyError:
1344
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   281
        attrs['klass'] = u'widget'
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   282
    attrs.setdefault('cubicweb:wdgtype', wdgtype)
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   283
    attrs.setdefault('cubicweb:loadtype', loadtype)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   284
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   285
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   286
class AjaxWidget(FieldWidget):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   287
    """simple <div> based ajax widget"""
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   288
    def __init__(self, wdgtype, inputid=None, **kwargs):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   289
        super(AjaxWidget, self).__init__(**kwargs)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   290
        init_ajax_attributes(self.attrs, wdgtype)
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   291
        if inputid is not None:
1344
930020cb134b shouldn't use unicode keys in attrs
sylvain.thenault@logilab.fr
parents: 1337
diff changeset
   292
            self.attrs['cubicweb:inputid'] = inputid
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   293
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   294
    def render(self, form, field):
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   295
        self.add_media(form)
1147
402e8a8b1d6a more form works
sylvain.thenault@logilab.fr
parents: 1110
diff changeset
   296
        attrs = self._render_attrs(form, field)[-1]
1081
f2a85f52b9e5 move fields and widgets to their own module
sylvain.thenault@logilab.fr
parents:
diff changeset
   297
        return tags.div(**attrs)
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   298
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   299
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   300
class AutoCompletionWidget(TextInput):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   301
    """ajax widget for StringField, proposing matching existing values as you
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   302
    type.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   303
    """
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   304
    needs_js = ('cubicweb.widgets.js', 'jquery.autocomplete.js')
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   305
    needs_css = ('jquery.autocomplete.css',)
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   306
    wdgtype = 'SuggestField'
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   307
    loadtype = 'auto'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   308
1966
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   309
    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
   310
        try:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   311
            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
   312
        except KeyError:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   313
            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
   314
                 '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
   315
                 '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
   316
                 DeprecationWarning)
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   317
            self.autocomplete_initfunc = None
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   318
        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
   319
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   320
    def _render_attrs(self, form, field):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   321
        name, values, attrs = super(AutoCompletionWidget, self)._render_attrs(form, field)
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   322
        init_ajax_attributes(attrs, self.wdgtype, self.loadtype)
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   323
        # XXX entity form specific
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   324
        attrs['cubicweb:dataurl'] = self._get_url(form.edited_entity, field)
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   325
        return name, values, attrs
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   326
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   327
    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
   328
        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
   329
            # XXX for bw compat
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   330
            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
   331
        else:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   332
            fname = self.autocomplete_initfunc
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   333
        return entity.req.build_url('json', fname=fname, mode='remote',
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   334
                                    pageid=entity.req.pageid)
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   335
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   336
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   337
class StaticFileAutoCompletionWidget(AutoCompletionWidget):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   338
    """XXX describe me"""
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   339
    wdgtype = 'StaticFileSuggestField'
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   340
1875
7bcb02377516 no rschema attribute on widgets
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1874
diff changeset
   341
    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
   342
        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
   343
            # XXX for bw compat
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   344
            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
   345
        else:
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   346
            fname = self.autocomplete_initfunc
87ce7d336393 stop using autocomplete_initfuncs dict on entity classes
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1934
diff changeset
   347
        return entity.req.datadir_url + fname
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   348
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   349
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   350
class RestrictedAutoCompletionWidget(AutoCompletionWidget):
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   351
    """XXX describe me"""
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   352
    wdgtype = 'RestrictedSuggestField'
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   353
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   354
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   355
class AddComboBoxWidget(Select):
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   356
    def _render_attrs(self, form, field):
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   357
        name, values, attrs = super(AddComboBoxWidget, self)._render_attrs(form, field)
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   358
        init_ajax_attributes(self.attrs, 'AddComboBox')
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   359
        # XXX entity form specific
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   360
        entity = form.edited_entity
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   361
        attrs['cubicweb:etype_to'] = entity.e_schema
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   362
        etype_from = entity.e_schema.subject_relation(self.name).objects(entity.e_schema)[0]
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   363
        attrs['cubicweb:etype_from'] = etype_from
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   364
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   365
    def render(self, form, field):
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   366
        return super(AddComboBoxWidget, self).render(form, field) + u'''
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   367
<div id="newvalue">
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   368
  <input type="text" id="newopt" />
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   369
  <a href="javascript:noop()" id="add_newopt">&nbsp;</a></div>
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   370
'''
1359
bef6891393d7 backport some tests
sylvain.thenault@logilab.fr
parents: 1344
diff changeset
   371
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   372
# buttons ######################################################################
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   373
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   374
class Button(Input):
1389
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   375
    """<input type='button'>, base class for global form buttons
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   376
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   377
    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
   378
    should not give an already translated string.
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   379
    """
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   380
    type = 'button'
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   381
    def __init__(self, label=stdmsgs.BUTTON_OK, attrs=None,
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   382
                 setdomid=None, settabindex=None,
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   383
                 name='', value='', onclick=None, cwaction=None):
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   384
        super(Button, self).__init__(attrs, setdomid, settabindex)
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   385
        self.label = label
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   386
        self.name = name
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   387
        self.value = ''
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   388
        self.onclick = onclick
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   389
        self.cwaction = cwaction
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   390
        self.attrs.setdefault('klass', 'validateButton')
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   391
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   392
    def render(self, form, field=None):
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   393
        label = form.req._(self.label)
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   394
        attrs = self.attrs.copy()
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   395
        if self.cwaction:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   396
            assert self.onclick is None
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   397
            attrs['onclick'] = "postForm('__action_%s', \'%s\', \'%s\')" % (
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   398
                self.cwaction, self.label, form.domid)
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   399
        elif self.onclick:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   400
            attrs['onclick'] = self.onclick
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   401
        if self.name:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   402
            attrs['name'] = name
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   403
            if self.setdomid:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   404
                attrs['id'] = self.name
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   405
        if self.settabindex and not 'tabindex' in attrs:
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   406
            attrs['tabindex'] = form.req.next_tabindex()
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   407
        return tags.input(value=label, type=self.type, **attrs)
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   408
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   409
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   410
class SubmitButton(Button):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   411
    """<input type='submit'>, main button to submit a form"""
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   412
    type = 'submit'
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   413
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   414
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   415
class ResetButton(Button):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   416
    """<input type='reset'>, main button to reset a form.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   417
    You usually don't want this.
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   418
    """
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   419
    type = 'reset'
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   420
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   421
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   422
class ImgButton(object):
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   423
    """<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
   424
    javascript call)
1389
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   425
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   426
    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
   427
    should not give an already translated string.
1330
92343a468e2a add some documentation, backport *CompletionWidget
sylvain.thenault@logilab.fr
parents: 1329
diff changeset
   428
    """
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   429
    def __init__(self, domid, href, label, imgressource):
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   430
        self.domid = domid
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   431
        self.href = href
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   432
        self.imgressource = imgressource
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   433
        self.label = label
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   434
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   435
    def render(self, form, field=None):
1389
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   436
        label = form.req._(self.label)
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   437
        imgsrc = form.req.external_resource(self.imgressource)
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   438
        return '<a id="%(domid)s" href="%(href)s">'\
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   439
               '<img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % {
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   440
            'label': label, 'imgsrc': imgsrc,
ae58c2e7e1f7 clear label handling
sylvain.thenault@logilab.fr
parents: 1367
diff changeset
   441
            'domid': self.domid, 'href': self.href}
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   442
1304
8975c8e520a9 refactor button handling
sylvain.thenault@logilab.fr
parents: 1295
diff changeset
   443
1474
716f0742ee7f delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1425
diff changeset
   444
1337
828bbf500bcc backport AddComboBoxWidget, ajax widgets refactoring
sylvain.thenault@logilab.fr
parents: 1336
diff changeset
   445
# XXX EntityLinkComboBoxWidget, [Raw]DynamicComboBoxWidget