web/form.py
branchtls-sprint
changeset 903 63a8ab7eeb9c
parent 902 e4de959c76af
child 904 4f1ce95aa686
equal deleted inserted replaced
902:e4de959c76af 903:63a8ab7eeb9c
   253     def __init__(self, attrs=None):
   253     def __init__(self, attrs=None):
   254         self.attrs = attrs or {}
   254         self.attrs = attrs or {}
   255 
   255 
   256     def render(self, form, field):
   256     def render(self, form, field):
   257         raise NotImplementedError
   257         raise NotImplementedError
   258     
   258 
       
   259     def _render_attrs(self, form, field):
       
   260         # name = form.form_field_name(field)
       
   261         # values = form.form_field_value(field)
       
   262         name = form.context[field]['name']
       
   263         values = form.context[field]['value']
       
   264         if not isinstance(values, (tuple, list)):
       
   265             values = (values,)
       
   266         return name, values, dict(self.attrs)
       
   267 
   259 class Input(FieldWidget):
   268 class Input(FieldWidget):
   260     type = None
   269     type = None
   261     
   270     
   262     def render(self, form, field):
   271     def render(self, form, field):
   263         name, value, attrs = self._render_attrs(form, field)
   272         name, values, attrs = self._render_attrs(form, field)
   264         if attrs is None:
   273         inputs = [tags.input(name=name, value=value, type=self.type, **attrs)
   265             return tags.input(name=name, value=value)
   274                   for value in values]
   266         return tags.input(name=name, value=value, type=self.type, **attrs)
   275         return u'\n'.join(inputs)
   267 
   276 
   268     def _render_attrs(self, form, field):
       
   269         name = form.context[field]['name'] # qualified name
       
   270         value = form.context[field]['value']
       
   271         #fattrs = field.widget_attributes(self)
       
   272         attrs = self.attrs.copy()
       
   273         attrs['id'] = form.context[field]['id']
       
   274         #attrs.update(fattrs)
       
   275         # XXX id
       
   276         return name, value, attrs
       
   277     
       
   278 class TextInput(Input):
   277 class TextInput(Input):
   279     type = 'text'
   278     type = 'text'
   280 
   279 
   281 class PasswordInput(Input):
   280 class PasswordInput(Input):
   282     type = 'password'
   281     type = 'password'
   283 
   282 
   284 class FileInput(Input):
   283 class FileInput(Input):
   285     type = 'file'
   284     type = 'file'
   286     
       
   287     def _render_attrs(self, form, field):
       
   288         name = form.context[field]['name'] # qualified name
       
   289         return name, None, {}
       
   290 
   285 
   291 class HiddenInput(Input):
   286 class HiddenInput(Input):
   292     type = 'hidden'
   287     type = 'hidden'
   293     
   288     
   294 class Button(Input):
   289 class Button(Input):
   295     type = 'button'
   290     type = 'button'
   296 
   291 
   297 class TextArea(FieldWidget):
   292 class TextArea(FieldWidget):
   298     def render(self, form, field):
   293     def render(self, form, field):
   299         name, value, attrs = self._render_attrs(form, field)
   294         name, values, attrs = self._render_attrs(form, field)
   300         attrs.setdefault('onkeypress', 'autogrow(this)')
   295         attrs.setdefault('onkeypress', 'autogrow(this)')
       
   296         if not values:
       
   297             value = u''
       
   298         elif len(values) == 1:
       
   299             value = values[0]
       
   300         else:
       
   301             raise ValueError('a textarea is not supposed to be multivalued')
   301         return tags.textarea(value, name=name, **attrs)
   302         return tags.textarea(value, name=name, **attrs)
   302 
   303 
   303 class FCKEditor(TextArea):
   304 class FCKEditor(TextArea):
   304     def __init__(self, attrs):
   305     def __init__(self, attrs):
   305         super(FCKEditor, self).__init__(attrs)
   306         super(FCKEditor, self).__init__(attrs)
   313 #class EditableFile(Widget):
   314 #class EditableFile(Widget):
   314 #    # XXX
   315 #    # XXX
   315 #    pass
   316 #    pass
   316 
   317 
   317 class Select(FieldWidget):
   318 class Select(FieldWidget):
   318     def __init__(self, attrs=None, vocabulary=()):
   319     def __init__(self, attrs=None, multiple=False):
   319         super(Select, self).__init__(attrs)
   320         super(Select, self).__init__(attrs)
   320         self.multiple = multiple
   321         self.multiple = multiple
   321         
   322         
   322     def render(self, form, field):
   323     def render(self, form, field):
   323         name, value, attrs = self._render_attrs(form, field)
   324         name, curvalues, attrs = self._render_attrs(form, field)
   324         if self.vocabulary:
   325         vocab = field.vocabulary(form)
   325             # static vocabulary defined in form definition
       
   326             vocab = self.vocabulary
       
   327         else:
       
   328             vocab = form.get_vocabulary(field)
       
   329         options = []
   326         options = []
   330         for label, value in vocab:
   327         for label, value in vocab:
   331             options.append(tags.option(label, value=value))
   328             if value in curvalues:
       
   329                 options.append(tags.option(label, value=value, selected='selected'))
       
   330             else:
       
   331                 options.append(tags.option(label, value=value))
   332         if attrs is None:
   332         if attrs is None:
   333             return tags.select(name=name, options=options)
   333             return tags.select(name=name, options=options)
   334         return tags.select(name=name, multiple=self.multiple,
   334         return tags.select(name=name, multiple=self.multiple,
   335                            options=options, **attrs)
   335                            options=options, **attrs)
   336 
   336 
   437 
   437 
   438     def __repr__(self):
   438     def __repr__(self):
   439         return self.__unicode__().encode('utf-8')
   439         return self.__unicode__().encode('utf-8')
   440     
   440     
   441     def format_value(self, req, value):
   441     def format_value(self, req, value):
       
   442         if isinstance(value, (list, tuple)):
       
   443             return [self.format_single_value(req, val) for val in value]
       
   444         return self.format_single_value(req, value)
       
   445     
       
   446     def format_single_value(self, req, value):
       
   447         if value is None:
       
   448             return u''
   442         return unicode(value)
   449         return unicode(value)
   443 
   450 
   444     def get_widget(self, req):
   451     def get_widget(self, req):
   445         return self.widget
   452         return self.widget
   446 
   453 
   455     def __init__(self, max_length=None, **kwargs):
   462     def __init__(self, max_length=None, **kwargs):
   456         super(StringField, self).__init__(**kwargs)
   463         super(StringField, self).__init__(**kwargs)
   457         self.max_length = max_length
   464         self.max_length = max_length
   458 
   465 
   459 class TextField(Field):
   466 class TextField(Field):
   460     widget = TextArea
   467     def __init__(self, rows=10, cols=80, **kwargs):
   461     def __init__(self, row=None, col=None, **kwargs):
   468         widget = TextArea(dict(rows=rows, cols=cols))
   462         super(TextField, self).__init__(**kwargs)
   469         super(TextField, self).__init__(widget=widget, **kwargs)
   463         self.row = row
   470         self.rows = rows
   464         self.col = col
   471         self.cols = cols
   465 
       
   466 
   472 
   467 class RichTextField(TextField):
   473 class RichTextField(TextField):
   468     widget = None
   474     widget = None
   469     def __init__(self, format_field=None, **kwargs):
   475     def __init__(self, format_field=None, **kwargs):
   470         super(RichTextField, self).__init__(**kwargs)
   476         super(RichTextField, self).__init__(**kwargs)
   517     def __init__(self, min=None, max=None, **kwargs):
   523     def __init__(self, min=None, max=None, **kwargs):
   518         super(IntField, self).__init__(**kwargs)
   524         super(IntField, self).__init__(**kwargs)
   519         self.min = min
   525         self.min = min
   520         self.max = max
   526         self.max = max
   521 
   527 
       
   528 class BooleanField(Field):
       
   529     widget = Radio
       
   530 
   522 class FloatField(IntField):    
   531 class FloatField(IntField):    
   523     def format_value(self, req, value):
   532     def format_single_value(self, req, value):
   524         formatstr = entity.req.property_value('ui.float-format')
   533         formatstr = entity.req.property_value('ui.float-format')
   525         if value is None:
   534         if value is None:
   526             return u''
   535             return u''
   527         return formatstr % float(value)
   536         return formatstr % float(value)
   528 
   537 
   548                                                       eidparam=True)
   557                                                       eidparam=True)
   549         self.visible_field = visible_field
   558         self.visible_field = visible_field
   550     
   559     
   551                  
   560                  
   552 class RelationField(Field):
   561 class RelationField(Field):
   553     def __init__(self, role='subject', **kwargs):
   562     def __init__(self, **kwargs):
   554         super(RelationField, self).__init__(**kwargs)
   563         super(RelationField, self).__init__(**kwargs)
   555 
   564 
   556     @staticmethod
   565     @staticmethod
   557     def fromcardinality(card, role, **kwargs):
   566     def fromcardinality(card, role, **kwargs):
   558         return RelationField(widget=Select(multiple=card in '*+'),
   567         return RelationField(widget=Select(multiple=card in '*+'),
   629     @property
   638     @property
   630     def form_needs_multipart(self):
   639     def form_needs_multipart(self):
   631         return any(field.needs_multipart for field in self.fields) 
   640         return any(field.needs_multipart for field in self.fields) 
   632 
   641 
   633     def form_add_hidden(self, name, value=None, **kwargs):
   642     def form_add_hidden(self, name, value=None, **kwargs):
   634         self.fields.append(TextField(name=name, widget=HiddenInput,
   643         self.fields.append(StringField(name=name, widget=HiddenInput,
   635                                      initial=value, **kwargs))
   644                                        initial=value, **kwargs))
   636 
   645 
   637     def form_render(self, **values):
   646     def form_render(self, **values):
   638         renderer = values.pop('renderer', FormRenderer())
   647         renderer = values.pop('renderer', FormRenderer())
   639         return renderer.render(self, values)
   648         return renderer.render(self, values)
   640 
   649 
   736         """
   745         """
   737         fieldname = field.name
   746         fieldname = field.name
   738         if fieldname.startswith('edits-') or fieldname.startswith('edito-'):
   747         if fieldname.startswith('edits-') or fieldname.startswith('edito-'):
   739             # edit[s|o]- fieds must have the actual value stored on the entity
   748             # edit[s|o]- fieds must have the actual value stored on the entity
   740             if self.entity.has_eid():
   749             if self.entity.has_eid():
   741                 value = self.form_field_entity_value(field, default_initial=False)
   750                 value = self.form_field_entity_value(field.visible_field, default_initial=False)
   742             else:
   751             else:
   743                 value = INTERNAL_FIELD_VALUE
   752                 value = INTERNAL_FIELD_VALUE
   744         elif fieldname == '__type':
   753         elif fieldname == '__type':
   745             value = self.entity.id
   754             value = self.entity.id
   746         elif fieldname == 'eid':
   755         elif fieldname == 'eid':
   747             value = self.entity.eid
   756             value = self.entity.eid
   748         elif fieldname in values:
   757         elif fieldname in values:
   749             value = values[fieldname]
   758             value = values[fieldname]
   750         elif fieldname in self.req.form:
   759         elif fieldname in self.req.form:
   751             value = self.req.form[fieldname]
   760             value = self.req.form[fieldname]
       
   761         elif isinstance(field, FileField):
       
   762             return None # XXX manage FileField
   752         else:
   763         else:
   753             if self.entity.has_eid() and field.eidparam:
   764             if self.entity.has_eid() and field.eidparam:
   754                 # use value found on the entity or field's initial value if it's
   765                 # use value found on the entity or field's initial value if it's
   755                 # not an attribute of the entity (XXX may conflicts and get
   766                 # not an attribute of the entity (XXX may conflicts and get
   756                 # undesired value)
   767                 # undesired value)
   782     def form_field_entity_value(self, field, default_initial=True):
   793     def form_field_entity_value(self, field, default_initial=True):
   783         attr = field.name 
   794         attr = field.name 
   784         if field.role == 'object':
   795         if field.role == 'object':
   785             attr += '_object'
   796             attr += '_object'
   786         if default_initial:
   797         if default_initial:
   787             return getattr(self.entity, attr, field.initial)
   798             value = getattr(self.entity, attr, field.initial)
   788         else:
   799         else:
   789             return getattr(self.entity, attr)
   800             value = getattr(self.entity, attr)
   790         
   801         if isinstance(field, RelationField):
       
   802             # in this case, value is the list of related entities
       
   803             value = [ent.eid for ent in value]
       
   804         return value
       
   805     
   791     def form_field_name(self, field):
   806     def form_field_name(self, field):
   792         if field.eidparam:
   807         if field.eidparam:
   793             return eid_param(field.name, self.entity.eid)
   808             return eid_param(field.name, self.entity.eid)
   794         return field.name
   809         return field.name
   795 
   810 
   797         if field.eidparam:
   812         if field.eidparam:
   798             return eid_param(field.id, self.entity.eid)
   813             return eid_param(field.id, self.entity.eid)
   799         return field.id
   814         return field.id
   800         
   815         
   801     def form_field_vocabulary(self, field):
   816     def form_field_vocabulary(self, field):
   802         choices = self.vocabfunc(entity)
   817         role, rtype = field.role, field.name
   803         if self.sort:
   818         try:
   804             choices = sorted(choices)
   819             vocabfunc = getattr(self.entity, '%s_%s_vocabulary' % (role, rtype))
   805         if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'):
   820         except AttributeError:
   806             return zip((entity.req._(v) for v in choices), choices)
   821             vocabfunc = getattr(self, '%s_relation_vocabulary' % role)
   807         return zip(choices, choices)
   822         else:
       
   823             # XXX bw compat, default_<field name> on the entity
       
   824             warn('found %s_%s_vocabulary on %s, should be set on a specific form'
       
   825                  % (role, rtype, self.entity.id), DeprecationWarning)
       
   826         return vocabfunc(rtype)
       
   827 ## XXX BACKPORT ME
       
   828 ##         if self.sort:
       
   829 ##             choices = sorted(choices)
       
   830 ##         if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'):
       
   831 ##             return zip((entity.req._(v) for v in choices), choices)
   808 
   832 
   809     def subject_relation_vocabulary(self, rtype, limit=None):
   833     def subject_relation_vocabulary(self, rtype, limit=None):
   810         """defaut vocabulary method for the given relation, looking for
   834         """defaut vocabulary method for the given relation, looking for
   811         relation's object entities (i.e. self is the subject)
   835         relation's object entities (i.e. self is the subject)
   812         """
   836         """