[Checkins] SVN: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/ First
attempt to write an ObjectWidget. This is far from finished...
Christophe Combelles
ccomb at free.fr
Sun Dec 9 15:50:50 EST 2007
Log message for revision 82213:
First attempt to write an ObjectWidget. This is far from finished...
Changed:
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/README.txt
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/configure.zcml
A Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.pt
A Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.py
A Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.txt
A Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.zcml
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/tests.py
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/configure.zcml
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/converter.py
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/field.py
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/form.txt
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/interfaces.py
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/subform.py
U Sandbox/ccomb/z3c.form/trunk/src/z3c/form/widget.py
-=-
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/README.txt
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/README.txt 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/README.txt 2007-12-09 20:50:50 UTC (rev 82213)
@@ -520,10 +520,90 @@
Object
------
-By default, we are not going to provide widgets for an object, since we
-believe this is better done using sub-forms.
+Object widgets can be handled by subforms.
+The object widget just creates a subform.
+ >>> import zope.interface
+ >>> class IMySubObject(zope.interface.Interface):
+ ... foofield = zope.schema.Int(default=1111)
+ ... barfield = zope.schema.Int(default=2222)
+ >>> field = zope.schema.Object(title=u'my object', schema=IMySubObject)
+ >>> widget = setupWidget(field)
+ >>> widget.update()
+Since we have no form, we have no subform, and the widget is rendered alone:
+
+ >>> print widget.render()
+ <fieldset id="foo" name="bar" class="object-widget required">
+ <legend>my object</legend>
+ </fieldset>
+ >>> widget.mode = interfaces.DISPLAY_MODE
+ >>> print widget.render()
+ <fieldset id="foo" name="bar" class="object-widget required">
+ <legend>my object</legend>
+ </fieldset>
+
+We define an interface containing a subobject, and an addform for it:
+
+ >>> from z3c.form import form, field
+ >>> class IMyObject(zope.interface.Interface):
+ ... subobject = zope.schema.Object(title=u'my object', schema=IMySubObject)
+ >>> class MyAddForm(form.AddForm):
+ ... fields = field.Fields(IMyObject)
+ ... def create(self, data):
+ ... pass
+ ... def add(self, obj):
+ ... pass
+ ... def nextURL(self):
+ ... pass
+
+We create the form and try to update it:
+
+ >>> request = TestRequest()
+ >>> myaddform = MyAddForm(root, request)
+ >>> myaddform.update()
+
+As usually, the form contains a widget manager with the expected widget
+
+ >>> myaddform.widgets.keys()
+ ['subobject']
+ >>> myaddform.widgets.values()
+ [<ObjectWidget 'form.widgets.subobject'>]
+
+But now, the addform contains a subform, that the user didn't need to create
+and which is already updated:
+
+ >>> myaddform.subobject
+ <z3c.form.subform.EditSubForm object at ...>
+ >>> myaddform.subobject.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
+ >>> myaddform.template = viewpagetemplatefile.BoundPageTemplate(
+ ... viewpagetemplatefile.ViewPageTemplateFile(
+ ... 'simple_edit.pt', os.path.dirname(tests.__file__)), myaddform)
+
+Now rendering the addform renders the subform as well:
+
+ >>> myaddform.render()
+ <fieldset id="foo" name="bar" class="object-widget required">
+ <input type="text" id="foo" name="bar" class="text-widget required int-field"
+ value="1,111" /><br/>
+ <input type="text" id="foo" name="bar" class="text-widget required int-field"
+ value="2,222" />
+ <legend>my object</legend>
+
+But if the user had previously created a subform by himself,
+the subform is untouched:
+
+ ...?...
+
+
+
Password
--------
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/configure.zcml
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/configure.zcml 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/configure.zcml 2007-12-09 20:50:50 UTC (rev 82213)
@@ -14,5 +14,6 @@
<include file="submit.zcml" />
<include file="text.zcml" />
<include file="textarea.zcml" />
+ <include file="object.zcml" />
</configure>
Added: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.pt
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.pt (rev 0)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.pt 2007-12-09 20:50:50 UTC (rev 82213)
@@ -0,0 +1,31 @@
+<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;
+ value view/value;
+ 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
Added: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.py (rev 0)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -0,0 +1,48 @@
+__docformat__ = "reStructuredText"
+import zope.component
+import zope.interface
+import zope.schema.interfaces
+
+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
+
+# FIXME: see if there is some interesting specific attributes for <fieldset>
+# We should then create a HTMLFieldsetElement and use it instead of base HTMLFormElement
+
+# FIXME where and when does the object creation takes place?
+
+class ObjectWidget(widget.HTMLFormElement, Widget):
+ zope.interface.implementsOnly(interfaces.IObjectWidget)
+
+ klass = u'object-widget'
+ widgets = None
+
+ def update(self):
+ if interfaces.IFormAware.providedBy(self) \
+ and not hasattr(self.form, self.name):
+ #FIXME None for add form, widget.context.? for editform
+ #FIXME: use a factory to create the subform, to be able
+ # to derive it from things like AddFormLayoutSupport
+ subform = EditSubForm(None, self.request, self.form)
+ subform.fields = Fields(self.field.schema)
+ setattr(self.form, self.field.__name__, subform)
+ zope.interface.alsoProvides(self, interfaces.ISubformAware)
+ self.subform = subform
+ if interfaces.ISubformAware.providedBy(self):
+ self.subform.update()
+ super(ObjectWidget, self).update()
+ def render(self):
+ return super(ObjectWidget, self).render()
+ def extract(self, default=interfaces.NOVALUE):
+ extracted = self.subform.widgets.extract()
+ return extracted
+
+ 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))
+
Added: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.txt
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.txt (rev 0)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.txt 2007-12-09 20:50:50 UTC (rev 82213)
@@ -0,0 +1,63 @@
+============
+ObjectWidget
+============
+FIXME: maybe move the more complete test from README to this file
+
+The widget can render a fieldset containing other widgets:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> from zope.app.form.interfaces import IInputWidget
+ >>> from z3c.form import interfaces
+ >>> from z3c.form.browser import object
+
+The ObjectWidget is a widget:
+
+ >>> verifyClass(interfaces.IWidget, object.ObjectWidget)
+ True
+
+The widget can render a fieldset by adapting only the request:
+
+ >>> from z3c.form.testing import TestRequest
+ >>> request = TestRequest()
+ >>> widget = object.ObjectWidget(request)
+
+Such a field provides IWidget:
+
+ >>> interfaces.IWidget.providedBy(widget)
+ True
+
+We also need to register the template for at least the widget and request:
+
+ >>> import os.path
+ >>> import zope.interface
+ >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+ >>> from zope.pagetemplate.interfaces import IPageTemplate
+ >>> import z3c.form.browser
+ >>> import z3c.form.widget
+ >>> template = os.path.join(os.path.dirname(z3c.form.browser.__file__),
+ ... 'object.pt')
+ >>> factory = z3c.form.widget.WidgetTemplateFactory(template)
+ >>> zope.component.provideAdapter(factory,
+ ... (zope.interface.Interface, IDefaultBrowserLayer, None, None, None),
+ ... IPageTemplate, name='input')
+
+If we render the widget we get the HTML:
+
+ >>> print widget.render()
+ <fieldset class="object-widget">
+ <legend></legend>
+ </fieldset>
+
+Adding some more attributes to the widget will make it display more:
+
+ >>> widget.id = 'id'
+ >>> widget.name = 'name'
+ >>> widget.style = u'color: blue'
+ >>> widget.label = u'custom label of the widget'
+
+ >>> print widget.render()
+ <fieldset id="id" name="name" class="object-widget"
+ style="color: blue">
+ <legend>custom label of the widget</legend>
+ </fieldset>
+
Added: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.zcml
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.zcml (rev 0)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/object.zcml 2007-12-09 20:50:50 UTC (rev 82213)
@@ -0,0 +1,32 @@
+<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.pt"
+ />
+<z3c:widgetTemplate
+ mode="display"
+ widget="z3c.form.interfaces.IObjectWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="object.pt"
+ />
+
+</configure>
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/tests.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/tests.py 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/browser/tests.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -65,4 +65,8 @@
setUp=testing.setUp, tearDown=testing.tearDown,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
),
+ DocFileSuite('object.txt',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
))
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/configure.zcml
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/configure.zcml 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/configure.zcml 2007-12-09 20:50:50 UTC (rev 82213)
@@ -68,6 +68,9 @@
/>
<adapter
factory=".converter.FieldWidgetDataConverter"
+ />
+ <adapter
+ factory=".converter.ObjectWidgetDataConverter"
/>
<!-- ITerms -->
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/converter.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/converter.py 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/converter.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -303,3 +303,26 @@
if value and value[0] == 'selected':
return True
return False
+
+class ObjectWidgetDataConverter(BaseDataConverter):
+ "A converter for ObjectWidget"
+
+ zope.component.adapts(
+ zope.schema.interfaces.IObject, interfaces.IObjectWidget)
+
+ def toWidgetValue(self, value):
+ print 'toWidgetValue'
+ print value
+
+ def toFieldValue(self, value):
+ print 'toFieldValue'
+ print value
+
+
+
+
+
+
+
+
+
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/field.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/field.py 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/field.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -225,8 +225,8 @@
if field.mode is not None:
mode = field.mode
elif field.field.readonly and not self.ignoreReadonly:
- mode = interfaces.DISPLAY_MODE
- elif not self.ignoreContext:
+ mode = interfaces.DISPLAY_MODE
+ elif not self.ignoreContext and self.content is not None:
# If we do not have enough permissions to write to the
# attribute, then switch to display mode.
dm = zope.component.getMultiAdapter(
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/form.txt
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/form.txt 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/form.txt 2007-12-09 20:50:50 UTC (rev 82213)
@@ -254,7 +254,14 @@
Since we have no customization components registered, all of those fields will
remain as set before.
+Subform for ObjectWidgets
+~~~~~~~~~~~~~~~~~~~~~~~~~
+If the field is an Object field, an ObjectWidget is created, and a
+subform is created and stored in the form. The widget itself
+can access to the subform through its subform attribute (provided by
+the ISubformAware interface)
+
Find an action manager, update and execute it
---------------------------------------------
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/interfaces.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/interfaces.py 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/interfaces.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -470,7 +470,10 @@
class IPasswordWidget(ITextWidget):
"""Password widget."""
+class IObjectWidget(IWidget):
+ """Object widget."""
+
class IWidgets(IManager):
"""A widget manager"""
@@ -715,7 +718,15 @@
form = zope.schema.Field()
+class ISubformAware(zope.interface.Interface):
+ """Offers a subform attribute.
+ Object Widgets need to access the subform they are associated to.
+ """
+
+ subform = zope.schema.Field()
+
+
class IForm(zope.interface.Interface):
"""Form"""
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/subform.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/subform.py 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/subform.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -53,9 +53,21 @@
def update(self):
super(EditSubForm, self).update()
- for action in self.parentForm.actions.executedActions:
- adapter = zope.component.queryMultiAdapter(
- (self, self.request, self.getContent(), action),
- interface=interfaces.IActionHandler)
- if adapter:
- adapter()
+ #FIXME: the code below may not be executed at all!
+ # The problem is that we update the subform while updating
+ # the parentForm. That means at this moment the actions manager
+ # has not been looked up and the parentForm.actions does not exist.
+ # The right order may be !
+ # -update form widgets
+ # -update subform widgets
+ # -update form actions
+ # -update subform actions?
+
+ def updateActions(self):
+ if hasattr(self.parentForm, 'actions'):
+ for action in self.parentForm.actions.executedActions:
+ adapter = zope.component.queryMultiAdapter(
+ (self, self.request, self.getContent(), action),
+ interface=interfaces.IActionHandler)
+ if adapter:
+ adapter()
Modified: Sandbox/ccomb/z3c.form/trunk/src/z3c/form/widget.py
===================================================================
--- Sandbox/ccomb/z3c.form/trunk/src/z3c/form/widget.py 2007-12-09 14:31:48 UTC (rev 82212)
+++ Sandbox/ccomb/z3c.form/trunk/src/z3c/form/widget.py 2007-12-09 20:50:50 UTC (rev 82213)
@@ -92,7 +92,7 @@
# context is to be used to extract a value, get
# it now via a data manager.
if (interfaces.IContextAware.providedBy(self) and
- not self.ignoreContext):
+ not self.ignoreContext and self.context is not None):
value = zope.component.getMultiAdapter(
(self.context, self.field), interfaces.IDataManager).get()
# Step 1.2.2: If we still do not have a value, we can always use
More information about the Checkins
mailing list