[Checkins] SVN: plone.z3cform/trunk/ Relicense and move
plone.z3cform into Zope repository
Daniel Nouri
daniel.nouri at gmail.com
Sun Jul 13 17:54:25 EDT 2008
Log message for revision 88331:
Relicense and move plone.z3cform into Zope repository
Changed:
A plone.z3cform/trunk/
A plone.z3cform/trunk/README.txt
A plone.z3cform/trunk/bootstrap.py
A plone.z3cform/trunk/buildout.cfg
A plone.z3cform/trunk/docs/
A plone.z3cform/trunk/docs/HISTORY.txt
A plone.z3cform/trunk/docs/INSTALL.txt
A plone.z3cform/trunk/docs/LICENSE.txt
A plone.z3cform/trunk/plone/
A plone.z3cform/trunk/plone/__init__.py
A plone.z3cform/trunk/plone/z3cform/
A plone.z3cform/trunk/plone/z3cform/__init__.py
A plone.z3cform/trunk/plone/z3cform/add.py
A plone.z3cform/trunk/plone/z3cform/base.py
A plone.z3cform/trunk/plone/z3cform/base.txt
A plone.z3cform/trunk/plone/z3cform/configure.zcml
A plone.z3cform/trunk/plone/z3cform/converter.py
A plone.z3cform/trunk/plone/z3cform/crud/
A plone.z3cform/trunk/plone/z3cform/crud/README.txt
A plone.z3cform/trunk/plone/z3cform/crud/__init__.py
A plone.z3cform/trunk/plone/z3cform/crud/crud-master.pt
A plone.z3cform/trunk/plone/z3cform/crud/crud-row.pt
A plone.z3cform/trunk/plone/z3cform/crud/crud-table.pt
A plone.z3cform/trunk/plone/z3cform/crud/crud.py
A plone.z3cform/trunk/plone/z3cform/fieldsets/
A plone.z3cform/trunk/plone/z3cform/fieldsets/README.txt
A plone.z3cform/trunk/plone/z3cform/fieldsets/__init__.py
A plone.z3cform/trunk/plone/z3cform/fieldsets/extensible.py
A plone.z3cform/trunk/plone/z3cform/fieldsets/group.py
A plone.z3cform/trunk/plone/z3cform/fieldsets/interfaces.py
A plone.z3cform/trunk/plone/z3cform/fieldsets/utils.py
A plone.z3cform/trunk/plone/z3cform/form.pt
A plone.z3cform/trunk/plone/z3cform/macros.pt
A plone.z3cform/trunk/plone/z3cform/overrides.zcml
A plone.z3cform/trunk/plone/z3cform/plone_skeleton.pt
A plone.z3cform/trunk/plone/z3cform/queryselect/
A plone.z3cform/trunk/plone/z3cform/queryselect/README.txt
A plone.z3cform/trunk/plone/z3cform/queryselect/__init__.py
A plone.z3cform/trunk/plone/z3cform/subform.pt
A plone.z3cform/trunk/plone/z3cform/templates.py
A plone.z3cform/trunk/plone/z3cform/templates.zcml
A plone.z3cform/trunk/plone/z3cform/testing.zcml
A plone.z3cform/trunk/plone/z3cform/tests.py
A plone.z3cform/trunk/plone/z3cform/widget.py
A plone.z3cform/trunk/plone/z3cform/wysiwyg/
A plone.z3cform/trunk/plone/z3cform/wysiwyg/README.txt
A plone.z3cform/trunk/plone/z3cform/wysiwyg/__init__.py
A plone.z3cform/trunk/plone/z3cform/wysiwyg/configure.zcml
A plone.z3cform/trunk/plone/z3cform/wysiwyg/widget.py
A plone.z3cform/trunk/plone/z3cform/wysiwyg/wysiwyg_input.pt
A plone.z3cform/trunk/plone/z3cform/z2.py
A plone.z3cform/trunk/setup.cfg
A plone.z3cform/trunk/setup.py
-=-
Added: plone.z3cform/trunk/README.txt
===================================================================
--- plone.z3cform/trunk/README.txt (rev 0)
+++ plone.z3cform/trunk/README.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,45 @@
+=============
+plone.z3cform
+=============
+
+plone.z3cform is a library that allows use of z3c.form with Zope 2 and
+Plone.
+
+Quick start
+===========
+
+Tons of examples of using ``z3c.form`` can be found online. This is a
+simple example of a form for Plone:
+
+ >>> from zope import interface, schema
+ >>> from z3c.form import form, field, button
+ >>> from plone.z3cform import base
+
+ >>> class MySchema(interface.Interface):
+ ... age = schema.Int(title=u"Age")
+
+ >>> class MyForm(form.Form):
+ ... fields = field.Fields(MySchema)
+ ... ignoreContext = True # don't try to get data from context
+ ...
+ ... @button.buttonAndHandler(u'Apply')
+ ... def handleApply(self, action):
+ ... data, errors = self.extractData()
+ ... print data['age'] # ... or do stuff
+
+ >>> class MyView(base.FormWrapper):
+ ... form = MyForm
+ ... label = u"Please enter your age"
+
+Note that we're using ``base.FormWrapper`` as a base class for our
+browser view. We can register the ``MyView`` view just like any other
+``browser:page``.
+
+Only the ``MyView`` bit is specific to ``plone.z3cform``. The rest is
+standard ``z3c.form`` stuff. For more details on the base FormWrapper
+class, see the ``plone.z3cform.base`` module.
+
+Please also refer to the `online documentation`_ for more details.
+
+.. _online documentation: http://plone.org/documentation/how-to/easy-forms-with-plone3
+
Property changes on: plone.z3cform/trunk/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/bootstrap.py
===================================================================
--- plone.z3cform/trunk/bootstrap.py (rev 0)
+++ plone.z3cform/trunk/bootstrap.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 21220 2008-06-20 15:57:16Z jfroche $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Property changes on: plone.z3cform/trunk/bootstrap.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/buildout.cfg
===================================================================
--- plone.z3cform/trunk/buildout.cfg (rev 0)
+++ plone.z3cform/trunk/buildout.cfg 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,66 @@
+[buildout]
+parts =
+ zope2
+ instance
+ plone
+ PILwoTK
+ test
+
+develop =
+ .
+
+find-links =
+ http://download.zope.org/distribution/
+ http://effbot.org/downloads
+
+[zope2]
+recipe = plone.recipe.zope2install
+url = ${plone:zope2-url}
+fake-zope-eggs = true
+# requiring zope.testing for z2testrunner
+# requiring zope.component for zope.i18n >= 3.4 which is needed for z3c.form
+skip-fake-eggs = zope.testing
+ zope.component
+ zope.i18n
+
+[instance]
+recipe = plone.recipe.zope2instance
+zope2-location = ${zope2:location}
+user = admin:admin
+verbose-security = on
+debug-mode = on
+products =
+ ${buildout:directory}/parts/plone
+
+eggs =
+ ${plone:eggs}
+ PILwoTK
+ zope.testing
+ plone.z3cform
+ zope.i18n
+
+zcml =
+ plone.z3cform
+
+[plone]
+recipe = plone.recipe.plone
+
+[PILwoTK]
+recipe = zc.recipe.egg
+find-links =
+ http://download.zope.org/distribution/
+
+[zopepy]
+recipe = zc.recipe.egg
+eggs = ${instance:eggs}
+interpreter = zopepy
+extra-paths = ${zope2:location}/lib/python
+scripts = zopepy
+
+[test]
+recipe = collective.recipe.z2testrunner
+zope2part = instance
+packages =
+ plone.z3cform
+extra-paths = ${buildout:directory}
+exit-with-status = true
Property changes on: plone.z3cform/trunk/buildout.cfg
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/docs/HISTORY.txt
===================================================================
--- plone.z3cform/trunk/docs/HISTORY.txt (rev 0)
+++ plone.z3cform/trunk/docs/HISTORY.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,42 @@
+Changelog
+=========
+
+0.3 - unreleased
+----------------
+
+* Add German translation.
+ [saily]
+
+0.2 - 2008-06-20
+----------------
+
+* Fix usage of NumberDataConverter with zope.i18n >= 3.4 as the
+ previous test setup was partial and did not register all adapters
+ from z3c.form (some of them depends on zope >= 3.4)
+ [gotcha, jfroche]
+
+* More tests
+ [gotcha, jfroche]
+
+0.1 - 2008-05-21
+----------------
+
+* Provide and *register* default form and subform templates. These
+ allow forms to be used with the style provided in this package
+ without having to declare ``form = ViewPageTemplateFile('form.pt')``.
+
+ This does not hinder you from overriding with your own ``form``
+ attribute like usual. You can also still register a more
+ specialized IPageTemplate for your form.
+
+* Add custom FileUploadDataConverter that converts a Zope 2 FileUpload
+ object to a Zope 3 one before handing it to the original
+ implementation. Also add support for different enctypes.
+ [skatja, nouri]
+
+* Added Archetypes reference selection widget (queryselect)
+ [malthe]
+
+* Moved generic Zope 2 compatibility code for z3c.form and a few
+ goodies from Singing & Dancing into this new package.
+ [nouri]
Property changes on: plone.z3cform/trunk/docs/HISTORY.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/docs/INSTALL.txt
===================================================================
--- plone.z3cform/trunk/docs/INSTALL.txt (rev 0)
+++ plone.z3cform/trunk/docs/INSTALL.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,2 @@
+Please refer to this online HOWTO for installation instructions for Plone:
+http://plone.org/documentation/how-to/easy-forms-with-plone3
Property changes on: plone.z3cform/trunk/docs/INSTALL.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/docs/LICENSE.txt
===================================================================
--- plone.z3cform/trunk/docs/LICENSE.txt (rev 0)
+++ plone.z3cform/trunk/docs/LICENSE.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,54 @@
+Zope Public License (ZPL) Version 2.1
+-------------------------------------
+
+A copyright notice accompanies this license document that
+identifies the copyright holders.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the
+ accompanying copyright notice, this list of conditions,
+ and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from the copyright
+ holders.
+
+4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use
+ Servicemarks (sm) or Trademarks (tm) of the copyright
+ holders. Use of them is covered by separate agreement
+ with the copyright holders.
+
+5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS``
+ AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
Property changes on: plone.z3cform/trunk/docs/LICENSE.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/__init__.py
===================================================================
--- plone.z3cform/trunk/plone/__init__.py (rev 0)
+++ plone.z3cform/trunk/plone/__init__.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Property changes on: plone.z3cform/trunk/plone/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/__init__.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/__init__.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/__init__.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,2 @@
+import zope.i18nmessageid
+MessageFactory = zope.i18nmessageid.MessageFactory('plone.z3cform')
Property changes on: plone.z3cform/trunk/plone/z3cform/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/add.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/add.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/add.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,74 @@
+from zope.app.container.interfaces import IContainerNamesContainer
+from zope.app.container.interfaces import INameChooser
+from zope.app.container.constraints import checkObject
+
+from Acquisition import aq_inner, aq_base
+from AccessControl import Unauthorized
+
+from Products.CMFCore.utils import getToolByName
+
+from z3c.form import form
+
+class AddForm(form.AddForm):
+ """CMF implementation of the add form
+ """
+
+ contentName = None
+
+ def add(self, object):
+
+ container = aq_inner(self.context)
+ content = object
+
+ name = self.contentName
+ chooser = INameChooser(container)
+
+ # Ensure that construction is allowed
+
+ portal_types = getToolByName(container, 'portal_types')
+ fti = portal_types.getTypeInfo(content)
+
+ if fti is not None:
+ # Check add permission
+ if not fti.isConstructionAllowed(container):
+ raise Unauthorized(u"You are not allowed to create a %d here" % fti.getId())
+ # Check allowable content types
+ if getattr(aq_base(container), 'allowedContentTypes', None) is not None and \
+ not fti.getId() in container.allowedContentTypes():
+ raise Unauthorized(u"You are not allowed to create a %d here" % fti.getId())
+
+ # check preconditions
+ checkObject(container, name, content)
+
+ if IContainerNamesContainer.providedBy(container):
+ # The container picks it's own names.
+ # We need to ask it to pick one.
+ name = chooser.chooseName(self.contentName or '', content)
+ else:
+ request = self.request
+ name = request.get('add_input_name', name)
+
+ if name is None:
+ name = chooser.chooseName(self.contentName or '', content)
+ elif name == '':
+ name = chooser.chooseName('', content)
+ else:
+ # Invoke the name chooser even when we have a
+ # name. It'll do useful things with it like converting
+ # the incoming unicode to an ASCII string.
+ name = chooser.chooseName(name, container)
+
+ if not name:
+ raise ValueError("Cannot add content: name chooser did not provide a name")
+
+ content.id = name
+ container._setObject(name, content)
+ content = container._getOb(name)
+
+ if fti is not None:
+ fti._finishConstruction(content)
+
+ self.contentName = name
+
+ def nextURL(self):
+ return "%s/%s/view" % (self.context.absolute_url(), self.contentName)
\ No newline at end of file
Property changes on: plone.z3cform/trunk/plone/z3cform/add.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/base.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/base.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/base.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,48 @@
+import z3c.form.interfaces
+from Products.Five import BrowserView
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+
+from plone.z3cform import z2
+
+class FormWrapper(BrowserView):
+ """Use this as a base class for your Five view and override the
+ 'form' attribute with your z3c.form form class. Your form will
+ then be rendered in the contents area of a Plone main template.
+ """
+ index = ViewPageTemplateFile('plone_skeleton.pt')
+ form = None # override this
+ request_layer = z3c.form.interfaces.IFormLayer
+
+ def __call__(self):
+ """This method renders the outer skeleton template, which in
+ turn calls the 'contents' method below.
+
+ We use an indirection to 'self.index' here to allow users to
+ override the skeleton template through the 'browser' zcml
+ directive.
+ """
+ return self.index()
+
+ def contents(self):
+ """This is the method that'll call your form. You don't
+ usually override this.
+ """
+ # A call to 'switch_on' is required before we can render
+ # z3c.forms within Zope 2.
+ z2.switch_on(self, request_layer=self.request_layer)
+ return self.render_form()
+
+ def render_form(self):
+ """This method returns the rendered z3c.form form.
+
+ Override this method if you need to pass a different context
+ to your form, or if you need to render a number of forms.
+ """
+ return self.form(self.context.aq_inner, self.request)()
+
+ def label(self):
+ """Override this method to use a different way of acquiring a
+ label or title for your page. Overriding this with a simple
+ attribute works as well.
+ """
+ return self.form.label
Property changes on: plone.z3cform/trunk/plone/z3cform/base.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/base.txt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/base.txt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/base.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,97 @@
+Base
+====
+
+Testing the FormWrapper class::
+
+ >>> from zope.interface import alsoProvides
+ >>> from zope.publisher.browser import TestRequest
+ >>> from zope.annotation.interfaces import IAttributeAnnotatable
+ >>> from z3c.form.interfaces import IFormLayer
+
+ >>> def make_request(form={}):
+ ... request = TestRequest()
+ ... request.form.update(form)
+ ... alsoProvides(request, IFormLayer)
+ ... alsoProvides(request, IAttributeAnnotatable)
+ ... return request
+
+Then we create a simple z3c form::
+
+ >>> from zope import interface, schema
+ >>> from z3c.form import form, field, button
+ >>> from plone.z3cform.base import FormWrapper
+
+ >>> class MySchema(interface.Interface):
+ ... age = schema.Int(title=u"Age")
+
+ >>> from z3c.form.interfaces import IFieldsForm
+ >>> from zope.interface import implements
+ >>> class MyWrappedForm(form.Form):
+ ... implements(IFieldsForm)
+ ... fields = field.Fields(MySchema)
+ ... ignoreContext = True # don't use context to get widget data
+ ...
+ ... @button.buttonAndHandler(u'Apply')
+ ... def handleApply(self, action):
+ ... data, errors = self.extractData()
+ ... print data['age'] # ... or do stuff
+
+ >>> class MyFormWrapper(FormWrapper):
+ ... form = MyWrappedForm
+ ... label = u"Please enter your age"
+
+ >>> from zope.component import provideAdapter
+ >>> from zope.publisher.interfaces.browser import IBrowserRequest
+ >>> from zope.interface import Interface
+
+ >>> provideAdapter(adapts=(Interface, IBrowserRequest),
+ ... provides=Interface,
+ ... factory=MyFormWrapper,
+ ... name=u"test-form")
+
+Let's verify that worked:
+
+ >>> from zope.component import getMultiAdapter
+ >>> context = object()
+ >>> request = make_request()
+ >>> getMultiAdapter((context, request), name=u"test-form")
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <MyFormWrapper object ...>
+ >>> del context, request
+
+Send bad data to the form:
+
+ >>> request = make_request(form={'form.widgets.age': '12.1'})
+ >>> from zope.interface import Interface, implements
+ >>> from Acquisition import Implicit
+ >>> class Bar(Implicit):
+ ... implements(Interface)
+ >>> context = Bar()
+ >>> formWrapper = getMultiAdapter((context, request), name=u"test-form")
+ >>> form = formWrapper.form(context, request)
+ >>> form.update()
+ >>> data, errors = form.extractData()
+ >>> data
+ {}
+ >>> errors
+ (<ValueErrorViewSnippet for ValueError>,)
+
+And then send correct data to the form:
+
+ >>> request = make_request(form={'form.widgets.age': '12'})
+ >>> from zope.interface import Interface, implements
+ >>> from Acquisition import Implicit
+ >>> class Bar(Implicit):
+ ... implements(Interface)
+ >>> context = Bar()
+ >>> formWrapper = getMultiAdapter((context, request), name=u"test-form")
+ >>> form = formWrapper.form(context, request)
+ >>> form.update()
+ >>> data, errors = form.extractData()
+ >>> data
+ {'age': 12}
+ >>> errors
+ ()
+
+
+
Property changes on: plone.z3cform/trunk/plone/z3cform/base.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/configure.zcml
===================================================================
--- plone.z3cform/trunk/plone/z3cform/configure.zcml (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/configure.zcml 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,15 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ i18n_domain="plone.z3cform">
+
+ <include package="z3c.form" file="meta.zcml" />
+ <include package="z3c.form" />
+
+ <includeOverrides file="overrides.zcml" />
+ <include file="templates.zcml" />
+
+ <i18n:registerTranslations directory="locales"/>
+
+</configure>
Property changes on: plone.z3cform/trunk/plone/z3cform/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/converter.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/converter.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/converter.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,26 @@
+import cgi
+import zope.publisher.browser
+import ZPublisher.HTTPRequest
+
+import z3c.form.interfaces
+import z3c.form.converter
+
+class FileUploadDataConverter(z3c.form.converter.FileUploadDataConverter):
+ """Although ZPublisher's and zope.publisher's FileUpload
+ implementations are almost identical, ``FileUploadDataConverter``
+ makes an ``isinstance`` call that breaks duck-typing.
+
+ Therefore, we override the stock ``FileUploadDataConverter`` with
+ this little class that will do the right thing when a Zope 2
+ FileUpload object is received.
+ """
+ def toFieldValue(self, value):
+ """See interfaces.IDataConverter"""
+ if isinstance(value, ZPublisher.HTTPRequest.FileUpload):
+ fieldstorage = cgi.FieldStorage()
+ fieldstorage.file = value
+ fieldstorage.headers = value.headers
+ fieldstorage.filename = value.filename
+ value = zope.publisher.browser.FileUpload(fieldstorage)
+
+ return super(FileUploadDataConverter, self).toFieldValue(value)
Property changes on: plone.z3cform/trunk/plone/z3cform/converter.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/crud/README.txt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/crud/README.txt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/crud/README.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,390 @@
+Crud
+====
+
+This module gives you an abstract base class to make CRUD forms with.
+These forms give you by default a tabular view of the objects, where
+attributes of the object can be edited in-place. Please refer to the
+``ICrudForm`` interface for more details.
+
+ >>> from plone.z3cform.crud import crud
+
+Setup
+-----
+
+ >>> from plone.z3cform.tests import setup_defaults
+ >>> setup_defaults()
+
+A simple form
+-------------
+
+First, let's define an interface and a class to play with:
+
+ >>> from zope import interface, schema
+ >>> class IPerson(interface.Interface) :
+ ... name = schema.TextLine()
+ ... age = schema.Int()
+
+ >>> class Person(object):
+ ... interface.implements(IPerson)
+ ... def __init__(self, name=None, age=None):
+ ... self.name, self.age = name, age
+ ... def __repr__(self):
+ ... return "<Person with name=%r, age=%r>" % (self.name, self.age)
+
+For this test, we take the the name of our persons as keys in our
+storage:
+
+ >>> storage = {'Peter': Person(u'Peter', 16),
+ ... 'Martha': Person(u'Martha', 32)}
+
+Our simple form looks like this:
+
+ >>> class MyForm(crud.CrudForm):
+ ... update_schema = IPerson
+ ...
+ ... def get_items(self):
+ ... return sorted(storage.items(), key=lambda x: x[1].name)
+ ...
+ ... def add(self, data):
+ ... person = Person(**data)
+ ... storage[str(person.name)] = person
+ ... return person
+ ...
+ ... def remove(self, (id, item)):
+ ... del storage[id]
+
+This is all that we need to render a combined edit add form containing
+all our items:
+
+ >>> from z3c.form.testing import TestRequest
+ >>> print MyForm(None, TestRequest())() \
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <div class="crud-form">...Martha...Peter...</div>
+
+Editing items with our form
+---------------------------
+
+Before we start with editing objects, let's log all events that the
+form fires for us:
+
+ >>> from zope.lifecycleevent.interfaces import IObjectModifiedEvent
+ >>> from plone.z3cform.tests import create_eventlog
+ >>> log = create_eventlog(IObjectModifiedEvent)
+
+ >>> request = TestRequest()
+ >>> request.form['crud-edit.Martha.widgets.select-empty-marker'] = u'1'
+ >>> request.form['crud-edit.Peter.widgets.select-empty-marker'] = u'1'
+ >>> request.form['crud-edit.Martha.widgets.name'] = u'Martha'
+ >>> request.form['crud-edit.Martha.widgets.age'] = 55
+ >>> request.form['crud-edit.Peter.widgets.name'] = u'Franz'
+ >>> request.form['crud-edit.Peter.widgets.age'] = 16
+ >>> request.form['crud-edit.form.buttons.edit'] = u'Apply changes'
+ >>> html = MyForm(None, request)()
+ >>> "Successfully updated" in html
+ True
+
+Two modified events should have been fired:
+
+ >>> event1, event2 = log.pop(), log.pop()
+ >>> storage['Peter'] in (event1.object, event2.object)
+ True
+ >>> storage['Martha'] in (event1.object, event2.object)
+ True
+ >>> log
+ []
+
+If we don't make any changes, we'll get a message that says so:
+
+ >>> html = MyForm(None, request)()
+ >>> "No changes made" in html
+ True
+ >>> log
+ []
+
+Now that we renamed Peter to Franz, it would be also nice to have
+Franz use 'Franz' as the id in the storage, wouldn't it?
+
+ >>> storage['Peter']
+ <Person with name=u'Franz', age=16>
+
+We can override the CrudForm's ``before_update`` method to perform a
+rename whenever the name of a person is changed:
+
+ >>> class MyRenamingForm(MyForm):
+ ... def before_update(self, item, data):
+ ... if data['name'] != item.name:
+ ... del storage[item.name]
+ ... storage[str(data['name'])] = item
+
+Let's rename Martha to Maria. This will give her another key in our
+storage:
+
+ >>> request.form['crud-edit.Martha.widgets.name'] = u'Maria'
+ >>> html = MyRenamingForm(None, request)()
+ >>> "Successfully updated" in html
+ True
+ >>> log.pop().object == storage['Maria']
+ True
+ >>> log
+ []
+ >>> sorted(storage.keys())
+ ['Maria', 'Peter']
+
+Next, we'll submit the form for edit, but we'll make no changes.
+Instead, we'll select one time. This shouldn't do anything, since we
+clicked the 'Apply changes' button:
+
+ >>> request.form['crud-edit.Maria.widgets.name'] = u'Maria'
+ >>> request.form['crud-edit.Maria.widgets.age'] = 55
+ >>> request.form['crud-edit.Maria.widgets.select'] = [u'selected']
+ >>> html = MyRenamingForm(None, request)()
+ >>> "No changes" in html
+ True
+ >>> log
+ []
+
+And what if we do have changes *and* click the checkbox?
+
+ >>> request.form['crud-edit.Maria.widgets.age'] = 50
+ >>> html = MyRenamingForm(None, request)()
+ >>> "Successfully updated" in html
+ True
+ >>> log.pop().object == storage['Maria']
+ True
+ >>> log
+ []
+
+If we omit the name, we'll get an error:
+
+ >>> request.form['crud-edit.Maria.widgets.name'] = u''
+ >>> html = MyRenamingForm(None, request)()
+ >>> "There were some errors" in html
+ True
+ >>> "Required input is missing" in html
+ True
+
+We expect an error message in the title cell of Maria:
+
+ >>> checkbox_pos = html.index('crud-edit.Maria.widgets.select-empty-marker')
+ >>> "Required input is missing" in html[checkbox_pos:]
+ True
+
+Delete an item with our form
+----------------------------
+
+We can delete an item by selecting the item we want to delete and
+clicking the "Delete" button:
+
+ >>> request = TestRequest()
+ >>> request.form['crud-edit.Peter.widgets.select'] = ['selected']
+ >>> request.form['crud-edit.form.buttons.delete'] = u'Delete'
+ >>> html = MyForm(None, request)()
+ >>> "Successfully deleted items" in html
+ True
+ >>> 'Franz' in html
+ False
+ >>> storage
+ {'Maria': <Person with name=u'Maria', age=50>}
+
+Add an item with our form
+-------------------------
+
+ >>> from zope.lifecycleevent.interfaces import IObjectCreatedEvent
+ >>> from plone.z3cform.tests import create_eventlog
+ >>> log = create_eventlog(IObjectCreatedEvent)
+
+ >>> request = TestRequest()
+ >>> request.form['crud-add.form.widgets.name'] = u'Daniel'
+ >>> request.form['crud-add.form.widgets.age'] = 28
+ >>> request.form['crud-add.form.buttons.add'] = u'Add'
+ >>> html = MyForm(None, request)()
+ >>> "Item added successfully" in html
+ True
+
+Added items should show up right away:
+
+ >>> "Daniel" in html
+ True
+
+ >>> storage['Daniel']
+ <Person with name=u'Daniel', age=28>
+ >>> log.pop().object == storage['Daniel']
+ True
+ >>> log
+ []
+
+Render some of the fields in view mode
+--------------------------------------
+
+We can implement in our form a ``view_schema`` attribute, which will
+then be used to view information in our form's table. Let's say we
+wanted the name of our persons to be viewable only in the table:
+
+ >>> from z3c.form import field
+ >>> class MyAdvancedForm(MyForm):
+ ... update_schema = field.Fields(IPerson).select('age')
+ ... view_schema = field.Fields(IPerson).select('name')
+ ... add_schema = IPerson
+
+ >>> print MyAdvancedForm(None, TestRequest())() \
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <div class="crud-form">...Daniel...Maria...</div>
+
+We can still edit the age of our Persons:
+
+ >>> request = TestRequest()
+ >>> request.form['crud-edit.Maria.widgets.age'] = 40
+ >>> request.form['crud-edit.Daniel.widgets.age'] = 35
+ >>> request.form['crud-edit.form.buttons.edit'] = u'Apply Changes'
+ >>> html = MyAdvancedForm(None, request)()
+ >>> "Successfully updated" in html
+ True
+
+ >>> storage['Maria'].age
+ 40
+ >>> storage['Daniel'].age
+ 35
+
+We can still add a Person using both name and age:
+
+ >>> request = TestRequest()
+ >>> request.form['crud-add.form.widgets.name'] = u'Thomas'
+ >>> request.form['crud-add.form.widgets.age'] = 28
+ >>> request.form['crud-add.form.buttons.add'] = u'Add'
+ >>> html = MyAdvancedForm(None, request)()
+ >>> "Item added successfully" in html
+ True
+ >>> len(storage)
+ 3
+ >>> storage['Thomas']
+ <Person with name=u'Thomas', age=28>
+
+Our form can also contain links to our items:
+
+ >>> class MyAdvancedLinkingForm(MyAdvancedForm):
+ ... def link(self, item, field):
+ ... if field == 'name':
+ ... return 'http://en.wikipedia.org/wiki/%s' % item.name
+
+ >>> print MyAdvancedLinkingForm(None, TestRequest())() \
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <div class="crud-form">...
+ ...<a href="http://en.wikipedia.org/wiki/Daniel"...
+ ...<a href="http://en.wikipedia.org/wiki/Maria"...
+ ...<a href="http://en.wikipedia.org/wiki/Thomas"...
+ </div>
+
+What if we wanted the name to be both used for linking to the item
+*and* for edit? We can just include the title field twice:
+
+ >>> class MyAdvancedLinkingForm(MyAdvancedLinkingForm):
+ ... update_schema = IPerson
+ ... view_schema = field.Fields(IPerson).select('name')
+ ... add_schema = IPerson
+
+ >>> print MyAdvancedLinkingForm(None, TestRequest())() \
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <div class="crud-form">...
+ ...<a href="http://en.wikipedia.org/wiki/Thomas"...Thomas...</a>...
+ </div>
+
+We can now change Thomas's name and see the change reflected in the
+Wikipedia link immediately:
+
+ >>> request = TestRequest()
+ >>> for name in 'Daniel', 'Maria', 'Thomas':
+ ... request.form['crud-edit.%s.widgets.name' % name] = storage[name].name
+ ... request.form['crud-edit.%s.widgets.age' % name] = storage[name].age
+ >>> request.form['crud-edit.Thomas.widgets.name'] = u'Dracula'
+ >>> request.form['crud-edit.form.buttons.edit'] = u'Apply Changes'
+
+ >>> print MyAdvancedLinkingForm(None, request)() \
+ ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
+ <div class="crud-form">...
+ ...<a href="http://en.wikipedia.org/wiki/Dracula"...Dracula...</a>...
+ </div>
+ >>> storage['Thomas'].name = u'Thomas'
+
+Don't render one part
+---------------------
+
+What if we wanted our form to display only one part, that is, only the
+add *or* the edit form. Our CrudForm can implement
+``editform_factory`` and ``addform_factory`` to override one or both
+forms. Seeting one of these to ``crud.NullForm`` will make them
+disappear:
+
+ >>> class OnlyEditForm(MyForm):
+ ... addform_factory = crud.NullForm
+ >>> html = OnlyEditForm(None, TestRequest())()
+ >>> 'Edit' in html, 'Add' in html
+ (True, False)
+
+ >>> class OnlyAddForm(MyForm):
+ ... editform_factory = crud.NullForm
+ >>> html = OnlyAddForm(None, TestRequest())()
+ >>> 'Edit' in html, 'Add' in html
+ (False, True)
+
+Render only in view, and define own actions
+-------------------------------------------
+
+Sometimes you want to present a list of items, possibly in view mode
+only, and have the user select one or more of the items to perform
+some action with them. We'll present a minimal example that does this
+here.
+
+We can simply leave the ``update_schema`` class attribute out (it
+defaults to ``None``). Furthermore, we'll need to override the
+ediform_factory with our custom version that provides other buttons
+than the 'edit' and 'delete' ones:
+
+ >>> from pprint import pprint
+ >>> from z3c.form import button
+
+ >>> class MyEditForm(crud.EditForm):
+ ... @button.buttonAndHandler(u'Capitalize', name='capitalize')
+ ... def handle_capitalize(self, action):
+ ... self.status = u"Please select items to capitalize first."
+ ... selected = self.selected_items()
+ ... if selected:
+ ... self.status = u"Capitalized items"
+ ... for id, item in selected:
+ ... item.name = item.name.upper()
+
+ >>> class MyCustomForm(crud.CrudForm):
+ ... view_schema = IPerson
+ ... editform_factory = MyEditForm
+ ... addform_factory = crud.NullForm # We don't want an add part.
+ ...
+ ... def get_items(self):
+ ... return sorted(storage.items(), key=lambda x: x[1].name)
+
+ >>> request = TestRequest()
+ >>> html = MyCustomForm(None, TestRequest())()
+ >>> "Delete" in html, "Apply changes" in html, "Capitalize" in html
+ (False, False, True)
+ >>> pprint(storage)
+ {'Daniel': <Person with name=u'Daniel', age=35>,
+ 'Maria': <Person with name=u'Maria', age=40>,
+ 'Thomas': <Person with name=u'Thomas', age=28>}
+
+ >>> request.form['crud-edit.Thomas.widgets.select'] = ['selected']
+ >>> request.form['crud-edit.form.buttons.capitalize'] = u'Capitalize'
+ >>> html = MyCustomForm(None, request)()
+ >>> "Capitalized items" in html
+ True
+ >>> pprint(storage)
+ {'Daniel': <Person with name=u'Daniel', age=35>,
+ 'Maria': <Person with name=u'Maria', age=40>,
+ 'Thomas': <Person with name=u'THOMAS', age=28>}
+
+We *cannot* use any of the other buttons:
+
+ >>> del request.form['crud-edit.form.buttons.capitalize']
+ >>> request.form['crud-edit.form.buttons.delete'] = u'Delete'
+ >>> html = MyCustomForm(None, request)()
+ >>> "Successfully deleted items" in html
+ False
+ >>> 'Thomas' in storage
+ True
Property changes on: plone.z3cform/trunk/plone/z3cform/crud/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/crud/__init__.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/crud/__init__.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/crud/__init__.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1 @@
+#
Property changes on: plone.z3cform/trunk/plone/z3cform/crud/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/crud/crud-master.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/crud/crud-master.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/crud/crud-master.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone.z3cform"
+ tal:omit-tag="">
+
+ <div class="portalMessage"
+ tal:condition="view/status" tal:content="view/status">
+ </div>
+
+ <p class="crud-description"
+ tal:condition="view/description"
+ tal:content="view/description">
+ </p>
+
+ <div tal:repeat="form view/subforms"
+ tal:content="structure form/render"
+ class="crud-form">
+ </div>
+
+ <div class="action" tal:repeat="action view/actions/values">
+ <input type="submit" tal:replace="structure action/render" />
+ </div>
+
+</html>
Property changes on: plone.z3cform/trunk/plone/z3cform/crud/crud-master.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/crud/crud-row.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/crud/crud-row.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/crud/crud-row.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,25 @@
+<tal:block define="tups view/getCombinedWidgets;
+ niceTitles view/getNiceTitles"
+ repeat="tup tups">
+
+ <td tal:define="error python:tup[0].error;
+ idx repeat/tup/index"
+ tal:attributes="class python:'field' + (error and ' error' or '')">
+ <tal:block repeat="widget tup">
+
+ <a href=""
+ tal:define="link python:view.context.context.link(view.getContent(), widget.field.__name__)"
+ tal:omit-tag="python:widget.mode == 'input' or link is None"
+ tal:attributes="href link">
+
+ <span class="error" tal:omit-tag="not:error">
+ <div tal:condition="error" tal:replace="structure error/render" />
+ <input type="text" tal:replace="structure widget/render" />
+ </span>
+
+ </a>
+ <br/>
+ </tal:block>
+
+ </td>
+</tal:block>
Property changes on: plone.z3cform/trunk/plone/z3cform/crud/crud-row.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/crud/crud-table.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/crud/crud-table.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/crud/crud-table.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,56 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone.z3cform"
+ tal:omit-tag=""
+ tal:condition="view/subforms">
+
+ <h2 tal:condition="view/label | nothing"
+ tal:content="view/label">Form title</h2>
+
+ <div class="portalMessage"
+ tal:condition="view/status" tal:content="view/status">
+ </div>
+
+ <form action="." method="post" tal:attributes="action request/getURL">
+
+ <table class="crud-table" tal:define="rows view/subforms">
+ <thead tal:define="row1 python:len(rows) and rows[0] or None"
+ tal:condition="python:row1 is not None">
+ <tr>
+ <th tal:define="widgetsForTitles row1/getTitleWidgets;
+ niceTitles row1/getNiceTitles"
+ tal:repeat="widget widgetsForTitles">
+
+ <span tal:define="idx repeat/widget/index"
+ tal:content="python: niceTitles[idx]"
+ tal:attributes="title widget/field/description;
+ class python: 'header-' + niceTitles[idx]">
+ Field
+ </span>
+
+ <span class="fieldRequired"
+ tal:condition="python:widget.required and widget.mode == 'input'"
+ i18n:attributes="title">
+ *
+ </span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tal:block repeat="row view/subforms">
+ <a name="" tal:attributes="name string:edit-${row/content_id}" />
+ <tr tal:content="structure row/render"
+ tal:attributes="class python:repeat['row'].odd() and 'odd' or 'even'" />
+ </tal:block>
+ </tbody>
+ </table>
+
+ <div class="action" tal:repeat="action view/actions/values">
+ <input type="submit" tal:replace="structure action/render" />
+ </div>
+
+ </form>
+
+</html>
Property changes on: plone.z3cform/trunk/plone/z3cform/crud/crud-table.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/crud/crud.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/crud/crud.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/crud/crud.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,310 @@
+from ZODB.POSException import ConflictError
+from zope import interface
+import zope.event
+import zope.lifecycleevent
+from z3c.form import button
+from z3c.form import field
+from z3c.form import form
+import z3c.form.widget
+from z3c.form.interfaces import DISPLAY_MODE, INPUT_MODE, NOVALUE
+from zope.app.pagetemplate import viewpagetemplatefile
+
+from plone.z3cform.widget import singlecheckboxwidget_factory
+from plone.z3cform import MessageFactory as _
+
+
+class ICrudForm(interface.Interface):
+
+ update_schema = interface.Attribute(
+ "Editable part of the schema for use in the update form.")
+
+ view_schema = interface.Attribute(
+ "Viewable (only) part of the schema for use in the update form.")
+
+ add_schema = interface.Attribute(
+ "Schema for use in the add form; defaults to ``update_schema``.")
+
+ def get_items():
+ """Subclasses must a list of all items to edit.
+
+ This list contains tuples of the form ``(id, item)``, where
+ the id is a unique identifiers to the items. The items must
+ be adaptable to the schema returned by ``update_schema`` and
+ ``view_schema`` methods.
+ """
+
+ def add(data):
+ """Subclasses must implement this method to create an item for
+ the given `data` *and* add it to a container, and return it.
+
+ The `data` mapping corresponds to the schema returned by
+ `add_schema`.
+ """
+
+ def remove((id, item)):
+ """Subclasses must implement this method to remove the given
+ item from the site.
+
+ It's left to the implementing class to notify of
+ ``zope.app.container.contained.ObjectRemovedEvent``.
+ """
+
+ def before_update(item, data):
+ """A hook that gets called before an item is updated.
+ """
+
+ def link(item, field):
+ """Return a URL for this item's field or None.
+ """
+
+class AbstractCrudForm(object):
+ """The AbstractCrudForm is not a form but implements methods
+ necessary to comply with the ``ICrudForm`` interface:
+
+ >>> from zope.interface.verify import verifyClass
+ >>> verifyClass(ICrudForm, AbstractCrudForm)
+ True
+ """
+ interface.implements(ICrudForm)
+
+ update_schema = None
+ view_schema = None
+
+ @property
+ def add_schema(self):
+ return self.update_schema
+
+ def get_items(self):
+ raise NotImplementedError
+
+ def add(self, data):
+ raise NotImplementedError
+
+ def remove(self, (id, item)):
+ raise NotImplementedError
+
+ def before_update(self, item, data):
+ pass
+
+ def link(self, item, field):
+ return None
+
+class EditSubForm(form.EditForm):
+ template = viewpagetemplatefile.ViewPageTemplateFile('crud-row.pt')
+
+ @property
+ def prefix(self):
+ return 'crud-edit.%s.' % self.content_id
+
+ # These are set by the parent form
+ content = None
+ content_id = None
+
+ @property
+ def fields(self):
+ fields = field.Fields(self._select_field())
+
+ crud_form = self.context.context
+
+ update_schema = crud_form.update_schema
+ if update_schema is not None:
+ fields += field.Fields(update_schema)
+
+ view_schema = crud_form.view_schema
+ if view_schema is not None:
+ view_fields = field.Fields(view_schema)
+ for f in view_fields.values():
+ f.mode = DISPLAY_MODE
+ # This is to allow a field to appear in both view
+ # and edit mode at the same time:
+ if not f.__name__.startswith('view_'):
+ f.__name__ = 'view_' + f.__name__
+ fields += view_fields
+
+ return fields
+
+ def getContent(self):
+ return self.content
+
+ def _select_field(self):
+ select_field = field.Field(
+ zope.schema.Bool(__name__='select',
+ required=False,
+ title=_(u'select')))
+ select_field.widgetFactory[INPUT_MODE] = singlecheckboxwidget_factory
+ return select_field
+
+ # XXX: The three following methods, 'getCombinedWidgets',
+ # 'getTitleWidgets', and 'getNiceTitles' are hacks to support the
+ # page template. Let's get rid of them.
+ def getCombinedWidgets(self):
+ """Returns pairs of widgets to improve layout"""
+ widgets = self.widgets.items()
+ combined = []
+ seen = set()
+ for name, widget in list(widgets):
+ if widget.mode == INPUT_MODE:
+ view_widget = self.widgets.get('view_%s' % name)
+ if view_widget is not None:
+ combined.append((widget, view_widget))
+ seen.add(view_widget)
+ else:
+ combined.append((widget,))
+ else:
+ if widget not in seen:
+ combined.append((widget,))
+ return combined
+
+ def getTitleWidgets(self):
+ combinedWidgets = self.getCombinedWidgets()
+ widgetsForTitles = [w[0] for w in combinedWidgets]
+ return widgetsForTitles
+
+ def getNiceTitles(self):
+ widgetsForTitles = self.getTitleWidgets()
+ freakList = []
+ for item in widgetsForTitles:
+ freakList.append(item.field.title)
+ return freakList
+
+class EditForm(form.Form):
+ label = _(u"Edit")
+ template = viewpagetemplatefile.ViewPageTemplateFile('crud-table.pt')
+
+ @property
+ def prefix(self):
+ parent_prefix = getattr(self.context, 'prefix', '')
+ return 'crud-edit.' + parent_prefix
+
+ def update(self):
+ self._update_subforms()
+ super(EditForm, self).update()
+
+ def _update_subforms(self):
+ self.subforms = []
+ for id, item in self.context.get_items():
+ subform = EditSubForm(self, self.request)
+ subform.content = item
+ subform.content_id = id
+ subform.update()
+ self.subforms.append(subform)
+
+ @button.buttonAndHandler(_('Apply changes'), name='edit')
+ def handle_edit(self, action):
+ success = _(u"Successfully updated")
+ partly_success = _(u"Some of your changes could not be applied.")
+ status = no_changes = _(u"No changes made.")
+ for subform in self.subforms:
+ # With the ``extractData()`` call, validation will occur,
+ # and errors will be stored on the widgets amongst other
+ # places. After this we have to be extra careful not to
+ # call (as in ``__call__``) the subform again, since
+ # that'll remove the errors again. With the results that
+ # no changes are applied but also no validation error is
+ # shown.
+ data, errors = subform.extractData()
+ if errors:
+ if status is no_changes:
+ status = subform.formErrorsMessage
+ elif status is success:
+ status = partly_success
+ continue
+ del data['select']
+ self.context.before_update(subform.content, data)
+ changes = subform.applyChanges(data)
+ if changes:
+ if status is no_changes:
+ status = success
+ elif status is subform.formErrorsMessage:
+ status = partly_success
+
+ # If there were changes, we'll update the view widgets
+ # again, so that they'll actually display the changes
+ [w.update() for w in subform.widgets.values()
+ if w.mode == DISPLAY_MODE]
+ self.status = status
+
+ @button.buttonAndHandler(_('Delete'), name='delete')
+ def handle_delete(self, action):
+ selected = self.selected_items()
+ if selected:
+ self.status = _(u"Successfully deleted items.")
+ for id, item in selected:
+ try:
+ self.context.remove((id, item))
+ except ConflictError:
+ raise
+ except:
+ # In case an exception is raised, we'll catch it
+ # and notify the user; in general, this is
+ # unexpected behavior:
+ self.status = _(u'Unable to remove one or more items.')
+ break
+
+ # We changed the amount of entries, so we update the subforms again.
+ self._update_subforms()
+ else:
+ self.status = _(u"Please select items to delete.")
+
+ def selected_items(self):
+ tuples = []
+ for subform in self.subforms:
+ data = subform.widgets['select'].extract()
+ if not data or data is NOVALUE:
+ continue
+ else:
+ tuples.append((subform.content_id, subform.content))
+ return tuples
+
+class AddForm(form.Form):
+ label = _(u"Add")
+ template = viewpagetemplatefile.ViewPageTemplateFile('../form.pt')
+ ignoreContext = True
+ ignoreRequest = True
+
+ @property
+ def prefix(self):
+ parent_prefix = getattr(self.context, 'prefix', '')
+ return 'crud-add.' + parent_prefix
+
+ @property
+ def fields(self):
+ return field.Fields(self.context.add_schema)
+
+ @button.buttonAndHandler(_('Add'), name='add')
+ def handle_add(self, action):
+ data, errors = self.extractData()
+ if errors:
+ self.status = form.AddForm.formErrorsMessage
+ return
+ item = self.context.add(data)
+ zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(item))
+ self.status = _(u"Item added successfully.")
+
+class NullForm(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def update(self):
+ pass
+
+ def render(self):
+ return ''
+ __call__ = render
+
+class CrudForm(AbstractCrudForm, form.Form):
+ template = viewpagetemplatefile.ViewPageTemplateFile('crud-master.pt')
+ description = u''
+
+ editform_factory = EditForm
+ addform_factory = AddForm
+
+ def update(self):
+ super(CrudForm, self).update()
+
+ addform = self.addform_factory(self, self.request)
+ editform = self.editform_factory(self, self.request)
+ addform.update()
+ editform.update()
+ self.subforms = [editform, addform]
Property changes on: plone.z3cform/trunk/plone/z3cform/crud/crud.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/fieldsets/README.txt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/fieldsets/README.txt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/fieldsets/README.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,144 @@
+Fieldsets and extensible forms
+==============================
+
+The ``fieldsets`` package provides support for groups/fieldsets and other
+modifications via "extender" adapters. The idea is that a third party
+component can modify the fields in the form and the way that they are grouped
+and ordered.
+
+This support relies on a mixin class, which is itself a subclass of
+z3c.form's GroupForm.
+
+ >>> from plone.z3cform.fieldsets import group, extensible
+
+To use this, you have to mix it into another form as the *first* base class:
+
+ >>> from zope.annotation import IAttributeAnnotatable
+ >>> from z3c.form import form, field, tests, group
+ >>> from zope.interface import Interface, implements
+ >>> from zope import schema
+
+ >>> class ITest(Interface):
+ ... title = schema.TextLine(title=u"Title")
+
+ >>> class Test(object):
+ ... implements(ITest, IAttributeAnnotatable)
+ ... title = u""
+
+ >>> class TestForm(extensible.ExtensibleForm, form.Form):
+ ... fields = field.Fields(ITest)
+
+Here, note the order of the base classes. Also note that we use an ordinary
+set of fields. This known as the default fieldset.
+
+This form should work as-is, i.e. we can update it:
+
+ >>> from z3c.form.testing import TestRequest
+
+ >>> request = TestRequest()
+ >>> context = Test()
+
+ >>> form = TestForm(context, request)
+ >>> form.update()
+ >>> _ = form.render()
+
+Now let's register an adapter that adds two new fields - one in the
+default fieldset as the first field, and one in a new group. To do this,
+we only need to register a named multi-adapter. However, we can use a
+convenience base class to make it easier to manipulate the fields of the
+form.
+
+ >>> from plone.z3cform.fieldsets.interfaces import IFormExtender
+ >>> from zope.component import adapts, provideAdapter
+
+ >>> class IExtraBehavior(Interface):
+ ... foo = schema.TextLine(title=u"Foo")
+ ... bar = schema.TextLine(title=u"Bar")
+ ... baz = schema.TextLine(title=u"Baz")
+ ... fub = schema.TextLine(title=u"Fub")
+
+One plausible implementation is to use an annotation to store this data.
+
+ >>> from zope.annotation import factory
+ >>> from zope.annotation.attribute import AttributeAnnotations
+ >>> from persistent import Persistent
+ >>> class ExtraBehavior(Persistent):
+ ... implements(IExtraBehavior)
+ ... adapts(Test)
+ ...
+ ... foo = u""
+ ... bar = u""
+ ... baz = u""
+ ... fub = u""
+
+ >>> ExtraBehavior = factory(ExtraBehavior)
+ >>> provideAdapter(ExtraBehavior)
+ >>> provideAdapter(AttributeAnnotations)
+
+We can now write the extender. The base class gives us some helper methods
+to add, remove and move fields. Here, we do a bit of unnecessary work just
+to exercise these methods.
+
+ >>> class ExtraBehaviorExtender(extensible.FormExtender):
+ ... adapts(Test, TestRequest, TestForm) # context, request, form
+ ...
+ ... def __init__(self, context, request, form):
+ ... self.context = context
+ ... self.request = request
+ ... self.form = form
+ ...
+ ... def update(self):
+ ... # Add all fields from an interface
+ ... self.add(IExtraBehavior, prefix="extra")
+ ...
+ ... # Remove the fub field
+ ... self.remove('fub', prefix="extra")
+ ...
+ ... all_fields = field.Fields(IExtraBehavior, prefix="extra")
+ ...
+ ... # Insert fub again, this time at the top
+ ... self.add(all_fields.select("fub", prefix="extra"), index=0)
+ ...
+ ... # Move 'baz' above 'fub'
+ ... self.move('baz', before='fub', prefix='extra', relative_prefix='extra')
+ ...
+ ... # Move 'foo' after 'bar' - here we specify prefix manually
+ ... self.move('foo', after='extra.bar', prefix='extra')
+ ...
+ ... # Remove 'bar' and re-insert into a new group
+ ... self.remove('bar', prefix='extra')
+ ... self.add(all_fields.select('bar', prefix='extra'), group='Second')
+ ...
+ ... # Move 'baz' after 'bar'. This means it also moves gropu.
+ ... self.move('extra.baz', after='extra.bar')
+
+
+ >>> provideAdapter(factory=ExtraBehaviorExtender, name=u"test.extender")
+
+With this in place, let's update the form once again.
+
+ >>> form = TestForm(context, request)
+ >>> form.update()
+
+At this point, we should have a set of default fields that represent the
+ones set in the adapter.
+
+ >>> form.fields.keys()
+ ['extra.fub', 'title', 'extra.foo']
+
+And we should have one group created by the group factory:
+
+ >>> form.groups # doctest: +ELLIPSIS
+ (<plone.z3cform.fieldsets.group.Group object at ...>,)
+
+Note that the created group is of a subtype of the standard z3c.form group,
+which has got support for a separate label and description as well as a
+canonical name.
+
+ >>> isinstance(form.groups[0], group.Group)
+ True
+
+This should have the group fields provided by the adapter as well.
+
+ >>> form.groups[0].fields.keys()
+ ['extra.bar', 'extra.baz']
\ No newline at end of file
Property changes on: plone.z3cform/trunk/plone/z3cform/fieldsets/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/fieldsets/__init__.py
===================================================================
Property changes on: plone.z3cform/trunk/plone/z3cform/fieldsets/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/fieldsets/extensible.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/fieldsets/extensible.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/fieldsets/extensible.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,64 @@
+from zope.interface import implements
+from zope.component import getAdapters
+
+from plone.z3cform.fieldsets.interfaces import IExtensibleForm
+from plone.z3cform.fieldsets.interfaces import IFormExtender
+
+from z3c.form.group import GroupForm
+
+from plone.z3cform.fieldsets import utils
+
+from plone.z3cform import MessageFactory as _
+
+def order_key(adapter_tuple):
+ return adapter_tuple[1].order
+
+class FormExtender(object):
+ """Base class for IFormExtender adapters with convenience APIs
+ """
+ implements(IFormExtender)
+
+ # Change this to prioritise
+ order = 0
+
+ def __init__(self, context, request, form):
+ self.context = context
+ self.request = request
+ self.form = form
+
+ def add(self, *args, **kwargs):
+ """Add one or more fields. Keyword argument 'index' can be used to
+ specify an index to insert at. Keyword argument 'group' can be used
+ to specify the label of a group, which will be found and used or
+ created if it doesn't exist.
+ """
+
+ utils.add(self.form, *args, **kwargs)
+
+ def remove(self, field_name, prefix=None):
+ """Get rid of a field. The omitted field will be returned.
+ """
+
+ return utils.remove(self.form, field_name, prefix=prefix)
+
+ def move(self, field_name, before=None, after=None, prefix=None, relative_prefix=None):
+ """Move the field with the given name before or after another field.
+ """
+
+ utils.move(self.form, field_name, before=before, after=after,
+ prefix=prefix, relative_prefix=relative_prefix)
+
+class ExtensibleForm(GroupForm):
+ implements(IExtensibleForm)
+
+ groups = []
+ default_fieldset_label = _(u"Default")
+
+ def update(self):
+ self.updateFields()
+ super(ExtensibleForm, self).update()
+
+ def updateFields(self):
+ extenders = getAdapters((self.context, self.request, self), IFormExtender)
+ for name, extender in sorted(extenders, key=order_key):
+ extender.update()
\ No newline at end of file
Property changes on: plone.z3cform/trunk/plone/z3cform/fieldsets/extensible.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/fieldsets/group.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/fieldsets/group.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/fieldsets/group.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,31 @@
+from zope.interface import implements
+
+from plone.z3cform.fieldsets.interfaces import IGroupFactory
+from plone.z3cform.fieldsets.interfaces import IDescriptiveGroup
+
+from z3c.form import group
+
+class Group(group.Group):
+ implements(IDescriptiveGroup)
+
+ __name__ = u""
+ label = u""
+ description = u""
+
+class GroupFactory(object):
+ implements(IGroupFactory)
+
+ def __init__(self, __name__, fields, label=None, description=None):
+ self.__name__ = __name__
+ self.fields = fields
+
+ self.label = label or __name__
+ self.description = description
+
+ def __call__(self, context, request, parentForm):
+ g = Group(context, request, parentForm)
+ g.__name__ = self.__name__
+ g.label = self.label
+ g.description = self.description
+ g.fields = self.fields
+ return g
\ No newline at end of file
Property changes on: plone.z3cform/trunk/plone/z3cform/fieldsets/group.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/fieldsets/interfaces.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/fieldsets/interfaces.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/fieldsets/interfaces.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,67 @@
+from zope.interface import Interface
+from zope import schema
+
+from z3c.form.interfaces import IFields, IGroup, IGroupForm
+
+class IFormExtender(Interface):
+ """A component that can add, modify, sort and group fields in a form.
+
+ This should be a named multi adapter from (context, request, form).
+ """
+
+ order = schema.Int(title=u"Order",
+ description=u"Use this property to order the sorter. " +
+ u"Low numbers are executed before high ones.",
+ required=True)
+
+ def update():
+ """Modify the form in place. Supported operations include:
+
+ - modify the 'fields' object to change the default fieldset
+ - modify the 'groups' list to add, remove or reorder fieldsets
+ - modify the 'fields' property of a given group
+ """
+
+class IDescriptiveGroup(IGroup):
+ """Extension to z3c.form's Group class that can separate out a name,
+ a label and a description.
+ """
+
+ __name__ = schema.TextLine(title=u"Name of this group")
+
+ label = schema.TextLine(title=u"Fieldset title",
+ description=u"The __name__ will be used if this is not given",
+ required=False)
+
+ description = schema.Text(title=u"Fieldset description",
+ required=False)
+
+class IGroupFactory(Interface):
+ """An object that can be used to create a z3c.form.group.Group.
+ """
+
+ __name__ = schema.TextLine(title=u"Name of this group")
+
+ label = schema.TextLine(title=u"Fieldset title",
+ description=u"The __name__ will be used if this is not given",
+ required=False)
+
+ description = schema.Text(title=u"Fieldset description",
+ required=False)
+
+ fields = schema.Object(title=u"Fields in this form", schema=IFields)
+
+class IExtensibleForm(Interface):
+ """A special version of the IGroupForm that is extensible via
+ IFormExtender adapters.
+ """
+
+ groups = schema.List(title=u'Groups',
+ value_type=schema.Object(title=u"Group", schema=IGroupFactory))
+
+ default_fieldset_label = schema.TextLine(title=u"Label of the default fieldset")
+
+ def updateFields():
+ """Called during form update to allow updating of self.fields
+ and self.groups.
+ """
\ No newline at end of file
Property changes on: plone.z3cform/trunk/plone/z3cform/fieldsets/interfaces.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/fieldsets/utils.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/fieldsets/utils.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/fieldsets/utils.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,108 @@
+from z3c.form.field import Fields
+from z3c.form.util import expandPrefix
+
+from plone.z3cform.fieldsets.group import GroupFactory
+
+def add(form, *args, **kwargs):
+ """Add one or more fields. Keyword argument 'index' can be used to
+ specify an index to insert at. Keyword argument 'group' can be used
+ to specify the label of a group, which will be found and used or
+ created if it doesn't exist.
+ """
+
+ index = kwargs.pop('index', None)
+ group = kwargs.pop('group', None)
+
+ new_fields = Fields(*args, **kwargs)
+
+ if not group or isinstance(group, basestring):
+ source = find_source(form, group=group)
+ else:
+ source = group
+
+ if source is None and group:
+ source = GroupFactory(group, new_fields)
+ form.groups.append(source)
+ else:
+ if index is None or index >= len(source.fields):
+ source.fields += new_fields
+ else:
+ field_names = source.fields.keys()
+ source.fields = source.fields.select(*field_names[:index]) + \
+ new_fields + \
+ source.fields.select(*field_names[index:])
+
+def remove(form, field_name, prefix=None):
+ """Get rid of a field. The omitted field will be returned.
+ """
+
+ if prefix:
+ field_name = expandPrefix(prefix) + field_name
+
+ if field_name in form.fields:
+ field = form.fields[field_name]
+ form.fields = form.fields.omit(field_name)
+ return field
+ else:
+ for group in form.groups:
+ if field_name in group.fields:
+ field = group.fields[field_name]
+ group.fields = group.fields.omit(field_name)
+ return field
+
+def move(form, field_name, before=None, after=None, prefix=None, relative_prefix=None):
+ """Move the field with the given name before or after another field.
+ """
+
+ if prefix:
+ field_name = expandPrefix(prefix) + field_name
+
+ if before and after:
+ raise ValueError(u"Only one of 'before' or 'after' is allowed")
+
+ offset = 0
+ if after:
+ offset = 1
+
+ relative = before or after
+ if relative_prefix:
+ relative = expandPrefix(relative_prefix) + relative
+
+ if field_name not in form.fields:
+ raise KeyError("Field %s not found" % field_name)
+
+ if relative not in form.fields:
+ found = False
+ for group in form.groups:
+ if relative in group.fields:
+ found = True
+ break
+ if not found:
+ raise KeyError("Field %s not found" % relative)
+
+ field = remove(form, field_name)
+
+ group = None
+ index = None
+
+ if relative in form.fields:
+ index = form.fields.keys().index(relative)
+ else:
+ for group in form.groups:
+ if relative in group.fields:
+ index = group.fields.keys().index(relative)
+ break
+
+ if index is None:
+ raise KeyError("Field %s not found" % relative)
+
+ add(form, field, group=group, index=index+offset)
+
+def find_source(form, group=None):
+ if group is not None:
+ group_factory = [g for g in form.groups if g.__name__ == group]
+ if len(group_factory) >= 1:
+ return group_factory[0]
+ else:
+ return None
+ return form
\ No newline at end of file
Property changes on: plone.z3cform/trunk/plone/z3cform/fieldsets/utils.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/form.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/form.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/form.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1 @@
+<metal:use use-macro="context/@@ploneform-macros/form" />
Property changes on: plone.z3cform/trunk/plone/z3cform/form.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/macros.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/macros.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/macros.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,168 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone.z3cform"
+ tal:omit-tag="">
+
+ <head></head>
+
+ <body>
+
+ <div class="form" metal:define-macro="form">
+
+ <h3 tal:condition="view/label | nothing">
+ <span tal:replace="view/label">Form title</span>:</h3>
+
+ <metal:define define-macro="titlelessform">
+
+ <tal:status define="status view/status" condition="status">
+ <dl class="portalMessage error"
+ tal:condition="view/widgets/errors">
+ <dt i18n:translate="">
+ Error
+ </dt>
+ <dd tal:content="status" />
+ </dl>
+
+ <dl class="portalMessage info"
+ tal:condition="not: view/widgets/errors">
+ <dt i18n:translate="">
+ Info
+ </dt>
+ <dd tal:content="status" />
+ </dl>
+ </tal:status>
+
+ <tal:comment condition="nothing">
+ <ul tal:define="errors view/widgets/errors"
+ tal:condition="errors">
+ <li tal:repeat="error errors">
+ <tal:block replace="error/widget/label"/>:
+ <tal:block replace="structure error/render" />
+ </li>
+ </ul>
+ </tal:comment>
+
+ <p class="discreet"
+ tal:define="description view/description | nothing"
+ tal:content="description">
+ Description
+ </p>
+
+ <form class="rowlike enableUnloadProtection" action="." method="post"
+ tal:define="groups view/groups | nothing;
+ form_name view/form_name | nothing;
+ default_fieldset_label view/default_fieldset_label | form_name;
+ has_groups python:bool(groups);
+ show_default_label python:has_groups and default_fieldset_label or form_name;"
+ tal:attributes="action request/getURL; enctype view/enctype;
+ class python: has_groups and 'rowlike enableUnloadProtection enableFormTabbing' or default">
+
+ <input type="hidden"
+ name="fieldset.current"
+ tal:condition="has_groups"
+ tal:attributes="value request/fieldset.current | string:" />
+
+ <!-- Default fieldset -->
+
+ <metal:define define-macro="fields">
+
+ <fieldset id="fieldset-default" tal:omit-tag="not:show_default_label">
+
+ <legend tal:condition="show_default_label"
+ tal:attributes="id string:fieldsetlegend-default"
+ tal:content="default_fieldset_label">Form name</legend>
+
+ <metal:define define-macro="widget_rendering">
+ <tal:widgets repeat="widget view/widgets/values">
+ <div class="row horizontal"
+ tal:define="hidden python:widget.mode == 'hidden'"
+ tal:omit-tag="hidden">
+
+ <metal:field define-macro="field">
+ <div class="field"
+ tal:define="error widget/error"
+ tal:attributes="class python:'field' + (error and ' error' or '')">
+
+ <label for="" class="horizontal"
+ tal:attributes="for widget/id"
+ tal:condition="not:hidden">
+ <span i18n:translate=""
+ tal:content="widget/label">label</span>
+ </label>
+
+ <span class="fieldRequired horizontal" title="Required"
+ tal:condition="python:widget.required and not hidden"
+ i18n:translate="label_required"
+ i18n:attributes="title title_required;">
+ (Required)
+ </span>
+
+ <div class="formHelp"
+ tal:define="description widget/field/description"
+ i18n:translate=""
+ tal:content="description"
+ tal:condition="python:description and not hidden"
+ >field description</div>
+
+ <div tal:condition="error"
+ tal:content="error/message">
+ Error
+ </div>
+
+ <div class="widget horizontal">
+ <input type="text" tal:replace="structure widget/render" />
+ </div>
+ </div>
+ </metal:field>
+
+ </div>
+ </tal:widgets>
+ </metal:define>
+
+ </fieldset>
+
+ <!-- Secondary fieldsets -->
+
+ <fieldset
+ tal:condition="has_groups"
+ tal:repeat="group groups"
+ tal:attributes="id string:fieldset-${repeat/group/index}">
+
+ <legend tal:define="form_name group/label"
+ tal:condition="form_name"
+ tal:attributes="id string:fieldsetlegend-${repeat/group/index}"
+ tal:content="form_name">Form name</legend>
+
+ <p i18n:translate=""
+ tal:define="group_description group/description|nothing"
+ tal:condition="group_description"
+ tal:content="group_description">
+ Description
+ </p>
+
+ <tal:block define="view nocall:group">
+ <metal:block use-macro="context/@@ploneform-macros/widget_rendering" />
+ </tal:block>
+
+ </fieldset>
+ </metal:define>
+
+ <metal:define define-macro="actions">
+
+ <div class="formFields" tal:condition="view/actions/values|nothing">
+ <tal:block repeat="action view/actions/values">
+ <input type="submit"
+ tal:replace="structure action/render" />
+ </tal:block>
+ </div>
+ </metal:define>
+
+ </form>
+ </metal:define>
+ </div>
+
+
+ </body>
+</html>
Property changes on: plone.z3cform/trunk/plone/z3cform/macros.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/overrides.zcml
===================================================================
--- plone.z3cform/trunk/plone/z3cform/overrides.zcml (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/overrides.zcml 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,7 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <adapter
+ factory=".converter.FileUploadDataConverter"
+ />
+
+</configure>
Property changes on: plone.z3cform/trunk/plone/z3cform/overrides.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/plone_skeleton.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/plone_skeleton.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/plone_skeleton.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,24 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ lang="en"
+ metal:use-macro="here/main_template/macros/master"
+ i18n:domain="plone.z3cform">
+<body>
+
+ <metal:main fill-slot="main">
+ <tal:main-macro metal:define-macro="main">
+
+ <h1 class="documentFirstHeading" tal:content="view/label">Title</h1>
+
+ <div id="skel-contents">
+ <span tal:replace="structure view/contents" />
+ </div>
+
+ </tal:main-macro>
+</metal:main>
+
+</body>
+</html>
+
Property changes on: plone.z3cform/trunk/plone/z3cform/plone_skeleton.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/queryselect/README.txt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/queryselect/README.txt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/queryselect/README.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,34 @@
+Query select widget
+===================
+
+The ``queryselect`` module provides a query source compatible with
+``z3c.formwidget.query`` which combines to a selection field that can
+be queried.
+
+The native value type for the widget is Archetypes UID collections.
+The default implementation will simply search using the
+``SearchableText`` index in the portal catalog.
+
+This is how your form schema could look like:
+
+ >>> from zope import interface, schema
+ >>> from plone.z3cform.queryselect import ArchetypesContentSourceBinder
+
+ >>> class ISelection(interface.Interface):
+ ... items = schema.Set(
+ ... title=u"Selection",
+ ... description=u"Search for content",
+ ... value_type=schema.Choice(
+ ... source=ArchetypesContentSourceBinder()))
+
+Optionally, instead of storing Archetypes UIDs, you can choose to use
+``persistent.wref``, i.e. weak references, instead of UIDs:
+
+ >>> from plone.z3cform.queryselect import uid2wref
+ >>> factory = uid2wref(ISelection['items'])
+
+To store weak references instead of UIDs you would register such a
+factory as a component adapting the context. The factory
+automatically provides the interface which defines the field.
+(XXX: Please rewrite this paragraph.)
+
Property changes on: plone.z3cform/trunk/plone/z3cform/queryselect/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/queryselect/__init__.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/queryselect/__init__.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/queryselect/__init__.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,71 @@
+from zope import interface
+from zope import schema
+
+import zope.schema.interfaces
+import zope.schema.vocabulary
+
+import z3c.formwidget.query.interfaces
+import persistent.wref
+
+from Products.CMFCore import utils as cmfutils
+
+class ArchetypesContentSource(object):
+ interface.implements(z3c.formwidget.query.interfaces.IQuerySource)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __contains__(self, uid):
+ """Verify the item exists."""
+
+ return bool(self.catalog(uid=uid))
+
+ def __iter__(self):
+ return [].__iter__()
+
+ @property
+ def catalog(self):
+ return cmfutils.getToolByName(self.context, 'portal_catalog')
+
+ def getTermByToken(self, token):
+ uid = token
+ brain = self.catalog(UID=uid)[0]
+ return self._term_for_brain(brain)
+
+ def getTermByValue(self, value):
+ uid = value
+ brain = self.catalog(UID=uid)[0]
+ return self._term_for_brain(brain)
+
+ def search(self, query_string, limit=20):
+ brains = self.catalog(SearchableText=query_string)[:limit]
+ return map(self._term_for_brain, brains)
+
+ def _term_for_brain(self, brain):
+ return zope.schema.vocabulary.SimpleTerm(brain.UID, brain.UID, brain.Title)
+
+class ArchetypesContentSourceBinder(object):
+ interface.implements(zope.schema.interfaces.IContextSourceBinder)
+
+ def __call__(self, context):
+ return ArchetypesContentSource(context)
+
+def uid2wref(field):
+ class Adapter(object):
+ interface.implements(field.interface)
+
+ def __init__(self, context):
+ self.context = context
+
+ def _get_items(self):
+ items = filter(None, (wref() for wref in self.context.items))
+ return [item.UID() for item in items]
+
+ def _set_items(self, uids):
+ catalog = cmfutils.getToolByName(self.context, 'portal_catalog')
+ brains = catalog(UID=tuple(uids))
+ items = [brain.getObject() for brain in brains]
+ self.context.items = map(persistent.wref.WeakRef, items)
+
+ setattr(Adapter, field.__name__, property(_get_items, _set_items))
+ return Adapter
Property changes on: plone.z3cform/trunk/plone/z3cform/queryselect/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/subform.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/subform.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/subform.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,7 @@
+<div tal:attributes="class view/css_class|nothing">
+ <h3 tal:replace="structure view/heading|nothing" />
+ <div tal:replace="structure view/contents_top|nothing" />
+ <metal:use use-macro="context/@@ploneform-macros/fields" />
+ <metal:use use-macro="context/@@ploneform-macros/actions" />
+ <div tal:replace="structure view/contents_bottom|nothing" />
+</div>
Property changes on: plone.z3cform/trunk/plone/z3cform/subform.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/templates.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/templates.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/templates.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,28 @@
+"""This module provides "form template factories" that can be
+registered to provide default form templates for forms and subforms
+that have a Plone style. These default templates draw from a macro
+page template which you can use by itself to render parts of it.
+"""
+
+import os
+import zope.publisher.browser
+import zope.app.pagetemplate.viewpagetemplatefile
+
+import z3c.form.interfaces
+from z3c.form.form import FormTemplateFactory
+
+import plone.z3cform
+
+path = lambda p: os.path.join(os.path.dirname(plone.z3cform.__file__), p)
+
+form_factory = FormTemplateFactory(
+ path('form.pt'), form=z3c.form.interfaces.IForm)
+subform_factory = FormTemplateFactory(
+ path('subform.pt'), form=z3c.form.interfaces.ISubForm)
+
+class Macros(zope.publisher.browser.BrowserView):
+ template = zope.app.pagetemplate.viewpagetemplatefile.ViewPageTemplateFile(
+ 'macros.pt')
+
+ def __getitem__(self, key):
+ return self.template.macros[key]
Property changes on: plone.z3cform/trunk/plone/z3cform/templates.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/templates.zcml
===================================================================
--- plone.z3cform/trunk/plone/z3cform/templates.zcml (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/templates.zcml 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,18 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="plone.z3cform">
+
+ <browser:page
+ name="ploneform-macros"
+ for="*"
+ class=".templates.Macros"
+ template="macros.pt"
+ allowed_interface="zope.interface.common.mapping.IItemMapping"
+ permission="zope.Public"
+ />
+
+ <adapter factory=".templates.form_factory" />
+ <adapter factory=".templates.subform_factory" />
+
+</configure>
Property changes on: plone.z3cform/trunk/plone/z3cform/templates.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/testing.zcml
===================================================================
--- plone.z3cform/trunk/plone/z3cform/testing.zcml (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/testing.zcml 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,16 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
+ xmlns:plone="http://namespaces.plone.org/plone"
+ i18n_domain="plone.z3cform">
+
+ <include file="configure.zcml" package="Products.Five"/>
+ <include file="meta.zcml" package="z3c.form"/>
+ <include file="configure.zcml" package="z3c.form"/>
+ <includeOverrides file="overrides.zcml" package="plone.z3cform"/>
+
+ <include file="configure.zcml" package="plone.z3cform"/>
+
+</configure>
+
Property changes on: plone.z3cform/trunk/plone/z3cform/testing.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/tests.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/tests.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/tests.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,96 @@
+import unittest
+from zope.testing import doctest
+
+from zope import component
+from zope import interface
+import zope.traversing.adapters
+import zope.traversing.namespace
+from zope.component import testing
+import zope.publisher.interfaces.browser
+import z3c.form.testing
+import plone.z3cform
+import os
+import plone.z3cform.templates
+
+def create_eventlog(event=interface.Interface):
+ value = []
+ @component.adapter(event)
+ def log(event):
+ value.append(event)
+ component.provideHandler(log)
+ return value
+
+def setup_defaults():
+ # Set up z3c.form defaults
+ z3c.form.testing.setupFormDefaults()
+ # Make traversal work; register both the default traversable
+ # adapter and the ++view++ namespace adapter
+ component.provideAdapter(
+ zope.traversing.adapters.DefaultTraversable, [None])
+ component.provideAdapter(
+ zope.traversing.namespace.view, (None, None), name='view')
+
+ # Setup ploneform macros
+ component.provideAdapter(
+ plone.z3cform.templates.Macros,
+ (None, None),
+ zope.publisher.interfaces.browser.IBrowserView,
+ name='ploneform-macros')
+ # setup plone.z3cform template
+ from zope.pagetemplate.interfaces import IPageTemplate
+
+ component.provideAdapter(
+ plone.z3cform.templates.form_factory,
+ (None, None),
+ IPageTemplate)
+
+ component.provideAdapter(
+ z3c.form.error.ErrorViewSnippet,
+ (None, None, None, None, None, None),
+ z3c.form.interfaces.IErrorViewSnippet)
+
+from zope.app.testing.functional import ZCMLLayer
+testingZCMLPath = os.path.join(os.path.dirname(__file__), 'testing.zcml')
+fullZ3CFormLayer = ZCMLLayer(testingZCMLPath,
+ 'plone.z3cform',
+ 'fullZ3CFormLayer')
+
+def test_suite():
+ fullZ3CForm = doctest.DocFileSuite('base.txt')
+ fullZ3CForm.layer = fullZ3CFormLayer
+
+ fieldsets = doctest.DocFileSuite('fieldsets/README.txt')
+ fieldsets.layer = fullZ3CFormLayer
+
+ return unittest.TestSuite([
+
+ doctest.DocFileSuite(
+ 'crud/README.txt',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ ),
+
+ fullZ3CForm,
+
+ fieldsets,
+
+ doctest.DocFileSuite(
+ 'wysiwyg/README.txt',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ ),
+
+ doctest.DocFileSuite(
+ 'queryselect/README.txt',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ ),
+
+ doctest.DocTestSuite(
+ 'plone.z3cform.crud.crud',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ ),
+
+ doctest.DocTestSuite(
+ 'plone.z3cform.wysiwyg.widget',
+ setUp=testing.setUp, tearDown=testing.tearDown,
+ ),
+
+ ])
Property changes on: plone.z3cform/trunk/plone/z3cform/tests.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/widget.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/widget.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/widget.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,38 @@
+from zope import interface
+from zope.schema import vocabulary
+
+import z3c.form.term
+import z3c.form.browser.checkbox
+import z3c.form.interfaces
+
+class SingleCheckboxWidget(z3c.form.browser.checkbox.SingleCheckBoxWidget):
+ """XXX: We need to refactor this and patch z3c.form where
+ it makes sense.
+ """
+
+ def update(self):
+ self.ignoreContext = True
+ super(SingleCheckboxWidget, self).update()
+
+ def updateTerms(self):
+ # The default implementation would render "selected" as a
+ # lebel for the single checkbox. We use no label instead.
+ if self.terms is None:
+ self.terms = z3c.form.term.Terms()
+ self.terms.terms = vocabulary.SimpleVocabulary((
+ vocabulary.SimpleTerm(True, 'selected', u''),
+ ))
+ return self.terms
+
+ def extract(self, default=z3c.form.interfaces.NOVALUE):
+ # The default implementation returns [] here.
+ if (self.name not in self.request and
+ self.name+'-empty-marker' in self.request):
+ return default
+ else:
+ return super(SingleCheckboxWidget, self).extract(default)
+
+ at interface.implementer(z3c.form.interfaces.IDataConverter)
+def singlecheckboxwidget_factory(field, request):
+ widget = SingleCheckboxWidget(request)
+ return z3c.form.widget.FieldWidget(field, widget)
Property changes on: plone.z3cform/trunk/plone/z3cform/widget.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/wysiwyg/README.txt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/wysiwyg/README.txt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/wysiwyg/README.txt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,25 @@
+WYSIWYG widget
+==============
+
+The ``wysiwyg`` package provides an implementation of the Plone
+WYSIWYG widget compatible with ``z3c.form``. This will allow you to
+use Kupu, FCKeditor and other editors compatible with the Plone
+WYSIWYG interface in your ``z3c.form`` forms.
+
+To use, simply set the widget factory for the widget you'd like to be
+displayed with the WYSIWYG widget:
+
+ >>> from zope import interface, schema
+ >>> from z3c.form import form, field
+ >>> from z3c.form.interfaces import INPUT_MODE
+ >>> from plone.z3cform.wysiwyg.widget import WysiwygFieldWidget
+
+ >>> class IProfile(interface.Interface):
+ ... name = schema.TextLine(title=u"Name")
+ ... age = schema.Int(title=u"Age")
+ ... bio = schema.Text(title=u"Bio")
+
+ >>> class MyForm(form.Form):
+ ... fields = field.Fields(IProfile)
+ ... fields['bio'].widgetFactory[INPUT_MODE] = WysiwygFieldWidget
+
Property changes on: plone.z3cform/trunk/plone/z3cform/wysiwyg/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/wysiwyg/__init__.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/wysiwyg/__init__.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/wysiwyg/__init__.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1 @@
+#
Property changes on: plone.z3cform/trunk/plone/z3cform/wysiwyg/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/wysiwyg/configure.zcml
===================================================================
--- plone.z3cform/trunk/plone/z3cform/wysiwyg/configure.zcml (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/wysiwyg/configure.zcml 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,20 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:z3c="http://namespaces.zope.org/z3c"
+ i18n_domain="plone.z3cform">
+
+ <class class=".widget.WysiwygWidget">
+ <require
+ permission="zope.Public"
+ interface=".widget.IWysiwygWidget"
+ />
+ </class>
+
+ <z3c:widgetTemplate
+ mode="input"
+ widget=".widget.IWysiwygWidget"
+ layer="z3c.form.interfaces.IFormLayer"
+ template="wysiwyg_input.pt"
+ />
+
+</configure>
Property changes on: plone.z3cform/trunk/plone/z3cform/wysiwyg/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/wysiwyg/widget.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/wysiwyg/widget.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/wysiwyg/widget.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,26 @@
+import zope.interface
+import zope.schema.interfaces
+
+import z3c.form.interfaces
+import z3c.form.browser.textarea
+import z3c.form.widget
+
+class IWysiwygWidget(z3c.form.interfaces.ITextAreaWidget):
+ pass
+
+class WysiwygWidget(z3c.form.browser.textarea.TextAreaWidget):
+ zope.interface.implementsOnly(IWysiwygWidget)
+
+ klass = u'kupu-widget'
+ value = u''
+
+ def update(self):
+ super(z3c.form.browser.textarea.TextAreaWidget, self).update()
+ z3c.form.browser.widget.addFieldClass(self)
+
+ at zope.component.adapter(zope.schema.interfaces.IField,
+ z3c.form.interfaces.IFormLayer)
+ at zope.interface.implementer(z3c.form.interfaces.IFieldWidget)
+def WysiwygFieldWidget(field, request):
+ """IFieldWidget factory for WysiwygWidget."""
+ return z3c.form.widget.FieldWidget(field, WysiwygWidget(request))
Property changes on: plone.z3cform/trunk/plone/z3cform/wysiwyg/widget.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/wysiwyg/wysiwyg_input.pt
===================================================================
--- plone.z3cform/trunk/plone/z3cform/wysiwyg/wysiwyg_input.pt (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/wysiwyg/wysiwyg_input.pt 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,24 @@
+<div lang="en"
+ xml:lang="en"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+
+ <tal:editor define="context nocall:view/context;
+ here nocall:context;
+ portal_url nocall:context/portal_url;
+ inputname view/name;
+ inputvalue view/value;
+ here_url context/absolute_url;
+ member context/portal_membership/getAuthenticatedMember;
+ editor python: member.getProperty('wysiwyg_editor','').lower();
+ support python: path('nocall:here/%s_wysiwyg_support|here/%s/wysiwyg_support|here/portal_skins/plone_wysiwyg/wysiwyg_support' % (editor, editor));
+ tabindex nothing">
+ <div metal:use-macro="context/wysiwyg_support/macros/wysiwygEditorBox">
+ The WYSIWYG code
+ </div>
+ </tal:editor>
+
+</div>
Property changes on: plone.z3cform/trunk/plone/z3cform/wysiwyg/wysiwyg_input.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/plone/z3cform/z2.py
===================================================================
--- plone.z3cform/trunk/plone/z3cform/z2.py (rev 0)
+++ plone.z3cform/trunk/plone/z3cform/z2.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,47 @@
+from zope import interface
+from zope.i18n.interfaces import IUserPreferredLanguages
+from zope.i18n.locales import locales, LoadLocaleError
+from Products.Five.browser import decode
+import z3c.form.interfaces
+
+class IFixedUpRequest(interface.Interface):
+ pass
+
+# XXX This is ripped from zope.publisher.http.HTTPRequest; we should
+# move this into Five
+def setup_locale(request):
+ envadapter = IUserPreferredLanguages(request, None)
+ if envadapter is None:
+ return None
+
+ langs = envadapter.getPreferredLanguages()
+ for httplang in langs:
+ parts = (httplang.split('-') + [None, None])[:3]
+ try:
+ return locales.getLocale(*parts)
+ except LoadLocaleError:
+ # Just try the next combination
+ pass
+ else:
+ # No combination gave us an existing locale, so use the default,
+ # which is guaranteed to exist
+ return locales.getLocale(None, None, None)
+
+# XXX Add a getURL method on the request object; we should move this
+# into Five
+def add_getURL(request):
+ def getURL(level=0, path_only=False):
+ assert level == 0 and path_only == False
+ return request['ACTUAL_URL']
+ request.getURL = getURL
+
+def switch_on(view, request_layer=z3c.form.interfaces.IFormLayer):
+ request = view.request
+ from zope.publisher.interfaces.browser import IBrowserApplicationRequest
+ if not IFixedUpRequest.providedBy(request) and \
+ not IBrowserApplicationRequest.providedBy(request):
+ interface.alsoProvides(request, IFixedUpRequest)
+ interface.alsoProvides(request, request_layer)
+ request.locale = setup_locale(request)
+ add_getURL(request)
+ decode.processInputs(request)
Property changes on: plone.z3cform/trunk/plone/z3cform/z2.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/setup.cfg
===================================================================
--- plone.z3cform/trunk/setup.cfg (rev 0)
+++ plone.z3cform/trunk/setup.cfg 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
Property changes on: plone.z3cform/trunk/setup.cfg
___________________________________________________________________
Name: svn:eol-style
+ native
Added: plone.z3cform/trunk/setup.py
===================================================================
--- plone.z3cform/trunk/setup.py (rev 0)
+++ plone.z3cform/trunk/setup.py 2008-07-13 21:54:24 UTC (rev 88331)
@@ -0,0 +1,44 @@
+from setuptools import setup, find_packages
+import os
+
+version = '0.3'
+
+
+def description():
+ join = lambda *paths: os.path.join('plone', 'z3cform', *paths)
+ return (open('README.txt').read() + '\n' +
+ open(join('wysiwyg', 'README.txt')).read() + '\n' +
+ open(join('queryselect', 'README.txt')).read() + '\n' +
+ open(join('crud', 'README.txt')).read() + '\n' +
+ open(os.path.join('docs', 'HISTORY.txt')).read() + '\n')
+
+setup(name='plone.z3cform',
+ version=version,
+ description="A library that allows use of z3c.form with Zope 2 (and Plone)",
+ long_description=description(),
+ # Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers
+ classifiers=[
+ "Framework :: Plone",
+ "Framework :: Zope2",
+ "Programming Language :: Python",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+ keywords='zope plone forms',
+ author='Daniel Nouri and contributors',
+ author_email='daniel.nouri at gmail.com',
+ url='http://pypi.python.org/pypi/plone.z3cform',
+ license='ZPL 2.1',
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['plone'],
+ include_package_data=True,
+ zip_safe=False,
+
+ # If the dependency to z3c.form gives you trouble within a Zope
+ # 2 environment, try the `fakezope2eggs` recipe
+ install_requires=[
+ 'setuptools',
+ 'z3c.form',
+ 'z3c.formwidget.query',
+ 'zope.i18n>=3.4'
+ ],
+ )
Property changes on: plone.z3cform/trunk/setup.py
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Checkins
mailing list