Metadata-Version: 1.0
Name: plone.z3cform
Version: 0.1
Summary: A library that allows use of z3c.form with Zope 2 and Plone
Home-page: http://pypi.python.org/pypi/plone.z3cform
Author: Daniel Nouri and contributors
Author-email: daniel.nouri@gmail.com
License: GPL
Description: =============
        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)
        ...
        ...     @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
        
        
        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
        
        
        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.)
        
        
        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.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.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.widgets.name'] = u'Daniel'
        >>> request.form['crud-add.widgets.age'] = 28
        >>> request.form['crud-add.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.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.widgets.name'] = u'Thomas'
        >>> request.form['crud-add.widgets.age'] = 28
        >>> request.form['crud-add.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.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.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.buttons.capitalize']
        >>> request.form['crud-edit.buttons.delete'] = u'Delete'
        >>> html = MyCustomForm(None, request)()
        >>> "Successfully deleted items" in html
        False
        >>> 'Thomas' in storage
        True
        
        Changelog
        =========
        
        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 plone forms
Platform: UNKNOWN
Classifier: Framework :: Plone
Classifier: Framework :: Zope2
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
