# HG changeset patch # User sylvain.thenault@logilab.fr # Date 1235066113 -3600 # Node ID 27c4ebe90d036d424660050e6364f207e5f74b3c # Parent e449f1da7d0915979f0968c706e0ba7d16c9b8a1 prefixed form methods to avoid potential conflicts with field names, button related method, a bit more serious renderer diff -r e449f1da7d09 -r 27c4ebe90d03 web/form.py --- a/web/form.py Thu Feb 19 18:54:26 2009 +0100 +++ b/web/form.py Thu Feb 19 18:55:13 2009 +0100 @@ -422,22 +422,58 @@ self.context = {} @property - def needs_multipart(self): + def form_needs_multipart(self): return any(field.needs_multipart for field in self.fields) - def render(self, **values): + def form_render(self, **values): renderer = values.pop('renderer', FormRenderer()) - self.build_context(values) + self.form_build_context(values) return renderer.render(self) - def build_context(self, values): + def form_build_context(self, values): self.context = context = {} - for name, field in self.fields: - value = values.get(field.name, field.initial) - context[field] = {'value': field.format_value(self.req, value)} + for field in self.fields: + context[field] = {'value': self.form_field_value(field, values), + 'name': self.form_field_name(field, values), + 'id': self.form_field_id(field, values), + } + + def form_field_value(self, field, values): + value = values.get(field.name, field.initial) + return field.format_value(self.req, value) + + def form_field_name(self, field, values): + return field.name - def get_vocabulary(self, field): + def form_field_id(self, field, values): + return field.id + + def form_field_vocabulary(self, field): raise NotImplementedError + + BUTTON_STR = u'' + ACTION_SUBMIT_STR = u'' + + def button_ok(self, label=None, tabindex=None): + label = self.req._(label or stdmsgs.BUTTON_OK).capitalize() + return self.BUTTON_STR % ('defaultsubmit', label, tabindex or 2) + + def button_apply(self, label=None, tabindex=None): + label = self.req._(label or stdmsgs.BUTTON_APPLY).capitalize() + return self.ACTION_SUBMIT_STR % ('__action_apply', label, self.id, label, tabindex or 3) + + def button_delete(self, label=None, tabindex=None): + label = self.req._(label or stdmsgs.BUTTON_DELETE).capitalize() + return self.ACTION_SUBMIT_STR % ('__action_delete', label, self.id, label, tabindex or 3) + + def button_cancel(self, label=None, tabindex=None): + label = self.req._(label or stdmsgs.BUTTON_CANCEL).capitalize() + return self.ACTION_SUBMIT_STR % ('__action_cancel', label, self.id, label, tabindex or 4) + + def button_reset(self, label=None, tabindex=None): + label = self.req._(label or stdmsgs.BUTTON_CANCEL).capitalize() + return u'' % ( + label, tabindex or 4) class EntityFieldsForm(FieldsForm): @@ -447,25 +483,28 @@ self.fields.append(TextField(name='__type', widget=HiddenInput)) self.fields.append(TextField(name='eid', widget=HiddenInput)) - def render(self, entity, **values): + def form_render(self, entity, **values): self.entity = entity - return super(EntityFieldsForm, self).render(**values) + return super(EntityFieldsForm, self).form_render(**values) + + def form_field_value(self, field, values): + try: + value = values[field.name] + except KeyError: + value = getattr(self.entity, field.name, field.initial) + return field.format_value(self.req, value) - def build_context(self, values): - self.context = context = {} - for field in self.fields: - try: - value = values[field.name] - except KeyError: - value = getattr(self.entity, field.name, field.initial) - if field.eidparam: - name = eid_param(field.name, self.entity.eid) - else: - name = field.name - context[field] = {'value': field.format_value(self.req, value), - 'name': name} + def form_field_name(self, field, values): + if field.eidparam: + return eid_param(field.name, self.entity.eid) + return field.name + + def form_field_id(self, field, values): + if field.eidparam: + return eid_param(field.id, self.entity.eid) + return field.id - def get_vocabulary(self, field): + def form_field_vocabulary(self, field): choices = self.vocabfunc(entity) if self.sort: choices = sorted(choices) @@ -477,9 +516,11 @@ # form renderers ############ class FormRenderer(object): + def render(self, form): data = [] w = data.append + # XXX form_needs_multipart w(u'
' % (form.req.build_url(form.action), form.id, form.id)) w(u'
%s
' % _('validating...')) @@ -487,10 +528,30 @@ w(tags.input(type='hidden', name='__form_id', value=form.id)) if form.redirect_path: w(tags.input(type='hidden', name='__redirect_path', value=form.redirect_path)) - for field in form.fields: - w(field.render(form)) - for button in form.buttons(): - w(button.render()) + self.render_fields(w, form) + self.render_buttons(w, form) w(u'') w(u'
') return '\n'.join(data) + + def render_fields(self, w, form): + w(u'') + for field in form.fields: + w(u'') + w('' % self.render_label(form, field)) + w(u'') + w(u'
%s') + w(field.render(form)) + w(u'
') + + def render_buttons(self, w, form): + for button in form.buttons(): + w(button) + + def render_label(self, form, field): + label = form.req._(field.label) + attrs = {'for': form.context[field]['id']} + if field.required: + attrs['class'] = 'required' + return tags.label(label, **attrs) + diff -r e449f1da7d09 -r 27c4ebe90d03 web/test/unittest_form.py --- a/web/test/unittest_form.py Thu Feb 19 18:54:26 2009 +0100 +++ b/web/test/unittest_form.py Thu Feb 19 18:55:13 2009 +0100 @@ -1,31 +1,30 @@ from logilab.common.testlib import TestCase, unittest_main, mock_object -from cubicweb.web.form import * -class ChangeStateForm(EntityFieldsForm): - state = TextField(widget=HiddenInput, eidparam=False) - __method = TextField(widget=HiddenInput, initial='set_state', eidparam=False) - trcomment = RichTextField() - - def buttons(self): - return [] +from cubicweb.web.form import * +from cubicweb.web.views.baseforms import ChangeStateForm class CustomChangeStateForm(ChangeStateForm): hello = IntField(name='youlou') class EntityFieldsFormTC(TestCase): + def setUp(self): + def next_tabindex(self): + self.count += 1 + return self.count + self.req = mock_object(build_url=lambda *args,**kwargs: 'myurl.com', + _=lambda s,x: x, + next_tabindex=next_tabindex, count=0) + self.entity = mock_object(eid=1) + def test(self): - req = mock_object(build_url=lambda *args,**kwargs: 'myurl.com') - form = ChangeStateForm(req, redirect_path='perdu.com') - entity = mock_object(eid=1) - self.assertEquals(form.render(entity, state=123), + form = ChangeStateForm(self.req, redirect_path='perdu.com') + self.assertEquals(form.form_render(self.entity, state=123), '''''') def test_form_inheritance(self): - req = mock_object(build_url=lambda *args,**kwargs: 'myurl.com') - form = CustomChangeStateForm(req, redirect_path='perdu.com') - entity = mock_object(eid=1) - self.assertEquals(form.render(entity, state=123), + form = CustomChangeStateForm(self.req, redirect_path='perdu.com') + self.assertEquals(form.form_render(self.entity, state=123), '''''')