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