Metadata-Version: 1.0
Name: plone.z3cform
Version: 0.5.7
Summary: plone.z3cform is a library that allows use of z3c.form with Zope 2 and the CMF.
Home-page: http://pypi.python.org/pypi/plone.z3cform
Author: Daniel Nouri and contributors
Author-email: daniel.nouri@gmail.com
License: ZPL 2.1
Description: =============
        plone.z3cform
        =============
        
        plone.z3cform is a library that allows use of `z3c.form`_ with Zope 2
        and the CMF_.
        
        .. _z3c.form: http://pypi.python.org/pypi/z3c.form
        .. _CMF: http://www.zope.org/Products/CMF
        
        
        Quick start
        ===========
        
        A quick example:
        
        >>> from zope import interface, schema
        >>> from z3c.form import form, field, button
        >>> from plone.z3cform.layout import wrap_form
        
        >>> class MySchema(interface.Interface):
        ...     age = schema.Int(title=u"Age")
        
        >>> class MyForm(form.Form):
        ...     fields = field.Fields(MySchema)
        ...     ignoreContext = True # don't use context to get widget data
        ...     label = u"Please enter your age"
        ...
        ...     @button.buttonAndHandler(u'Apply')
        ...     def handleApply(self, action):
        ...         data, errors = self.extractData()
        ...         print data['age'] # ... or do stuff
        
        >>> MyView = wrap_form(MyForm)
        
        Then, register ``MyView`` as a ``browser:page``.
        
        The ``wrap_form`` function returns a browser view that embeds your
        form in a CMF layout template.  See the ``layout`` module for details.
        
        For more examples, please refer to the `z3c.form docs`_ and to `this
        how-to`_.
        
        
        .. _z3c.form docs: http://docs.carduner.net/z3c.form
        .. _this how-to: http://plone.org/documentation/how-to/easy-forms-with-plone3
        
        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'] = u'55'
        >>> request.form['crud-edit.Peter.widgets.name'] = u'Franz'
        >>> request.form['crud-edit.Peter.widgets.age'] = u'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'] = u'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'] = u'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'] = u'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
        []
        
        What if we try to add "Daniel" twice?  Our current implementation of
        the add form will simply overwrite the data:
        
        >>> save_daniel = storage['Daniel']
        >>> html = MyForm(None, request)()
        >>> "Item added successfully" in html
        True
        >>> save_daniel is storage['Daniel']
        False
        >>> log.pop().object is storage['Daniel']
        True
        
        Let's implement a class that prevents this:
        
        >>> class MyCarefulForm(MyForm):
        ...     def add(self, data):
        ...         name = data['name']
        ...         if name not in storage:
        ...             return super(MyCarefulForm, self).add(data)
        ...         else:
        ...             raise schema.ValidationError(
        ...                 u"There's already an item with the name '%s'" % name)
        
        >>> save_daniel = storage['Daniel']
        >>> html = MyCarefulForm(None, request)()
        >>> "Item added successfully" in html
        False
        >>> "There's already an item with the name 'Daniel'" in html
        True
        >>> save_daniel is storage['Daniel']
        True
        >>> len(log) == 0
        True
        
        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'] = u'40'
        >>> request.form['crud-edit.Daniel.widgets.age'] = u'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'] = u'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] = unicode(storage[name].name)
        ...     request.form['crud-edit.%s.widgets.age' % name] = unicode(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
        
        Customizing sub forms
        ---------------------
        
        The EditForm class allows you to specify an editsubform_factory-a classs
        inherits from EditSubForm.  This allows you to say, override the crud-row.pt
        page template and customize the look of the fields.
        
        >>> import zope.schema
        >>> class MyCustomEditSubForm(crud.EditSubForm):
        ...
        ...     def _select_field(self):
        ...         """I want to customize the field that it comes with..."""
        ...         select_field = field.Field(
        ...         zope.schema.TextLine(__name__='select',
        ...                              required=False,
        ...                              title=u'select'))
        ...         return select_field
        
        >>> class MyCustomEditForm(MyEditForm):
        ...     editsubform_factory = MyCustomEditSubForm
        
        >>> class MyCustomFormWithCustomSubForm(MyCustomForm):
        ...     editform_factory = MyCustomEditForm
        
        >>> request = TestRequest()
        >>> html = MyCustomFormWithCustomSubForm(None, TestRequest())()
        
        Still uses same form as before
        >>> "Delete" in html, "Apply changes" in html, "Capitalize" in html
        (False, False, True)
        
        Just changes the widget used for selecting...
        >>> 'type="checkbox"' in html
        False
        
        Using batching
        --------------
        
        The CrudForm base class supports batching.  When setting the
        ``batch_size`` attribute to a value greater than ``0``, we'll only get
        as many items displayed per page.
        
        >>> class MyBatchingForm(MyForm):
        ...     batch_size = 2
        >>> request = TestRequest()
        >>> html = MyBatchingForm(None, request)()
        >>> "Daniel" in html, "Maria" in html
        (True, True)
        >>> "THOMAS" in html
        False
        
        >>> request.form['crud-edit.form.page'] = '1'
        >>> html = MyBatchingForm(None, request)()
        >>> "Daniel" in html, "Maria" in html
        (False, False)
        >>> "THOMAS" in html
        True
        
        Let's change Thomas' age on the second page:
        
        >>> request.form['crud-edit.Thomas.widgets.name'] = u'Thomas'
        >>> request.form['crud-edit.Thomas.widgets.age'] = '911'
        >>> request.form['crud-edit.form.buttons.edit'] = u'Apply changes'
        >>> html = MyBatchingForm(None, request)()
        >>> "Successfully updated" in html
        True
        >>> "911" in html
        True
        
        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']
        
        Changelog
        =========
        
        0.5.7 - 2009-11-17
        ------------------
        
        * Fix silly doctests so that they don't break in Python 2.6 / Zope 2.12
        [optilude]
        
        0.5.6 - 2009-09-25
        ------------------
        
        * Added title_required msgid in macros.pt to be the same as plone.app.z3cform
        because macros.pt from plone.app.z3cform uses plone.z3cform translations.
        Added French translation and fixed German and Dutch translations
        for label_required and title_required messages.
        [vincentfretin]
        
        0.5.5 - 2009-07-26
        ------------------
        
        * Removed explicit <includeOverrides /> call from configure.zcml. This causes
        race condition type errors in ZCML loading when overrides are included
        later.
        [optilude]
        
        0.5.4 - 2009-04-17
        ------------------
        
        * Added monkey patch to fix a bug in z3c.form's ChoiceTerms on z3c.form 1.9.0.
        [optilude]
        
        * Fix obvious bugs and dodgy naming in SingleCheckBoxWidget.
        [optilude]
        
        * Use chameleon-based page templates from five.pt if available.
        [davisagli]
        
        * Copied the basic textlines widget from z3c.form trunk for use until
        it is released.
        [davisagli]
        
        0.5.3 - 2008-12-09
        ------------------
        
        * Add translation marker for batch, update translation files.
        [thefunny42]
        
        * Handle changed signature for widget extract method in z3c.form > 1.9.0
        [davisagli]
        
        * Added wildcard support to the 'before' and 'after' parameters of the
        fieldset 'move' utility function.
        [davisagli]
        
        * Fixes for Zope 2.12 compatibility.
        [davisagli]
        
        * Don't display an 'Apply changes' button if you don't define an
        update_schema.
        [thefunny42]
        
        * Declare xmlnamespace into 'layout.pt' and 'subform.pt' templates
        
        * Added support for an editsubform_factory for an EditForm so you can
        override the default behavior for a sub form now.
        
        * Changed css in crud-table.pt for a table to "listing" so that tables
        now look like plone tables.
        
        * Copy translation files to an english folder, so if your browser
        negociate to ``en,nl``, you will get english translations instead of
        dutch ones (like expected).
        [thefunny42]
        
        * Send an event IAfterWidgetUpdateEvent after updating display widgets
        manually in a CRUD form.
        [thefunny42]
        
        0.5.2 - 2008-08-28
        ------------------
        
        * Add a namespace traversal adapter that allows traversal to widgets. This
        is useful for AJAX calls, for example.
        
        0.5.1 - 2008-08-21
        ------------------
        
        * Add batching to ``plone.z3cform.crud`` CrudForm.
        
        * Look up the layout template as an IPageTemplate adapter. This means that
        it is possible for Plone to provide a "Ploneish" default template for forms
        that don't opt into this, without those forms having a direct Plone
        dependency.
        
        * Default to the titleless form template, since the layout template will
        provide a title anyway.
        
        * In ``plone.z3cform.layout``, allow labels to be defined per form
        instance, and not only per form class.
        
        0.5.0 - 2008-07-30
        ------------------
        
        * No longer depend on <3.5 of zope.component.
        
        0.4 - 2008-07-25
        ----------------
        
        * Depend on zope.component<3.5 to avoid ``TypeError("Missing
        'provides' attribute")`` error.
        
        * Allow ICrudForm.add to raise ValidationError, which allows for
        displaying a user-friendly error message.
        
        * Make the default layout template CMFDefault- compatible.
        
        0.3 - 2008-07-24
        ----------------
        
        * Moved Plone layout wrapper to ``plone.app.z3cform.layout``.  If you
        were using ``plone.z3cform.base.FormWrapper`` to get the Plone
        layout before, you'll have to use
        ``plone.app.z3cform.layout.FormWrapper`` instead now.  (Also, make
        sure you include plone.app.z3cform's ZCML in this case.)
        
        * Move out Plone-specific subpackages to ``plone.app.z3cform``.  These
        are:
        
        - wysywig: Kupu/Plone integration
        
        - queryselect: use z3c.formwidget.query with Archetypes
        
        Clean up testing code and development ``buildout.cfg`` to not pull
        in Plone anymore.
        [nouri]
        
        * Relicensed under the ZPL 2.1 and moved into the Zope repository.
        [nouri]
        
        * 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]
        
        
Keywords: zope cmf form widget
Platform: UNKNOWN
Classifier: Framework :: Plone
Classifier: Framework :: Zope2
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
