# HG changeset patch # User Adrien Di Mascio # Date 1235142244 -3600 # Node ID 63a8ab7eeb9ce117764bfac40f86a360bdc912a4 # Parent e4de959c76aff9f3abab7cab3650ae9ced5b77d4 The value as returned by FieldWidget._render_attrs() is now always a list diff -r e4de959c76af -r 63a8ab7eeb9c web/form.py --- a/web/form.py Fri Feb 20 16:03:01 2009 +0100 +++ b/web/form.py Fri Feb 20 16:04:04 2009 +0100 @@ -255,26 +255,25 @@ def render(self, form, field): raise NotImplementedError - + + def _render_attrs(self, form, field): + # name = form.form_field_name(field) + # values = form.form_field_value(field) + name = form.context[field]['name'] + values = form.context[field]['value'] + if not isinstance(values, (tuple, list)): + values = (values,) + return name, values, dict(self.attrs) + class Input(FieldWidget): type = None def render(self, form, field): - name, value, attrs = self._render_attrs(form, field) - if attrs is None: - return tags.input(name=name, value=value) - return tags.input(name=name, value=value, type=self.type, **attrs) + name, values, attrs = self._render_attrs(form, field) + inputs = [tags.input(name=name, value=value, type=self.type, **attrs) + for value in values] + return u'\n'.join(inputs) - def _render_attrs(self, form, field): - name = form.context[field]['name'] # qualified name - value = form.context[field]['value'] - #fattrs = field.widget_attributes(self) - attrs = self.attrs.copy() - attrs['id'] = form.context[field]['id'] - #attrs.update(fattrs) - # XXX id - return name, value, attrs - class TextInput(Input): type = 'text' @@ -283,10 +282,6 @@ class FileInput(Input): type = 'file' - - def _render_attrs(self, form, field): - name = form.context[field]['name'] # qualified name - return name, None, {} class HiddenInput(Input): type = 'hidden' @@ -296,8 +291,14 @@ class TextArea(FieldWidget): def render(self, form, field): - name, value, attrs = self._render_attrs(form, field) + name, values, attrs = self._render_attrs(form, field) attrs.setdefault('onkeypress', 'autogrow(this)') + if not values: + value = u'' + elif len(values) == 1: + value = values[0] + else: + raise ValueError('a textarea is not supposed to be multivalued') return tags.textarea(value, name=name, **attrs) class FCKEditor(TextArea): @@ -315,20 +316,19 @@ # pass class Select(FieldWidget): - def __init__(self, attrs=None, vocabulary=()): + def __init__(self, attrs=None, multiple=False): super(Select, self).__init__(attrs) self.multiple = multiple def render(self, form, field): - name, value, attrs = self._render_attrs(form, field) - if self.vocabulary: - # static vocabulary defined in form definition - vocab = self.vocabulary - else: - vocab = form.get_vocabulary(field) + name, curvalues, attrs = self._render_attrs(form, field) + vocab = field.vocabulary(form) options = [] for label, value in vocab: - options.append(tags.option(label, value=value)) + if value in curvalues: + options.append(tags.option(label, value=value, selected='selected')) + else: + options.append(tags.option(label, value=value)) if attrs is None: return tags.select(name=name, options=options) return tags.select(name=name, multiple=self.multiple, @@ -439,6 +439,13 @@ return self.__unicode__().encode('utf-8') def format_value(self, req, value): + if isinstance(value, (list, tuple)): + return [self.format_single_value(req, val) for val in value] + return self.format_single_value(req, value) + + def format_single_value(self, req, value): + if value is None: + return u'' return unicode(value) def get_widget(self, req): @@ -457,12 +464,11 @@ self.max_length = max_length class TextField(Field): - widget = TextArea - def __init__(self, row=None, col=None, **kwargs): - super(TextField, self).__init__(**kwargs) - self.row = row - self.col = col - + def __init__(self, rows=10, cols=80, **kwargs): + widget = TextArea(dict(rows=rows, cols=cols)) + super(TextField, self).__init__(widget=widget, **kwargs) + self.rows = rows + self.cols = cols class RichTextField(TextField): widget = None @@ -519,8 +525,11 @@ self.min = min self.max = max +class BooleanField(Field): + widget = Radio + class FloatField(IntField): - def format_value(self, req, value): + def format_single_value(self, req, value): formatstr = entity.req.property_value('ui.float-format') if value is None: return u'' @@ -550,7 +559,7 @@ class RelationField(Field): - def __init__(self, role='subject', **kwargs): + def __init__(self, **kwargs): super(RelationField, self).__init__(**kwargs) @staticmethod @@ -631,8 +640,8 @@ return any(field.needs_multipart for field in self.fields) def form_add_hidden(self, name, value=None, **kwargs): - self.fields.append(TextField(name=name, widget=HiddenInput, - initial=value, **kwargs)) + self.fields.append(StringField(name=name, widget=HiddenInput, + initial=value, **kwargs)) def form_render(self, **values): renderer = values.pop('renderer', FormRenderer()) @@ -738,7 +747,7 @@ if fieldname.startswith('edits-') or fieldname.startswith('edito-'): # edit[s|o]- fieds must have the actual value stored on the entity if self.entity.has_eid(): - value = self.form_field_entity_value(field, default_initial=False) + value = self.form_field_entity_value(field.visible_field, default_initial=False) else: value = INTERNAL_FIELD_VALUE elif fieldname == '__type': @@ -749,6 +758,8 @@ value = values[fieldname] elif fieldname in self.req.form: value = self.req.form[fieldname] + elif isinstance(field, FileField): + return None # XXX manage FileField else: if self.entity.has_eid() and field.eidparam: # use value found on the entity or field's initial value if it's @@ -784,10 +795,14 @@ if field.role == 'object': attr += '_object' if default_initial: - return getattr(self.entity, attr, field.initial) + value = getattr(self.entity, attr, field.initial) else: - return getattr(self.entity, attr) - + value = getattr(self.entity, attr) + if isinstance(field, RelationField): + # in this case, value is the list of related entities + value = [ent.eid for ent in value] + return value + def form_field_name(self, field): if field.eidparam: return eid_param(field.name, self.entity.eid) @@ -799,12 +814,21 @@ return field.id def form_field_vocabulary(self, field): - choices = self.vocabfunc(entity) - if self.sort: - choices = sorted(choices) - if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'): - return zip((entity.req._(v) for v in choices), choices) - return zip(choices, choices) + role, rtype = field.role, field.name + try: + vocabfunc = getattr(self.entity, '%s_%s_vocabulary' % (role, rtype)) + except AttributeError: + vocabfunc = getattr(self, '%s_relation_vocabulary' % role) + else: + # XXX bw compat, default_ on the entity + warn('found %s_%s_vocabulary on %s, should be set on a specific form' + % (role, rtype, self.entity.id), DeprecationWarning) + return vocabfunc(rtype) +## XXX BACKPORT ME +## if self.sort: +## choices = sorted(choices) +## if self.rschema.rproperty(self.subjtype, self.objtype, 'internationalizable'): +## return zip((entity.req._(v) for v in choices), choices) def subject_relation_vocabulary(self, rtype, limit=None): """defaut vocabulary method for the given relation, looking for