web/formfields.py
changeset 3388 b8be8fc77c27
parent 3347 428f95118556
parent 3387 a357d4147eee
child 3451 6b46d73823f5
equal deleted inserted replaced
3369:7b88d12b4ee2 3388:b8be8fc77c27
   212         """method called before by form_build_context to trigger potential field
   212         """method called before by form_build_context to trigger potential field
   213         initialization requiring the form instance
   213         initialization requiring the form instance
   214         """
   214         """
   215         pass
   215         pass
   216 
   216 
       
   217     def process_form_value(self, form):
       
   218         """process posted form and return correctly typed value"""
       
   219         widget = self.get_widget(form)
       
   220         return widget.process_field_data(form, self)
       
   221 
       
   222     def process_posted(self, form):
       
   223         for field in self.actual_fields(form):
       
   224             if field is self:
       
   225                 yield field.name, field.process_form_value(form)
       
   226             else:
       
   227                 # recursive function: we might have compound fields
       
   228                 # of compound fields (of compound fields of ...)
       
   229                 for fieldname, value in field.process_posted(form):
       
   230                     yield fieldname, value
       
   231 
   217 
   232 
   218 class StringField(Field):
   233 class StringField(Field):
   219     widget = TextArea
   234     widget = TextArea
   220 
   235 
   221     def __init__(self, max_length=None, **kwargs):
   236     def __init__(self, max_length=None, **kwargs):
   284                 fkwargs['widget'] = Select()
   299                 fkwargs['widget'] = Select()
   285                 fcstr = FormatConstraint()
   300                 fcstr = FormatConstraint()
   286                 fkwargs['choices'] = fcstr.vocabulary(form=form)
   301                 fkwargs['choices'] = fcstr.vocabulary(form=form)
   287                 fkwargs['internationalizable'] = True
   302                 fkwargs['internationalizable'] = True
   288                 fkwargs['initial'] = lambda f: f.form_field_format(self)
   303                 fkwargs['initial'] = lambda f: f.form_field_format(self)
       
   304             fkwargs['eidparam'] = self.eidparam
   289             field = StringField(name=self.name + '_format', **fkwargs)
   305             field = StringField(name=self.name + '_format', **fkwargs)
   290             req.data[self] = field
   306             req.data[self] = field
   291             return field
   307             return field
   292 
   308 
   293     def actual_fields(self, form):
   309     def actual_fields(self, form):
   358     def render_subfield(self, form, field, renderer):
   374     def render_subfield(self, form, field, renderer):
   359         return (renderer.render_label(form, field)
   375         return (renderer.render_label(form, field)
   360                 + field.render(form, renderer)
   376                 + field.render(form, renderer)
   361                 + renderer.render_help(form, field)
   377                 + renderer.render_help(form, field)
   362                 + u'<br/>')
   378                 + u'<br/>')
       
   379 
       
   380     def process_form_value(self, form):
       
   381         posted = form.req.form
       
   382         value = posted.get(form.form_field_name(self))
       
   383         formkey = form.form_field_name(self)
       
   384         if ('%s__detach' % form.context[self]['name']) in posted:
       
   385             # drop current file value
       
   386             value = None
       
   387         # no need to check value when nor explicit detach nor new file
       
   388         # submitted, since it will think the attribute is not modified
       
   389         elif value:
       
   390             filename, _, stream = value
       
   391             # value is a  3-uple (filename, mimetype, stream)
       
   392             value = Binary(stream.read())
       
   393             if not val.getvalue(): # usually an unexistant file
       
   394                 value = None
       
   395             else:
       
   396                 value.filename = filename
       
   397         return value
   363 
   398 
   364 
   399 
   365 class EditableFileField(FileField):
   400 class EditableFileField(FileField):
   366     editable_formats = ('text/plain', 'text/html', 'text/rest')
   401     editable_formats = ('text/plain', 'text/html', 'text/rest')
   367 
   402 
   389                     wdgs.append(u'<p><b>%s</b></p>' % msg)
   424                     wdgs.append(u'<p><b>%s</b></p>' % msg)
   390                     wdgs.append(TextArea(setdomid=False).render(form, self, renderer))
   425                     wdgs.append(TextArea(setdomid=False).render(form, self, renderer))
   391                     # XXX restore form context?
   426                     # XXX restore form context?
   392         return '\n'.join(wdgs)
   427         return '\n'.join(wdgs)
   393 
   428 
       
   429     def process_form_value(self, form):
       
   430         value = form.req.form.get(form.form_field_name(self))
       
   431         if isinstance(value, unicode):
       
   432             # file modified using a text widget
       
   433             encoding = form.form_field_encoding(self)
       
   434             return Binary(value.encode(encoding))
       
   435         return super(EditableFileField, self).process_form_value(form)
       
   436 
   394 
   437 
   395 class IntField(Field):
   438 class IntField(Field):
   396     def __init__(self, min=None, max=None, **kwargs):
   439     def __init__(self, min=None, max=None, **kwargs):
   397         super(IntField, self).__init__(**kwargs)
   440         super(IntField, self).__init__(**kwargs)
   398         self.min = min
   441         self.min = min
   399         self.max = max
   442         self.max = max
   400         if isinstance(self.widget, TextInput):
   443         if isinstance(self.widget, TextInput):
   401             self.widget.attrs.setdefault('size', 5)
   444             self.widget.attrs.setdefault('size', 5)
   402             self.widget.attrs.setdefault('maxlength', 15)
   445             self.widget.attrs.setdefault('maxlength', 15)
   403 
   446 
       
   447     def process_form_value(self, form):
       
   448         return int(Field.process_form_value(self, form))
   404 
   449 
   405 class BooleanField(Field):
   450 class BooleanField(Field):
   406     widget = Radio
   451     widget = Radio
   407 
   452 
   408     def vocabulary(self, form):
   453     def vocabulary(self, form):
   409         if self.choices:
   454         if self.choices:
   410             return self.choices
   455             return self.choices
   411         return [(form.req._('yes'), '1'), (form.req._('no'), '')]
   456         return [(form.req._('yes'), '1'), (form.req._('no'), '')]
   412 
   457 
       
   458     def process_form_value(self, form):
       
   459         return bool(Field.process_form_value(self, form))
   413 
   460 
   414 class FloatField(IntField):
   461 class FloatField(IntField):
   415     def format_single_value(self, req, value):
   462     def format_single_value(self, req, value):
   416         formatstr = req.property_value('ui.float-format')
   463         formatstr = req.property_value('ui.float-format')
   417         if value is None:
   464         if value is None:
   419         return formatstr % float(value)
   466         return formatstr % float(value)
   420 
   467 
   421     def render_example(self, req):
   468     def render_example(self, req):
   422         return self.format_single_value(req, 1.234)
   469         return self.format_single_value(req, 1.234)
   423 
   470 
       
   471     def process_form_value(self, form):
       
   472         return float(Field.process_form_value(self, form))
   424 
   473 
   425 class DateField(StringField):
   474 class DateField(StringField):
   426     format_prop = 'ui.date-format'
   475     format_prop = 'ui.date-format'
   427     widget = DateTimePicker
   476     widget = DateTimePicker
   428 
   477 
   430         return value and ustrftime(value, req.property_value(self.format_prop)) or u''
   479         return value and ustrftime(value, req.property_value(self.format_prop)) or u''
   431 
   480 
   432     def render_example(self, req):
   481     def render_example(self, req):
   433         return self.format_single_value(req, datetime.now())
   482         return self.format_single_value(req, datetime.now())
   434 
   483 
       
   484     def process_form_value(self, form):
       
   485         # widget is supposed to return a date as a correctly formatted string
       
   486         date = Field.process_form_value(self, form)
       
   487         # but for some widgets, it might be simpler to return date objects
       
   488         # directly, so handle that case :
       
   489         if isinstance(date, basestring):
       
   490             date = form.parse_date(wdgdate, 'Date')
       
   491         return date
   435 
   492 
   436 class DateTimeField(DateField):
   493 class DateTimeField(DateField):
   437     format_prop = 'ui.datetime-format'
   494     format_prop = 'ui.datetime-format'
   438 
   495 
       
   496     def process_form_value(self, form):
       
   497         # widget is supposed to return a date as a correctly formatted string
       
   498         date = Field.process_form_value(self, form)
       
   499         # but for some widgets, it might be simpler to return date objects
       
   500         # directly, so handle that case :
       
   501         if isinstance(date, basestring):
       
   502             date = form.parse_datetime(wdgdate, 'Datetime')
       
   503         return date
   439 
   504 
   440 class TimeField(DateField):
   505 class TimeField(DateField):
   441     format_prop = 'ui.time-format'
   506     format_prop = 'ui.time-format'
   442     widget = TextInput
   507     widget = TextInput
   443 
   508 
   444 
   509     def process_form_value(self, form):
   445 class HiddenInitialValueField(Field):
   510         # widget is supposed to return a date as a correctly formatted string
   446     def __init__(self, visible_field):
   511         time = Field.process_form_value(self, form)
   447         name = 'edit%s-%s' % (visible_field.role[0], visible_field.name)
   512         # but for some widgets, it might be simpler to return time objects
   448         super(HiddenInitialValueField, self).__init__(
   513         # directly, so handle that case :
   449             name=name, widget=HiddenInput, eidparam=True)
   514         if isinstance(time, basestring):
   450         self.visible_field = visible_field
   515             time = form.parse_time(wdgdate, 'Time')
   451 
   516         return time
   452     def format_single_value(self, req, value):
       
   453         return self.visible_field.format_single_value(req, value)
       
   454 
       
   455 
   517 
   456 class RelationField(Field):
   518 class RelationField(Field):
   457     # XXX (syt): iirc, we originaly don't sort relation vocabulary since we want
   519     # XXX (syt): iirc, we originaly don't sort relation vocabulary since we want
   458     # to let entity.unrelated_rql control this, usually to get most recently
   520     # to let entity.unrelated_rql control this, usually to get most recently
   459     # modified entities in the select box instead of by alphabetical order. Now,
   521     # modified entities in the select box instead of by alphabetical order. Now,
   531     kwargs['name'] = rschema.type
   593     kwargs['name'] = rschema.type
   532     if role == 'object':
   594     if role == 'object':
   533         kwargs['label'] = (eschema.type + '_object', rschema.type)
   595         kwargs['label'] = (eschema.type + '_object', rschema.type)
   534     else:
   596     else:
   535         kwargs['label'] = (eschema.type, rschema.type)
   597         kwargs['label'] = (eschema.type, rschema.type)
       
   598     kwargs['eidparam'] = True
   536     kwargs.setdefault('help', help)
   599     kwargs.setdefault('help', help)
   537     if rschema.is_final():
   600     if rschema.is_final():
   538         if skip_meta_attr and rschema in eschema.meta_attributes():
   601         if skip_meta_attr and rschema in eschema.meta_attributes():
   539             return None
   602             return None
   540         fieldclass = FIELDS[targetschema]
   603         fieldclass = FIELDS[targetschema]