[Checkins] SVN: z3c.form/branches/adamg-objectwidget/ first try at the objectwidget,
Adam Groszer
agroszer at gmail.com
Tue Oct 7 11:41:25 EDT 2008
Log message for revision 91860:
first try at the objectwidget,
missing points:
- object factory totally bad
- error display bad
Changed:
U z3c.form/branches/adamg-objectwidget/buildout.cfg
U z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/configure.zcml
A z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py
A z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
A z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.zcml
A z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_display.pt
A z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_input.pt
U z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/tests.py
U z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/widget.py
U z3c.form/branches/adamg-objectwidget/src/z3c/form/configure.zcml
U z3c.form/branches/adamg-objectwidget/src/z3c/form/converter.py
A z3c.form/branches/adamg-objectwidget/src/z3c/form/dummy.py
U z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py
-=-
Modified: z3c.form/branches/adamg-objectwidget/buildout.cfg
===================================================================
--- z3c.form/branches/adamg-objectwidget/buildout.cfg 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/buildout.cfg 2008-10-07 15:41:24 UTC (rev 91860)
@@ -7,6 +7,8 @@
[versions]
lxml = 2.1.1
zope.app.locales = 3.4.5
+z3c.pt = 1.0a9
+z3c.pt.compat = 0.2
[test-environment]
Z3C_PT_DEBUG = False
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/configure.zcml
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/configure.zcml 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/configure.zcml 2008-10-07 15:41:24 UTC (rev 91860)
@@ -17,4 +17,6 @@
<include file="textarea.zcml" />
<include file="textlines.zcml" />
+ <include file="object.zcml" />
+
</configure>
Added: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py (rev 0)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py 2008-10-07 15:41:24 UTC (rev 91860)
@@ -0,0 +1,104 @@
+__docformat__ = "reStructuredText"
+import zope.component
+import zope.interface
+import zope.schema.interfaces
+
+from z3c.form import action, button, form, interfaces
+from z3c.form.i18n import MessageFactory as _
+from z3c.form import interfaces
+from z3c.form.widget import Widget, FieldWidget
+from z3c.form.field import FieldWidgets, Fields
+from z3c.form.browser import widget
+from z3c.form.subform import EditSubForm
+
+class ObjectSubForm(form.BaseForm):
+ zope.interface.implements(interfaces.ISubForm)
+
+ formErrorsMessage = _('There were some errors.')
+ successMessage = _('Data successfully updated.')
+ noChangesMessage = _('No changes were applied.')
+
+ def __init__(self, context, parentWidget):
+ self.context = context
+ self.request = parentWidget.request
+ self.parentWidget = parentWidget
+ self.parentForm = self.__parent__ = parentWidget.form
+
+ def _validate(self):
+ for widget in self.widgets.values():
+ try:
+ # convert widget value to field value
+ converter = interfaces.IDataConverter(widget)
+ value = converter.toFieldValue(widget.value)
+ # validate field value
+ zope.component.getMultiAdapter(
+ (self.context,
+ self.request,
+ self.parentWidget.form,
+ getattr(widget, 'field', None),
+ widget),
+ interfaces.IValidator).validate(value)
+ except (zope.schema.ValidationError, ValueError), error:
+ # on exception, setup the widget error message
+ view = zope.component.getMultiAdapter(
+ (error, self.request, widget, widget.field,
+ self.parentWidget.form, self.context),
+ interfaces.IErrorViewSnippet)
+ view.update()
+ widget.error = view
+
+ def update(self):
+ self.fields = Fields(self.parentWidget.field.schema)
+
+ self.mode = self.parentWidget.mode
+ self.ignoreContext = self.parentWidget.ignoreContext
+ self.ignoreRequest = self.parentWidget.ignoreRequest
+ self.prefix = self.parentWidget.field.__name__
+
+ if interfaces.IFormAware.providedBy(self.parentWidget):
+ self.ignoreReadonly = self.parentWidget.form.ignoreReadonly
+
+ super(ObjectSubForm, self).update()
+
+ self._validate()
+
+
+class ObjectWidget(widget.HTMLFormElement, Widget):
+ zope.interface.implementsOnly(interfaces.IObjectWidget)
+
+ klass = u'object-widget'
+ subform = None
+
+ def _makeSubform(self):
+ #if self.subform is None:
+ try:
+ subobj = getattr(self.context, self.field.__name__)
+ except AttributeError:
+ if self.value:
+ subobj = self.value
+ else:
+ #lame, mostly for adding
+ subobj = self.context
+ self.subform = ObjectSubForm(subobj, self)
+ #self.subform = ObjectSubForm(self.value, self)
+
+ def update(self):
+ super(ObjectWidget, self).update()
+
+ self._makeSubform()
+ self.subform.update()
+
+ def extract(self, default=interfaces.NOVALUE):
+ if self.name+'-empty-marker' in self.request:
+ self._makeSubform()
+ self.subform.update()
+ rv=self.subform.extractData()
+ return rv
+ else:
+ return default
+
+ at zope.component.adapter(zope.schema.interfaces.IObject, interfaces.IFormLayer)
+ at zope.interface.implementer(interfaces.IFieldWidget)
+def ObjectFieldWidget(field, request):
+ """IFieldWidget factory for IObjectWidget."""
+ return FieldWidget(field, ObjectWidget(request))
Property changes on: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.py
___________________________________________________________________
Name: svn:keywords
+ Date Author Id Revision
Name: svn:eol-style
+ native
Added: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt (rev 0)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt 2008-10-07 15:41:24 UTC (rev 91860)
@@ -0,0 +1,430 @@
+============
+ObjectWidget
+============
+
+The ObjectWidget is about rendering a schema's fields as a single widget.
+
+
+There are way too many preconditions to exercise the ObjectWidget as it
+relies heavily on the from and widget framework.
+It renders the sub-widgets in a sub-form.
+
+In order to not overwhelm you with our set of well-chosen defaults,
+all the default component registrations have been made prior to doing those
+examples:
+
+ >>> from z3c.form import testing
+ >>> testing.setupFormDefaults()
+
+
+
+As for all widgets, the objectwidget must provide the new ``IWidget``
+interface:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> from z3c.form import interfaces
+ >>> from z3c.form.browser import object
+
+ >>> verifyClass(interfaces.IWidget, object.ObjectWidget)
+ True
+
+The widget can be instantiated only using the request:
+
+ >>> from z3c.form.testing import TestRequest
+ >>> request = TestRequest()
+ >>> widget = object.ObjectWidget(request)
+
+Before rendering the widget, one has to set the name and id of the widget:
+
+ >>> widget.id = 'widget-id'
+ >>> widget.name = 'widget.name'
+
+Also, stand-alone widgets need to ignore the context:
+
+ >>> widget.ignoreContext = True
+
+There is no life for ObjectWidget without a schema to render:
+
+ >>> widget.update()
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'NoneType' object has no attribute 'schema'
+
+This schema is specified by the field:
+
+ >>> from z3c.form.widget import FieldWidget
+ >>> from z3c.form.dummy import IMySubObject
+ >>> import zope.schema
+ >>> field = zope.schema.Object(
+ ... __name__='subobject',
+ ... title=u'my object widget',
+ ... schema=IMySubObject)
+
+Apply the field nicely with the helper:
+
+ >>> widget = FieldWidget(field, widget)
+
+We also need to register the templates for the widget and request:
+
+ >>> import zope.component
+ >>> from zope.pagetemplate.interfaces import IPageTemplate
+ >>> from z3c.form.testing import getPath
+ >>> from z3c.form.widget import WidgetTemplateFactory
+
+ >>> zope.component.provideAdapter(
+ ... WidgetTemplateFactory(getPath('object_input.pt'), 'text/html'),
+ ... (None, None, None, None, interfaces.IObjectWidget),
+ ... IPageTemplate, name=interfaces.INPUT_MODE)
+
+ >>> zope.component.provideAdapter(
+ ... WidgetTemplateFactory(getPath('object_display.pt'), 'text/html'),
+ ... (None, None, None, None, interfaces.IObjectWidget),
+ ... IPageTemplate, name=interfaces.DISPLAY_MODE)
+
+We can now render the widget:
+
+ >>> widget.update()
+ >>> print widget.render()
+ <fieldset class="object-widget required" id="subobject" name="subobject">
+ <legend>my object widget</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield"
+ name="subobject.widgets.foofield" type="text" value="1,111">
+ <br>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield"
+ name="subobject.widgets.barfield" type="text" value="2,222">
+ <br>
+ <input name="subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+
+As you see all sort of default values are rendered.
+
+Let's provide a more meaningful value:
+
+ >>> from z3c.form.dummy import MySubObject
+ >>> v = MySubObject()
+ >>> v.foofield = 42
+ >>> v.barfield = 666
+
+ >>> widget.value = v
+ >>> widget.ignoreContext = False
+
+#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+
+ >>> widget.update()
+ >>> print widget.render()
+ <fieldset class="object-widget required" id="subobject" name="subobject">
+ <legend>my object widget</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield"
+ name="subobject.widgets.foofield" type="text" value="42">
+ <br>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield"
+ name="subobject.widgets.barfield" type="text" value="666">
+ <br>
+ <input name="subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+
+Let's fill in some values:
+
+ >>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'2',
+ ... 'subobject.widgets.barfield':u'999'})
+ >>> widget.update()
+ >>> print widget.render()
+ <fieldset class="object-widget required" id="subobject" name="subobject">
+ <legend>my object widget</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield"
+ name="subobject.widgets.foofield" type="text" value="2">
+ <br>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield"
+ name="subobject.widgets.barfield" type="text" value="999">
+ <br>
+ <input name="subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+
+
+Error handling is next. Let's use teh value "bad" (an invalid integer literal)
+as input for our internal (sub) widget.
+
+ >>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'2',
+ ... 'subobject.widgets.barfield':u'bad'})
+
+
+# >>> from pub.dbgpclient import brk; brk('192.168.32.1')
+
+ >>> widget.update()
+ >>> print widget.render()
+ <fieldset id="subobject" name="subobject"
+ class="object-widget required">
+ <legend>my object widget</legend>
+ <input id="subobject-widgets-foofield"
+ name="subobject.widgets.foofield"
+ class="text-widget required int-field" value="2"
+ type="text" />
+ <br />
+ <div class="error">
+ <div class="error">The entered value is not a valid integer literal.</div>
+ </div>
+ <input id="subobject-widgets-barfield"
+ name="subobject.widgets.barfield"
+ class="text-widget required int-field" value="bad"
+ type="text" />
+ <br />
+ <input name="subobject-empty-marker" type="hidden" value="1" />
+ </fieldset>
+
+
+
+
+
+
+
+
+
+Do all that fun in add and edit forms too:
+
+We have to provide an adapter first:
+
+ >>> zope.component.provideAdapter(object.ObjectFieldWidget)
+ >>> from z3c.form import converter
+ >>> zope.component.provideAdapter(converter.ObjectConverter)
+
+We define an interface containing a subobject, and an addform for it:
+
+ >>> from z3c.form import form, field
+ >>> from z3c.form.dummy import MyObject, IMyObject
+
+ >>> class MyAddForm(form.AddForm):
+ ... fields = field.Fields(IMyObject)
+ ... def create(self, data):
+ ... print "MyAddForm.create", str(data)
+ ... return MyObject(**data)
+ ... def add(self, obj):
+ ... self.context[obj.name] = obj
+ ... def nextURL(self):
+ ... pass
+
+We create the form and try to update it:
+
+ >>> request = TestRequest()
+ >>> myaddform = MyAddForm(root, request)
+
+#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+
+ >>> myaddform.update()
+
+As usually, the form contains a widget manager with the expected widget
+
+ >>> myaddform.widgets.keys()
+ ['subobject', 'name']
+ >>> myaddform.widgets.values()
+ [<ObjectWidget 'form.widgets.subobject'>, <TextWidget 'form.widgets.name'>]
+
+But now, the addform contains a subform, that the user didn't need to create
+and which is already updated:
+
+ >>> myaddform.widgets['subobject'].subform
+ <z3c.form.browser.object.ObjectSubForm object at ...>
+ >>> myaddform.widgets['subobject'].subform.widgets.keys()
+ ['foofield', 'barfield']
+
+If we want to render the addform, we must give it a template:
+
+ >>> import os
+ >>> from zope.app.pagetemplate import viewpagetemplatefile
+ >>> from z3c.form import tests
+ >>> def addTemplate(form):
+ ... form.template = viewpagetemplatefile.BoundPageTemplate(
+ ... viewpagetemplatefile.ViewPageTemplateFile(
+ ... 'simple_edit.pt', os.path.dirname(tests.__file__)), form)
+ >>> addTemplate(myaddform)
+
+Now rendering the addform renders the subform as well:
+
+ >>> print myaddform.render()
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <form action=".">
+ <div class="row">
+ <label for="form-widgets-subobject">my object</label>
+ <fieldset class="object-widget required" id="form-widgets-subobject" name="form.widgets.subobject">
+ <legend>my object</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield" name="subobject.widgets.foofield" type="text" value="1,111">
+ <br>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield" name="subobject.widgets.barfield" type="text" value="2,222">
+ <br>
+ <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+ </div>
+ <div class="row">
+ <label for="form-widgets-name">name</label>
+ <input class="text-widget required textline-field" id="form-widgets-name" name="form.widgets.name" type="text" value="">
+ </div>
+ <div class="action">
+ <input class="submit-widget button-field" id="form-buttons-add" name="form.buttons.add" type="submit" value="Add">
+ </div>
+ </form>
+ </body>
+ </html>
+
+Let's try to add an object:
+
+ >>> request = TestRequest(form={'subobject.widgets.foofield':u'66',
+ ... 'subobject.widgets.barfield':u'99',
+ ... 'form.widgets.name':u'first',
+ ... 'form.widgets.subobject-empty-marker':u'1',
+ ... 'form.buttons.add':'Add'})
+ >>> myaddform.request = request
+ >>> myaddform.update()
+ MyAddForm.create {'subobject': <z3c.form.dummy.MySubObject object at ...>,
+ 'name': u'first'}
+
+Wow, it got added:
+
+ >>> root['first']
+ <z3c.form.dummy.MyObject object at ...>
+
+ >>> root['first'].subobject
+ <z3c.form.dummy.MySubObject object at ...>
+
+ >>> root['first'].subobject.foofield
+ 66
+
+ >>> root['first'].subobject.barfield
+ 99
+
+ >>> myaddform.render()
+ ''
+
+
+
+ >>> class MyEditForm(form.EditForm):
+ ... fields = field.Fields(IMyObject)
+
+ >>> editform = MyEditForm(root['first'], TestRequest())
+ >>> addTemplate(editform)
+ >>> editform.update()
+
+ >>> print editform.render()
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <form action=".">
+ <div class="row">
+ <label for="form-widgets-subobject">my object</label>
+ <fieldset class="object-widget required" id="form-widgets-subobject" name="form.widgets.subobject">
+ <legend>my object</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield" name="subobject.widgets.foofield" type="text" value="66">
+ <br>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield" name="subobject.widgets.barfield" type="text" value="99">
+ <br>
+ <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+ </div>
+ <div class="row">
+ <label for="form-widgets-name">name</label>
+ <input class="text-widget required textline-field" id="form-widgets-name" name="form.widgets.name" type="text" value="first">
+ </div>
+ <div class="action">
+ <input class="submit-widget button-field" id="form-buttons-apply" name="form.buttons.apply" type="submit" value="Apply">
+ </div>
+ </form>
+ </body>
+ </html>
+
+
+ >>> request = TestRequest(form={'subobject.widgets.foofield':u'43',
+ ... 'subobject.widgets.barfield':u'55',
+ ... 'form.widgets.name':u'first',
+ ... 'form.widgets.subobject-empty-marker':u'1',
+ ... 'form.buttons.apply':'Apply'})
+
+ >>> editform.request = request
+ >>> editform.update()
+
+ >>> root['first'].subobject.foofield
+ 43
+
+ >>> root['first'].subobject.barfield
+ 55
+
+ >>> print editform.render()
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <i>Data successfully updated.</i>
+ <form action=".">
+ <div class="row">
+ <label for="form-widgets-subobject">my object</label>
+ <fieldset class="object-widget required" id="form-widgets-subobject" name="form.widgets.subobject">
+ <legend>my object</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield" name="subobject.widgets.foofield" type="text" value="43">
+ <br>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield" name="subobject.widgets.barfield" type="text" value="55">
+ <br>
+ <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+ </div>
+ <div class="row">
+ <label for="form-widgets-name">name</label>
+ <input class="text-widget required textline-field" id="form-widgets-name" name="form.widgets.name" type="text" value="first">
+ </div>
+ <div class="action">
+ <input class="submit-widget button-field" id="form-buttons-apply" name="form.buttons.apply" type="submit" value="Apply">
+ </div>
+ </form>
+ </body>
+ </html>
+
+
+ >>> request = TestRequest(form={'subobject.widgets.foofield':u'99',
+ ... 'subobject.widgets.barfield':u'bad',
+ ... 'form.widgets.name':u'first',
+ ... 'form.widgets.subobject-empty-marker':u'1',
+ ... 'form.buttons.apply':'Apply'})
+
+ >>> editform.request = request
+
+#>>> from pub.dbgpclient import brk; brk('192.168.32.1')
+
+ >>> editform.update()
+ >>> print editform.render()
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <body>
+ <i>There were some errors.</i>
+ <ul>
+ <li>
+ my object:
+ <div class="error">The entered value is not a valid integer literal.</div>
+ </li>
+ </ul>
+ <form action=".">
+ <div class="row">
+ <b>
+ <div class="error">The entered value is not a valid integer literal.</div>
+ </b>
+ <label for="form-widgets-subobject">my object</label>
+ <fieldset class="object-widget required" id="form-widgets-subobject" name="form.widgets.subobject">
+ <legend>my object</legend>
+ <input class="text-widget required int-field" id="subobject-widgets-foofield" name="subobject.widgets.foofield" type="text" value="99">
+ <br>
+ <div class="error">
+ <div class="error">The entered value is not a valid integer literal.</div>
+ </div>
+ <input class="text-widget required int-field" id="subobject-widgets-barfield" name="subobject.widgets.barfield" type="text" value="bad">
+ <br>
+ <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
+ </fieldset>
+ </div>
+ <div class="row">
+ <label for="form-widgets-name">name</label>
+ <input class="text-widget required textline-field" id="form-widgets-name" name="form.widgets.name" type="text" value="first">
+ </div>
+ <div class="action">
+ <input class="submit-widget button-field" id="form-buttons-apply" name="form.buttons.apply" type="submit" value="Apply">
+ </div>
+ </form>
+ </body>
+ </html>
+
+ >>> root['first'].subobject.foofield
+ 43
+
+ >>> root['first'].subobject.barfield
+ 55
Property changes on: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.txt
___________________________________________________________________
Name: svn:keywords
+ Date Author Id Revision
Name: svn:eol-style
+ native
Added: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.zcml
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.zcml (rev 0)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.zcml 2008-10-07 15:41:24 UTC (rev 91860)
@@ -0,0 +1,38 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="z3c.form">
+
+ <class class=".object.ObjectWidget">
+ <require
+ permission="zope.Public"
+ interface="z3c.form.interfaces.IObjectWidget"
+ />
+ </class>
+
+<adapter
+ factory=".object.ObjectFieldWidget"
+ for="zope.schema.interfaces.IObject
+ z3c.form.interfaces.IFormLayer"
+ />
+
+<z3c:widgetTemplate
+ mode="input"
+ widget="z3c.form.interfaces.IObjectWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="object_input.pt"
+ />
+<z3c:widgetTemplate
+ mode="hidden"
+ widget="z3c.form.interfaces.IObjectWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="object_input.pt"
+ />
+<z3c:widgetTemplate
+ mode="display"
+ widget="z3c.form.interfaces.IObjectWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="object_display.pt"
+ />
+
+</configure>
Property changes on: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object.zcml
___________________________________________________________________
Name: svn:keywords
+ Date Author Id Revision
Name: svn:eol-style
+ native
Added: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_display.pt
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_display.pt (rev 0)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_display.pt 2008-10-07 15:41:24 UTC (rev 91860)
@@ -0,0 +1,30 @@
+<fieldset id="" name="" class="" title="" lang="" disabled=""
+ tal:attributes="id view/id;
+ name view/name;
+ class view/klass;
+ style view/style;
+ title view/title;
+ lang view/lang;
+ onclick view/onclick;
+ ondblclick view/ondblclick;
+ onmousedown view/onmousedown;
+ onmouseup view/onmouseup;
+ onmouseover view/onmouseover;
+ onmousemove view/onmousemove;
+ onmouseout view/onmouseout;
+ onkeypress view/onkeypress;
+ onkeydown view/onkeydown;
+ onkeyup view/onkeyup;
+ disabled view/disabled;
+ tabindex view/tabindex;
+ onfocus view/onfocus;
+ onblur view/onblur;
+ onchange view/onchange;">
+<legend tal:content="view/label">foobar</legend>
+
+<tal:block repeat="widget view/subform/widgets/values">
+ <tal:block content="structure widget/render" />
+ <br/>
+</tal:block>
+
+</fieldset>
\ No newline at end of file
Property changes on: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_display.pt
___________________________________________________________________
Name: svn:keywords
+ Date Author Id Revision
Name: svn:eol-style
+ native
Added: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_input.pt
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_input.pt (rev 0)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_input.pt 2008-10-07 15:41:24 UTC (rev 91860)
@@ -0,0 +1,37 @@
+<fieldset id="" name="" class="" title="" lang="" disabled=""
+ tal:attributes="id view/id;
+ name view/name;
+ class view/klass;
+ style view/style;
+ title view/title;
+ lang view/lang;
+ onclick view/onclick;
+ ondblclick view/ondblclick;
+ onmousedown view/onmousedown;
+ onmouseup view/onmouseup;
+ onmouseover view/onmouseover;
+ onmousemove view/onmousemove;
+ onmouseout view/onmouseout;
+ onkeypress view/onkeypress;
+ onkeydown view/onkeydown;
+ onkeyup view/onkeyup;
+ disabled view/disabled;
+ tabindex view/tabindex;
+ onfocus view/onfocus;
+ onblur view/onblur;
+ onchange view/onchange;">
+<legend tal:content="view/label">foobar</legend>
+
+<tal:block repeat="widget view/subform/widgets/values">
+ <div class="error"
+ tal:condition="widget/error">
+ <span tal:replace="structure widget/error/render">error</span>
+ </div>
+ <tal:block content="structure widget/render" />
+ <br/>
+</tal:block>
+
+<input name="field-empty-marker" type="hidden" value="1"
+ tal:attributes="name string:${view/name}-empty-marker" />
+
+</fieldset>
\ No newline at end of file
Property changes on: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/object_input.pt
___________________________________________________________________
Name: svn:keywords
+ Date Author Id Revision
Name: svn:eol-style
+ native
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/tests.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/tests.py 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/tests.py 2008-10-07 15:41:24 UTC (rev 91860)
@@ -91,6 +91,11 @@
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
checker=checker,
),
+ DocFileSuite('object.txt',
+ setUp=setUp, tearDown=testing.tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ checker=checker,
+ ),
DocFileSuite('multi.txt',
setUp=setUp, tearDown=testing.tearDown,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/widget.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/widget.py 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/browser/widget.py 2008-10-07 15:41:24 UTC (rev 91860)
@@ -54,7 +54,16 @@
if not self.klass:
self.klass = unicode(klass)
else:
- self.klass += u' ' + unicode(klass)
+ #make sure items are not repeated
+ parts = self.klass.split()+[unicode(klass)]
+ seen = {}
+ unique = []
+ for item in parts:
+ if item in seen:
+ continue
+ seen[item]=1
+ unique.append(item)
+ self.klass = u' '.join(unique)
def update(self):
"""See z3c.form.interfaces.IWidget"""
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/configure.zcml 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/configure.zcml 2008-10-07 15:41:24 UTC (rev 91860)
@@ -74,6 +74,9 @@
<adapter
factory=".converter.MultiConverter"
/>
+ <adapter
+ factory=".converter.ObjectConverter"
+ />
<!-- ITerms -->
<adapter
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/converter.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/converter.py 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/converter.py 2008-10-07 15:41:24 UTC (rev 91860)
@@ -339,7 +339,7 @@
"""Just dispatch it."""
if value is self.field.missing_value:
return []
- # We relay on the default registered widget, this is probably a
+ # We relay on the default registered widget, this is probably a
# restriction for custom widgets. If so use your own MultiWidget and
# register your own converter which will get the right widget for the
# used value_type.
@@ -359,10 +359,70 @@
return self.field.missing_value
valueType = self.field.value_type._type
values = [valueType(v) for v in value]
- # convert the field values to a tuple or list
+ # convert the field values to a tuple or list
return collectionType(values)
+from z3c.form.dummy import MySubObject
+class ObjectConverter(BaseDataConverter):
+ """Data converter for IObjectWidget."""
+
+ zope.component.adapts(
+ zope.schema.interfaces.IObject, interfaces.IObjectWidget)
+
+ factory = MySubObject
+ #factory = None
+
+ def _fields(self):
+ x = zope.schema.getFields(self.field.schema)
+ return x
+
+ def toWidgetValue(self, value):
+ """Just dispatch it."""
+ if value is self.field.missing_value:
+ return None
+
+ return value
+
+ rv = {}
+ for name, field in self._fields().items():
+ #widget = zope.component.getMultiAdapter((field, self.widget.request),
+ # interfaces.IFieldWidget)
+ #converter = zope.component.getMultiAdapter((field, widget),
+ # interfaces.IDataConverter)
+
+ v = getattr(value, name, None)
+ #rv[name] = converter.toWidgetValue(v)
+ rv[name] = v
+
+ return (rv, tuple())
+
+ def toFieldValue(self, value):
+ """See interfaces.IDataConverter"""
+ #if self.factory is None:
+ # adapter = zope.component.queryMultiAdapter(
+ # (self.widget.context, self.widget.request, self.widget.form,
+ # self.field.schema, self.widget),
+ # interfaces.IValue, name='default')
+ # if adapter:
+ # obj = adapter.get()
+ #else:
+ # obj = self.factory()
+
+ #this is creepy
+ if value[1]:
+ raise value[1][0].error
+
+ obj = self.factory()
+ for name, f in self._fields().items():
+ try:
+ setattr(obj, name, value[0][name])
+ except KeyError:
+ #smells like an input error?
+ pass
+ return obj
+
+
class BoolSingleCheckboxDataConverter(BaseDataConverter):
"A special converter between boolean fields and single checkbox widgets."
Added: z3c.form/branches/adamg-objectwidget/src/z3c/form/dummy.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/dummy.py (rev 0)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/dummy.py 2008-10-07 15:41:24 UTC (rev 91860)
@@ -0,0 +1,80 @@
+############
+# REMOVE this after we found a good solution for factory
+
+
+import zope.interface
+import zope.schema
+from zope.schema.fieldproperty import FieldProperty
+
+class IMySubObject(zope.interface.Interface):
+ foofield = zope.schema.Int(default=1111)
+ barfield = zope.schema.Int(default=2222)
+
+class MySubObject(object):
+ zope.interface.implements(IMySubObject)
+
+ foofield = FieldProperty(IMySubObject['foofield'])
+ barfield = FieldProperty(IMySubObject['barfield'])
+
+class IMySecond(zope.interface.Interface):
+ subfield = zope.schema.Object(schema=IMySubObject)
+ moofield = zope.schema.TextLine(title=u"Something")
+
+class MySecond(object):
+ zope.interface.implements(IMySecond)
+
+ subfield = FieldProperty(IMySecond['subfield'])
+ moofield = FieldProperty(IMySecond['moofield'])
+
+
+class IMyObject(zope.interface.Interface):
+ subobject = zope.schema.Object(title=u'my object', schema=IMySubObject)
+ name = zope.schema.TextLine(title=u'name')
+
+class MyObject(object):
+ zope.interface.implements(IMyObject)
+ def __init__(self, name=u'', subobject=None):
+ self.subobject=subobject
+ self.name=name
+
+
+import zope.interface
+import zope.component
+import zope.schema.interfaces
+
+from z3c.form import interfaces
+
+
+class FactoryAdapter(object):
+ """ """
+
+ zope.interface.implements(interfaces.IValue)
+ zope.component.adapts(zope.interface.Interface, interfaces.IFormLayer,
+ interfaces.IForm, zope.schema.interfaces.IField, interfaces.IWidget)
+
+ factory = None
+
+ def __init__(self, context, request, form, field, widget):
+ self.context = context
+ self.request = request
+ self.form = form
+ self.field = field
+ self.widget = widget
+
+ def get(self):
+ return self.factory()
+
+ def __repr__(self):
+ return '<%s %r>' % (self.__class__.__name__, self.__name__)
+
+class MySubObjectFactory(FactoryAdapter):
+ zope.component.adapts(zope.interface.Interface, interfaces.IFormLayer,
+ interfaces.IForm, IMySubObject, interfaces.IWidget)
+
+ factory = MySubObject
+
+class MySecondFactory(FactoryAdapter):
+ zope.component.adapts(zope.interface.Interface, interfaces.IFormLayer,
+ interfaces.IForm, IMySecond, interfaces.IWidget)
+
+ factory = MySecond
\ No newline at end of file
Property changes on: z3c.form/branches/adamg-objectwidget/src/z3c/form/dummy.py
___________________________________________________________________
Name: svn:keywords
+ Date Author Id Revision
Name: svn:eol-style
+ native
Modified: z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py 2008-10-07 15:40:37 UTC (rev 91859)
+++ z3c.form/branches/adamg-objectwidget/src/z3c/form/interfaces.py 2008-10-07 15:41:24 UTC (rev 91860)
@@ -508,6 +508,8 @@
class IPasswordWidget(ITextWidget):
"""Password widget."""
+class IObjectWidget(IWidget):
+ """Object widget."""
class IWidgets(IManager):
"""A widget manager"""
More information about the Checkins
mailing list