web/formfields.py
branchtls-sprint
changeset 1265 e5cdd5c0dce3
parent 1181 620ec8e6ae19
child 1268 5db94912650b
equal deleted inserted replaced
1264:fe2934a7df7f 1265:e5cdd5c0dce3
    13 
    13 
    14 from cubicweb.schema import FormatConstraint
    14 from cubicweb.schema import FormatConstraint
    15 from cubicweb.utils import ustrftime
    15 from cubicweb.utils import ustrftime
    16 from cubicweb.common import tags, uilib
    16 from cubicweb.common import tags, uilib
    17 from cubicweb.web import INTERNAL_FIELD_VALUE
    17 from cubicweb.web import INTERNAL_FIELD_VALUE
    18 from cubicweb.web.formwidgets import (HiddenInput, TextInput, FileInput, PasswordInput,
    18 from cubicweb.web.formwidgets import (
    19                                       TextArea, FCKEditor, Radio, Select,
    19     HiddenInput, TextInput, FileInput, PasswordInput, TextArea, FCKEditor,
    20                                       DateTimePicker) 
    20     Radio, Select, DateTimePicker) 
    21 
    21 
    22 class Field(object):
    22 class Field(object):
    23     """field class is introduced to control what's displayed in edition form
    23     """field class is introduced to control what's displayed in forms. It makes
       
    24     the link between something to edit and its display in the form. Actual
       
    25     display is handled by a widget associated to the field.
       
    26 
       
    27     Attributes
       
    28     ----------
       
    29     all the attributes described below have sensible default value which may be
       
    30     overriden by value given to field's constructor.
       
    31     
       
    32     :name:
       
    33        name of the field (basestring), should be unique in a form.
       
    34     :id:
       
    35        dom identifier (default to the same value as `name`), should be unique in
       
    36        a form.
       
    37     :label:
       
    38        label of the field (default to the same value as `name`).
       
    39     :help:
       
    40        help message about this field.
       
    41     :widget:
       
    42        widget associated to the field. Each field class has a default widget
       
    43        class which may be overriden per instance.
       
    44     :required:
       
    45        bool flag telling if the field is required or not.
       
    46     :initial:
       
    47        initial value, used when no value specified by other means.
       
    48     :choices:
       
    49        static vocabulary for this field. May be a list of values or a list of
       
    50        (label, value) tuples if specified.
       
    51     :sort:
       
    52        bool flag telling if the vocabulary (either static vocabulary specified
       
    53        in `choices` or dynamic vocabulary fetched from the form) should be
       
    54        sorted on label.
       
    55     :internationalizable:
       
    56        bool flag telling if the vocabulary labels should be translated using the
       
    57        current request language.
       
    58     :eidparam:
       
    59        bool flag telling if this field is linked to a specific entity
       
    60     :role:
       
    61        when the field is linked to an entity attribute or relation, tells the
       
    62        role of the entity in the relation (eg 'subject' or 'object')
       
    63     
    24     """
    64     """
       
    65     # default widget associated to this class of fields. May be overriden per
       
    66     # instance
    25     widget = TextInput
    67     widget = TextInput
       
    68     # does this field requires a multipart form
    26     needs_multipart = False
    69     needs_multipart = False
    27     creation_rank = 0
    70     # class attribute used for ordering of fields in a form
    28 
    71     __creation_rank = 0
    29     def __init__(self, name=None, id=None, label=None,
    72 
       
    73     def __init__(self, name=None, id=None, label=None, help=None, 
    30                  widget=None, required=False, initial=None,
    74                  widget=None, required=False, initial=None,
    31                  choices=None, help=None, eidparam=False, role='subject'):
    75                  choices=None, sort=True, internationalizable=False,
       
    76                  eidparam=False, role='subject'):
       
    77         self.name = name
       
    78         self.id = id or name
       
    79         self.label = label or name
       
    80         self.help = help
    32         self.required = required
    81         self.required = required
    33         if widget is not None:
    82         if widget is not None:
    34             self.widget = widget
    83             self.widget = widget
    35         if isinstance(self.widget, type):
    84         if isinstance(self.widget, type):
    36             self.widget = self.widget()
    85             self.widget = self.widget()
    37         self.name = name
       
    38         self.label = label or name
       
    39         self.id = id or name
       
    40         self.initial = initial
    86         self.initial = initial
    41         self.choices = choices
    87         self.choices = choices
    42         self.help = help
    88         self.sort = sort
       
    89         self.internationalizable = internationalizable
    43         self.eidparam = eidparam
    90         self.eidparam = eidparam
    44         self.role = role
    91         self.role = role
    45         # global fields ordering in forms
    92         # ordering number for this field instance
    46         self.creation_rank = Field.creation_rank
    93         self.creation_rank = Field.__creation_rank
    47         Field.creation_rank += 1
    94         Field.__creation_rank += 1
    48     
    95     
    49     def __unicode__(self):
    96     def __unicode__(self):
    50         return u'<%s name=%r label=%r id=%r initial=%r @%x>' % (
    97         return u'<%s name=%r label=%r id=%r initial=%r @%x>' % (
    51             self.__class__.__name__, self.name, self.label,
    98             self.__class__.__name__, self.name, self.label,
    52             self.id, self.initial, id(self))
    99             self.id, self.initial, id(self))
    53 
   100 
    54     def __repr__(self):
   101     def __repr__(self):
    55         return self.__unicode__().encode('utf-8')
   102         return self.__unicode__().encode('utf-8')
    56 
   103 
    57     def set_name(self, name):
   104     def set_name(self, name):
       
   105         """automatically set .id and .label when name is set"""
    58         assert name
   106         assert name
    59         self.name = name
   107         self.name = name
    60         if not self.id:
   108         if not self.id:
    61             self.id = name
   109             self.id = name
    62         if not self.label:
   110         if not self.label:
    63             self.label = name
   111             self.label = name
    64             
   112             
    65     def is_visible(self):
   113     def is_visible(self):
       
   114         """return true if the field is not an hidden field"""
    66         return not isinstance(self.widget, HiddenInput)
   115         return not isinstance(self.widget, HiddenInput)
    67     
   116     
    68     def actual_fields(self, form):
   117     def actual_fields(self, form):
       
   118         """return actual fields composing this field in case of a compound
       
   119         field, usually simply return self
       
   120         """
    69         yield self
   121         yield self
    70     
   122     
    71     def format_value(self, req, value):
   123     def format_value(self, req, value):
       
   124         """return value suitable for display where value may be a list or tuple
       
   125         of values
       
   126         """
    72         if isinstance(value, (list, tuple)):
   127         if isinstance(value, (list, tuple)):
    73             return [self.format_single_value(req, val) for val in value]
   128             return [self.format_single_value(req, val) for val in value]
    74         return self.format_single_value(req, value)
   129         return self.format_single_value(req, value)
    75     
   130     
    76     def format_single_value(self, req, value):
   131     def format_single_value(self, req, value):
       
   132         """return value suitable for display"""
    77         if value is None:
   133         if value is None:
    78             return u''
   134             return u''
    79         return unicode(value)
   135         return unicode(value)
    80 
   136 
    81     def get_widget(self, form):
   137     def get_widget(self, form):
       
   138         """return the widget instance associated to this field"""
    82         return self.widget
   139         return self.widget
    83     
   140     
    84     def example_format(self, req):
   141     def example_format(self, req):
       
   142         """return a sample string describing what can be given as input for this
       
   143         field
       
   144         """        
    85         return u''
   145         return u''
    86 
   146 
    87     def render(self, form, renderer):
   147     def render(self, form, renderer):
       
   148         """render this field, which is part of form, using the given form
       
   149         renderer
       
   150         """
    88         return self.get_widget(form).render(form, self)
   151         return self.get_widget(form).render(form, self)
    89 
   152 
    90     def vocabulary(self, form):
   153     def vocabulary(self, form):
       
   154         """return vocabulary for this field. This method will be called by
       
   155         widgets which desire it."""        
    91         if self.choices is not None:
   156         if self.choices is not None:
    92             if callable(self.choices):
   157             if callable(self.choices):
    93                 vocab = self.choices(req=form.req)
   158                 vocab = self.choices(req=form.req)
    94             else:
   159             else:
    95                 vocab = self.choices
   160                 vocab = self.choices
    96             if vocab and not isinstance(vocab[0], (list, tuple)):
   161             if vocab and not isinstance(vocab[0], (list, tuple)):
    97                 vocab = [(x, x) for x in vocab]
   162                 vocab = [(x, x) for x in vocab]
    98             return vocab
   163         else:
    99         return form.form_field_vocabulary(self)
   164             vocab = form.form_field_vocabulary(self)
       
   165         if self.internationalizable:
       
   166             vocab = [(form.req._(label), value) for label, value in vocab]
       
   167         if self.sort:
       
   168             vocab = sorted(vocab)
       
   169         return vocab
   100 
   170 
   101     
   171     
   102 class StringField(Field):
   172 class StringField(Field):
   103     def __init__(self, max_length=None, **kwargs):
   173     def __init__(self, max_length=None, **kwargs):
   104         super(StringField, self).__init__(**kwargs)
   174         super(StringField, self).__init__(**kwargs)
   367     fieldclass = None
   437     fieldclass = None
   368     eschema = eclass.e_schema
   438     eschema = eclass.e_schema
   369     if role == 'subject':
   439     if role == 'subject':
   370         targetschema = rschema.objects(eschema)[0]
   440         targetschema = rschema.objects(eschema)[0]
   371         card = rschema.rproperty(eschema, targetschema, 'cardinality')[0]
   441         card = rschema.rproperty(eschema, targetschema, 'cardinality')[0]
       
   442         if rschema.is_final():
       
   443             if rschema.rproperty(eschema, targetschema, 'internationalizable'):
       
   444                 kwargs['internationalizable'] = True
       
   445             kwargs['initial'] = rschema.rproperty(eschema, targetschema, 'default')
   372     else:
   446     else:
   373         targetschema = rschema.subjects(eschema)[0]
   447         targetschema = rschema.subjects(eschema)[0]
   374         card = rschema.rproperty(targetschema, eschema, 'cardinality')[1]
   448         card = rschema.rproperty(targetschema, eschema, 'cardinality')[1]
   375     kwargs['required'] = card in '1+'
   449     kwargs['required'] = card in '1+'
   376     kwargs['name'] = rschema.type
   450     kwargs['name'] = rschema.type