[Zope3-Users] z3c.formext into Plone
Laurent Mignon
laurent.mignon at softwareag.com
Fri Jan 30 12:54:58 EST 2009
Today, I've spent a lot of time trying to use z3c.formext into plone.
Here is a summary of the different adaptations to be done to make this
possible.
z3c.formext
-----------
* in the component.py file, the statement used into the getConfig
function of the Component class in not compatibe with Python2.4. (simple
fix)
{{{
return jsonEncode(self._getConfig()) if json else self._getConfig()
}}}
must be replaced by
{{{
if json:
return jsonEncode(self._getConfig())
return self._getConfig()
}}}
* I also have modified calls to the translate method to provide the
request as context since, in zope2, locale is set up on the request.
into jsoncompat.py
{{{
def translateObject(o, context):
if isinstance(o, list):
for index, value in enumerate(o):
o[index] = translateObject(value, context)
elif isinstance(o, tuple):
o = [translateObject(value, context) for value in o]
elif isinstance(o, dict):
for key, value in o.items():
o[key] = translateObject(value, context)
elif isinstance(o, unicode):
o = translate(o, context=context)
return o
def jsonEncode(o, context):
o = translateObject(o, context)
return encode(o)
}}}
* the handler used for the jsmodule zcml directive doesn't correctly
register the resource for zope2. To make the resource available, I've
modified the directive to use the same implementation that the one used
by Five. I can provide the new implementation into a new module (maybe
plone.z3cformext or collective.z3cformext or ???)
* the versionedResource zcml directive doen't work for me. I've just
registered the z3c.formext.loader.js as a simple browser:resource (it's
probably the same kind of problem that for the jsmodule directive.
z3c.formjs
----------
z3c.formjs is used to provide ajax functionalities used for button
handling.
These functionalities are provided by an AjaxRequestTraverserPlugin that
allow to access methods registered as an ajax request handler (ex button
handler).
These handler are provided as BrowserPage that allow these to be
publishable.
The AjaxRequestTraverserPlugin has to be rewritten since our z3c.form
instance are wrapped into a Five BrowserView by plone.z3cform.
The AjaxView must also be rewritten to mix in acquisition so that
security can be acquired for views.
My changes look like:
{{{
class AJAXView(Acquisition.Explicit, BrowserPage):
"""A wrapper class around AJAX handler to allow it to be
publishable.
Mixes in explicit acquisition so that security can be
acquired for
views"""
def __init__(self, handler, request, view):
self.context = self.handler = handler
self.request = request
self.__parent__ = self.view = view
#see Zope2.app.startup line 284 needed to build a physicalPath.
#it's probably not the good way
self.__name__ = self.handler.func.__name__
def __call__(self):
return self.handler(self.view)
class AJAXRequestTraverserPlugin(object):
"""Allow access to methods registered as an ajax request handler.
Call acquisition
"""
zope.interface.implements(ITraverserPlugin)
def __init__(self, context, request):
self.context = context
self.request = request
def publishTraverse(self, request, name):
#context is a plone.z3cform.layout.FormWrapper
#a call to switch_on' is required before we can
#update and use the form_instance
z2.switch_on(self.context,
request_layer=self.context.request_layer)
self.context.form_instance.update()
handler =
self.context.form_instance.ajaxRequestHandlers.get(name)
if handler is None:
raise NotFound(self.context, name, request)
#acquisition
return AJAXView(handler, self.request,
self.context).__of__(self.context)
}}}
The new implementation can be provided into a new module
(plone.z3cformjs or collective.z3cformjs or ???)
The taverser plugin would be registered as a subscriber for the
plone.z3cform.interfaces.IFormWrapper or a new interface defined in the
new module
{{{
<subscriber
for="plone.z3cform.interfaces.IFormWrapper
zope.publisher.interfaces.browser.IBrowserRequest"
provides="z3c.traverser.interfaces.ITraverserPlugin"
factory=".ajax.AJAXRequestTraverserPlugin"
/>
}}}
z3c.traverser
-------------
The factory used to provide the ajax traverser plugin is provided by
z3c.traverser.browser.PluggableBrowserTraverser.
The traversing process in zope2 is implemented into
ZPublisher.BaseRequest. The PluggableBrowserTraverser is looked up by
the traverseName method (line 308).
After the lookup, an explicit call to the Acquisition is performed
{{{
def traverseName(self, ob, name):
if name and name[:1] in '@+':
# Process URI segment parameters.
ns, nm = nsParse(name)
if ns:
try:
ob2 = namespaceLookup(ns, nm, ob, self)
except TraversalError:
raise KeyError(ob, name)
return ob2.__of__(ob)
}}}
Since the PluggableBrowserTraverser provided by z3c.traverser is not
Acquisition.Explicit, we need to provide a new one mixin the
z3c.traverser.browser.PluggableBrowserTraverser and Acquisition.Explicit.
The new traverser can be registered as an adapter for the
plone.z3cform.interfaces.IFormWrapper or the new interface provided by
(plone.z3cformjs or collective.z3cformjs or ???)
The new implementation can be provided into a new module
(plone.z3ctraverser or collective.z3ctraverser or ???) or we can use the
plone.z3cformjs module
into the plone.z3cformjs configure.zcml, the factory used for ajax would
be registered with
{{{
<adapter
trusted="True"
for="plone.z3cform.interfaces.IFormWrapper
zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.publisher.interfaces.browser.IBrowserPublisher"
factory="plone.z3ctraverser.browser.PluggableBrowserTraverser"
permission="zope.Public"
name="ajax"
/>
}}}
conclusion
----------
It's possible to use z3c.formext with Plone/zope2. Maybe, some of my
explanations are wrong and I've missed something... Your comments are
welcome.
I'm really impressed by the concepts and the functionalities provided by
the different modules involved into the integration of z3c.formext.
Thank you to their authors and contributors! The Plone community has
much to learn from what is done outside of itself... Plone
sorry for my English....
ps: I think that the z3cFormPanel extjs component uses the svn version
of extjs (probably the next 3.0). If you use extjs 2.2 you have to
modify some parts of the z3cFormPanel definition.
More information about the Zope3-users
mailing list