21 from cubicweb import tags, uilib |
21 from cubicweb import tags, uilib |
22 from cubicweb.web import INTERNAL_FIELD_VALUE, ProcessFormError, eid_param |
22 from cubicweb.web import INTERNAL_FIELD_VALUE, ProcessFormError, eid_param |
23 from cubicweb.web.formwidgets import ( |
23 from cubicweb.web.formwidgets import ( |
24 HiddenInput, TextInput, FileInput, PasswordInput, TextArea, FCKEditor, |
24 HiddenInput, TextInput, FileInput, PasswordInput, TextArea, FCKEditor, |
25 Radio, Select, DateTimePicker) |
25 Radio, Select, DateTimePicker) |
|
26 |
|
27 |
|
28 class UnmodifiedField(Exception): |
|
29 """raise this when a field has not actually been edited and you want to skip |
|
30 it |
|
31 """ |
26 |
32 |
27 |
33 |
28 def vocab_sort(vocab): |
34 def vocab_sort(vocab): |
29 """sort vocabulary, considering option groups""" |
35 """sort vocabulary, considering option groups""" |
30 result = [] |
36 result = [] |
359 return widget.process_field_data(form, self) |
365 return widget.process_field_data(form, self) |
360 |
366 |
361 def process_posted(self, form): |
367 def process_posted(self, form): |
362 for field in self.actual_fields(form): |
368 for field in self.actual_fields(form): |
363 if field is self: |
369 if field is self: |
364 yield field, field.process_form_value(form) |
370 try: |
|
371 yield field, field.process_form_value(form) |
|
372 except UnmodifiedField: |
|
373 continue |
365 else: |
374 else: |
366 # recursive function: we might have compound fields |
375 # recursive function: we might have compound fields |
367 # of compound fields (of compound fields of ...) |
376 # of compound fields (of compound fields of ...) |
368 for field, value in field.process_posted(form): |
377 for field, value in field.process_posted(form): |
369 yield field, value |
378 yield field, value |
548 + u'<br/>') |
557 + u'<br/>') |
549 |
558 |
550 def process_form_value(self, form): |
559 def process_form_value(self, form): |
551 posted = form._cw.form |
560 posted = form._cw.form |
552 if self.input_name(form, u'__detach') in posted: |
561 if self.input_name(form, u'__detach') in posted: |
553 # drop current file value |
562 # drop current file value on explictily asked to detach |
|
563 return None |
|
564 try: |
|
565 value = posted[self.input_name(form)] |
|
566 except KeyError: |
|
567 # raise UnmodifiedField instead of returning None, since the later |
|
568 # will try to remove already attached file if any |
|
569 raise UnmodifiedField() |
|
570 # skip browser submitted mime type |
|
571 filename, _, stream = value |
|
572 # value is a 3-uple (filename, mimetype, stream) |
|
573 value = Binary(stream.read()) |
|
574 if not val.getvalue(): # usually an unexistant file |
554 value = None |
575 value = None |
555 else: |
576 else: |
556 value = posted.get(self.input_name(form)) |
577 # set filename on the Binary instance, may be used later in hooks |
557 # no need to check value when nor explicit detach nor new file |
578 value.filename = filename |
558 # submitted, since it will think the attribute is not modified |
|
559 if value: |
|
560 filename, _, stream = value |
|
561 # value is a 3-uple (filename, mimetype, stream) |
|
562 value = Binary(stream.read()) |
|
563 if not val.getvalue(): # usually an unexistant file |
|
564 value = None |
|
565 else: |
|
566 value.filename = filename |
|
567 return value |
579 return value |
568 |
580 |
569 |
581 |
570 class EditableFileField(FileField): |
582 class EditableFileField(FileField): |
571 editable_formats = ('text/plain', 'text/html', 'text/rest') |
583 editable_formats = ('text/plain', 'text/html', 'text/rest') |