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] |