diff -r c0c7a944c00d -r a3431f4e2f40 web/views/forms.py --- a/web/views/forms.py Mon Sep 28 16:39:10 2009 +0200 +++ b/web/views/forms.py Tue Sep 29 15:58:44 2009 +0200 @@ -10,7 +10,6 @@ from warnings import warn from logilab.common.compat import any -from logilab.common.decorators import iclassmethod from cubicweb.selectors import non_final_entity, match_kwargs, one_line_rset from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param @@ -56,7 +55,6 @@ """ __regid__ = 'base' - is_subform = False internal_fields = ('__errorurl',) + NAV_FORM_PARAMETERS # attributes overrideable by subclasses or through __init__ @@ -84,6 +82,8 @@ self.form_add_hidden(key, val) elif hasattr(self.__class__, key) and not key[0] == '_': setattr(self, key, val) + else: + self.extra_kwargs[key] = val # skip other parameters, usually given for selection # (else write a custom class to handle them) if mainform: @@ -101,52 +101,6 @@ if 'domid' in kwargs:# session key changed self.restore_previous_post(self.session_key()) - @iclassmethod - def _fieldsattr(cls_or_self): - if isinstance(cls_or_self, type): - fields = cls_or_self._fields_ - else: - fields = cls_or_self.fields - return fields - - @iclassmethod - def field_by_name(cls_or_self, name, role='subject'): - """return field with the given name and role. - Raise FieldNotFound if the field can't be found. - """ - for field in cls_or_self._fieldsattr(): - if field.name == name and field.role == role: - return field - raise form.FieldNotFound(name) - - @iclassmethod - def fields_by_name(cls_or_self, name, role='subject'): - """return a list of fields with the given name and role""" - return [field for field in cls_or_self._fieldsattr() - if field.name == name and field.role == role] - - @iclassmethod - def remove_field(cls_or_self, field): - """remove a field from form class or instance""" - cls_or_self._fieldsattr().remove(field) - - @iclassmethod - def append_field(cls_or_self, field): - """append a field to form class or instance""" - cls_or_self._fieldsattr().append(field) - - @iclassmethod - def insert_field_before(cls_or_self, new_field, name, role='subject'): - field = cls_or_self.field_by_name(name, role) - fields = cls_or_self._fieldsattr() - fields.insert(fields.index(field), new_field) - - @iclassmethod - def insert_field_after(cls_or_self, new_field, name, role='subject'): - field = cls_or_self.field_by_name(name, role) - fields = cls_or_self._fieldsattr() - fields.insert(fields.index(field)+1, new_field) - @property def form_needs_multipart(self): """true if the form needs enctype=multipart/form-data""" @@ -174,6 +128,7 @@ """render this form, using the renderer given in args or the default FormRenderer() """ + self.build_context(values) renderer = values.pop('renderer', None) if renderer is None: renderer = self.form_default_renderer() @@ -184,7 +139,7 @@ self._cw, rset=self.cw_rset, row=self.cw_row, col=self.cw_col) - def form_build_context(self, rendervalues=None): + def build_context(self, rendervalues=None): """build form context values (the .context attribute which is a dictionary with field instance as key associated to a dictionary containing field 'name' (qualified), 'id', 'value' (for display, always @@ -193,6 +148,8 @@ rendervalues is an optional dictionary containing extra kwargs given to form_render() """ + if self.context is not None: + return # already built self.context = context = {} # ensure rendervalues is a dict if rendervalues is None: @@ -224,6 +181,8 @@ if value is None: if field.name in rendervalues: value = rendervalues[field.name] + elif field.name in self.extra_kwargs: + value = self.extra_kwargs[field.name] else: value = self.form_field_value(field, load_bytes) if callable(value): @@ -349,9 +308,9 @@ searchedvalues = ['%s:%s:%s' % (field.name, eid, field.role) for eid in value] # remove associated __linkto hidden fields - for field in self.fields_by_name('__linkto'): + for field in self.root_form.fields_by_name('__linkto'): if field.initial in searchedvalues: - self.remove_field(field) + self.root_form.remove_field(field) else: value = None return value @@ -375,21 +334,6 @@ self.form_renderer_id, self._cw, rset=self.cw_rset, row=self.cw_row, col=self.cw_col, entity=self.edited_entity) -## def form_build_context(self, values=None): -## """overriden to add edit[s|o] hidden fields and to ensure schema fields -## have eidparam set to True -## """ -## eschema = self.edited_entity.e_schema -## for field in self.fields[:]: -## for field in field.actual_fields(self): -## fieldname = field.name -## if fieldname != 'eid' and ( -## (eschema.has_subject_relation(fieldname) or -## eschema.has_object_relation(fieldname))): -## # XXX why do we need to do this here ? -## field.eidparam = True -## return super(EntityFieldsForm, self).form_build_context(values) - def form_field_value(self, field, load_bytes=False): """return field's *typed* value @@ -554,31 +498,28 @@ return False -class CompositeForm(FieldsForm): +class CompositeFormMixIn(object): """form composed of sub-forms""" __regid__ = 'composite' form_renderer_id = __regid__ def __init__(self, *args, **kwargs): - super(CompositeForm, self).__init__(*args, **kwargs) + super(CompositeFormMixIn, self).__init__(*args, **kwargs) self.forms = [] - def form_add_subform(self, subform): + def add_subform(self, subform): """mark given form as a subform and append it""" - subform.is_subform = True + subform.parent_form = self self.forms.append(subform) + def build_context(self, rendervalues=None): + super(CompositeFormMixIn, self).build_context(rendervalues) + for form in self.forms: + form.build_context(rendervalues) + -class CompositeEntityForm(EntityFieldsForm): - """form composed of sub-forms""" - __regid__ = 'composite' - form_renderer_id = __regid__ +class CompositeForm(CompositeFormMixIn, FieldsForm): + pass - def __init__(self, *args, **kwargs): - super(CompositeEntityForm, self).__init__(*args, **kwargs) - self.forms = [] - - def form_add_subform(self, subform): - """mark given form as a subform and append it""" - subform.is_subform = True - self.forms.append(subform) +class CompositeEntityForm(CompositeFormMixIn, EntityFieldsForm): + pass # XXX why is this class necessary?