Metadata-Version: 1.0
Name: collective.z3cform.wizard
Version: 1.4.1
Summary: This is a library for creating multi-page wizards using z3c.form.  Values are stored in a session until the wizard is finished.
Home-page: http://svn.plone.org/svn/collective/collective.z3cform.wizard/trunk
Author: David Glick
Author-email: davidglick@groundwire.org
License: GPL
Description: Introduction
        ============
        
        This library implements a simple z3c.form-based wizard.  The wizard is composed
        of multiple steps.  Each step is a form.  Data is stored in a session until
        the user clicks the Finish button on the last step.
        
        In order to make good use of this library you'll need to be reasonably familiar
        with z3c.form first.  Here are some places to start:
        
         * Official documentation: http://docs.zope.org/z3c.form
         
         * Slides from Stephan Richter's tutorial at Plone Conference 2008:
           http://svn.zope.org/\*checkout\*/z3c.talk/trunk/Z3CForms/Z3CForms.html?rev=92118
         
        
        Wizard Step
        -----------
        
        A wizard step is a normal z3c.form form with a few additional features.
        
        By default, the content accessed by this form will be a dictionary
        within the wizard's session, with a key equal to the step's prefix.
        
        Additional attributes:
        
          wizard
            The wizard this step is being used in.
        
          available
            Boolean indicating whether the current step can be accessed via the
            wizard navigation links.  By default, only steps for which there is already
            data stored in the session can be accessed. (The next and previous steps
            can always be accessed via the respective buttons regardless of the value
            of this property.)
        
          completed
            Boolean indicating whether the user should be allowed to move on to the
            next step.  Defaults to True.  If False, the Continue button will be
            disabled.
        
        Additional methods:
        
          applyChanges(data)
            Saves changes from this step to its content (typically a PersistentDict
            in the wizard's session.)
        
          load(context):
            Loads the session data for this step based on a context.
        
          apply(context):
            Updates a context based on the session data for this step.
        
        
        Wizard Group Step
        -----------------
        
        Same as a Wizard Step; it just handles a list of groups just like a z3c.form
        GroupForm.
        
        Additional attributes:
        
          groups
            The list of groups you'd like to show up in the form as separate fieldsets
        
        
        Wizard
        ------
        
        The wizard is also a form, with a list of steps and built-in logic for
        moving between those steps.
        
        Class attributes.  Override these to affect how the wizard behaves:
        
          steps
            A sequence of step classes that will be instantiated when the wizard's
            update method is called.
        
          sessionKey
            Returns the unique session key used by this wizard instance. By default,
            this is a tuple of 'collective.z3cform.wizard' and the URL
            path to the wizard.
        
        Attributes set during the update method:
        
          activeSteps
            A sequence of wizard step instances.
        
          currentStep
            The wizard step instance currently being displayed.
        
          currentIndex
            The (0-based) index of the current step within the activeSteps sequence.
        
          session
            The session where data for this wizard is persisted.
        
          onFirstStep
            Boolean.  True if the first step of the wizard is being displayed.
        
          onLastStep
            Boolean.  True if the last step of the wizard is being displayed.
        
          allStepsFinished
            Boolean.  True if the 'available' attribute of each wizard step is True.
        
          finished
            Boolean.  True if the wizard has been completed.
        
          absolute_url
            The URL of the wizard.
        
        Methods:
        
          initialize()
            Called the first time a wizard is viewed in a given session.
              
            This method may be used to populate the session with data from some
            source.
              
            The default implementation calls the loadSteps method.
          
          loadSteps(context)
            Loads the wizard session data from a context.
              
            The default implementation calls the 'load' method of each wizard step.
          
          finish()
            Called when a wizard is successfully completed, after validation of the
            final step.
              
            Use this method to carry out some actions based on the values that have
            been filled out during completion of the wizard.
              
            The default implementation calls the applySteps method.
          
          applySteps(context)
            Updates a context based on the wizard session data.
              
            The default implementation calls the 'apply' method of each wizard step.
          
          sync()
            Mark the session as having changed, to ensure that changes get
            persisted.  This is required since we aren't using a
            persistence-aware dictionary class for our session variables.
        
        
        Compatibility
        =============
        
        This package has been tested in Zope 2.10 with Plone 3.3, and in Zope 2.12 with
        Plone 4.
        
        It should be pretty easy to get it to work in other environments supported by
        z3c.form, such as Zope 3, but I'll need someone familiar with those environments
        to tell me how sessions work there, for example.
        
        Credits
        =======
        
        This package is inspired by and based on the non-session-based z3c.form wizard
        included in the collective.singing package, which was implemented by Daniel
        Nouri.
        
        Session support, miscellaneous improvements, and repackaging by David Glick.
        
        Thanks also to Nathan van Gheem.
        
        Changelog
        =========
        
        1.4.1 (2011-05-04)
        ------------------
        
        * Add an AutoWizard for use with plone.autoform.
          [elro]
        
        * Add a Clear button that clears the session and goes back to step 1.
          [elro]
        
        * Reorder buttons so Finish and Continue both appear before Back.
          [elro]
        
        1.4 (2011-05-04)
        ----------------
        
        * Remove <hr />
          [elro]
        
        * Use Products.statusmessages.
          [elro]
        
        * Tweak wizard-buttons to conform to standard plone formControls.
          [elro]
        
        * Remove div.row from wizard-step.pt.
          [elro]
        
        1.3.3 (2011-03-22)
        ------------------
        
        * Normalize @@ view prefix when comparing URLs.
          [davisagli]
        
        1.3.2 (2010-07-27)
        ------------------
        
        * Remove stray debugging statement.
          [khink]
        
        1.3.1 (2010-06-28)
        ------------------
        
        * Avoid clobbering the session during plone.app.z3cform's inline validation.
          [davisagli]
        
        1.3 (2010-06-23)
        ----------------
        
        * Avoid errors when plone.app.z3cform's inline validation is installed.
          [davisagli]
        
        1.2 (2010-04-08)
        ----------------
        
        * Added a GroupStep for GroupForm-like integration.
          [vangheem]
        
        1.1 (2010-03-01)
        ----------------
        
        * Make sure that the Next button is the default if a step is submitted by
          pressing enter.
        
        1.0 (2010-01-19)
        ----------------
        
        * Include the form's enctype in the form tag.
        
        * Don't clear the session when traversing over the form to other things (such
          as a widget).
        
        1.0b2 (2009-06-25)
        ------------------
        
        * Moved the default wizard CSS to a browser resource which is available but
          not pulled in by anything by default.
        
        * Adjusted the criteria for visibility of the Finish button so that it shows up
          on any step as long as data is stored in the session for all steps.
          Previously it was only shown on the final step.
        
        * Added wizard navigation which lists the wizard's steps and links to ones
          that are available.
        
        * Added support in the Wizard class for jumping to a particular step based
          on an index passed in the request (but only if that step is available).
        
        * Adjusted the URL check that triggers session invalidation to not pay
          attention to the query string or fragment.
        
        * Changed the updateCurrentStep method of the Wizard class (not part of the
          public API) to take a single parameter, the target step index.
        
        * Added 'allStepsFinished' property to the Wizard class.
        
        * Added 'available' property to the Step class.
        
        * Added 'absolute_url' property to the Wizard class.
        
        * Reset the wizard session if you leave it before finishing.
        
        
        1.0b1 (2009-05-12)
        ------------------
        
        * Initial release
        
        Example and tests
        =================
        
        Define a wizard with three steps
        --------------------------------
        
        To define a form that uses the wizard, we'll need to define steps.
        These steps represent individual forms that are processed
        sequentially.  Only when the last step is completed will the data be
        submitted through a user-defined method.
        
          >>> from zope import schema
          >>> from z3c.form import field, form
          >>> from collective.z3cform.wizard import wizard
          >>> from plone.z3cform.fieldsets import group
          >>> from Products.statusmessages.interfaces import IStatusMessage
          >>> from Products.statusmessages.adapter import _decodeCookieValue
        
          >>> class StepOne(wizard.Step):
          ...     prefix = 'one'
          ...     fields = field.Fields(
          ...         schema.Int(__name__='age', title=u"Age"))
        
        By default, the steps will get/set values in the session.  If we want to
        initialize these values or do something with them once the wizard is completed,
        we need to implement the load and apply methods for our step.
        
          >>> from pprint import pprint
          >>> class StepTwo(wizard.Step):
          ...     prefix = 'two'
          ...     fields = field.Fields(
          ...         schema.TextLine(__name__='name', title=u"Name", required=True))
          ...         
          ...     def load(self, context):
          ...         data = self.getContent()
          ...         data['name'] = 'David'
          ...         
          ...     def apply(self, context):
          ...         data = self.getContent()
          ...         pprint('Name from step 2: %s' % data['name'])
        
        We can also do group steps
        
          >>> class AddressGroup(group.Group):
          ...   fields = field.Fields(
          ...     schema.TextLine(__name__='address', title=u'Address', required=False),
          ...     schema.TextLine(__name__='city', title=u'City', required=False),
          ...     schema.TextLine(__name__='state', title=u'State', required=False))
          ...   label = u"Address Information"
          ...   prefix = 'address'
        
          >>> class StepThree(wizard.GroupStep):
          ...   prefix = 'three'
          ...   fields = field.Fields()
          ...   groups = [AddressGroup]
        
        
        We can now define our minimal wizard:
        
          >>> class Wizard(wizard.Wizard):
          ...     label = u"My silly wizard"
          ...     steps = StepOne, StepTwo, StepThree
        
        Render the form
        ---------------
        
        Let's render the form for the first time now:
        
          >>> request = TestRequest()
          >>> wizard = Wizard(None, request)
          >>> print wizard()
          <...
          <div class="form" id="wizard-step-one">
            <form action="http://127.0.0.1" method="post"
                  class="rowlike enableUnloadProtection kssattr-formname-127.0.0.1"
                  enctype="multipart/form-data">
                <p class="discreet"></p>
                <div class="field">
                  <label for="one-widgets-age">
                    <span>Age</span>
                  </label>...
                  <span class="fieldRequired"
                        title="Required">
                    (Required)
                  </span>
                  <div class="widget">
                    <input id="one-widgets-age" name="one.widgets.age"
                           class="text-widget required int-field" value=""
                           type="text" />
                  </div>
                </div>
            <div class="formControls wizard-buttons">
                <input id="form-buttons-continue"
                       name="form.buttons.continue"
                       class="submit-widget button-field" value="Continue"
                       type="submit" />
                <input id="form-buttons-clear"
                       name="form.buttons.clear"
                       class="submit-widget button-field" value="Clear"
                       type="submit" />
            </div>
            </form>
          </div>
        
        
        Submit with an error
        --------------------
        
        Remember that our first step requires the age.
        
          >>> request.form = {
          ...     'form.buttons.continue': u'Continue',
          ... }
          >>> wizard = Wizard(None, request)
        
          >>> print wizard()
          <...
          ...Required input is missing...
        
          >>> messages = _decodeCookieValue(request.__annotations__.pop('statusmessages'))
          >>> [(m.message, m.type) for m in messages]
          [(u'There were errors.', u'error')]
        
        
        Submit the first step successfully
        ----------------------------------
        
          >>> request.form['one.widgets.age'] = u'27'
          >>> wizard = Wizard(None, request)
          >>> print wizard()
          <...
          <div class="form" id="wizard-step-two">
            <form action="http://127.0.0.1" method="post"
                  class="rowlike enableUnloadProtection kssattr-formname-127.0.0.1"
                  enctype="multipart/form-data">
                <p class="discreet"></p>
                <div class="field">
                  <label for="two-widgets-name">
                    <span>Name</span>
                  </label>
                  <span class="fieldRequired"
                        title="Required">
                    (Required)
                  </span>
                  <div class="widget">
                    <input id="two-widgets-name" name="two.widgets.name"
                           class="text-widget required textline-field"
                           value="David" type="text" />
                  </div>  
                </div>
              <div class="formControls wizard-buttons">
                <input id="form-buttons-continue" name="form.buttons.continue"
                       class="submit-widget button-field" value="Continue"
                       type="submit" />
                <input id="form-buttons-back" name="form.buttons.back"
                       class="submit-widget button-field" value="Back"
                       type="submit" />
                <input id="form-buttons-clear"
                       name="form.buttons.clear"
                       class="submit-widget button-field" value="Clear"
                       type="submit" />
              </div>
            </form>
          </div>
        
        Submitting step two
        -------------------
        
        Step two works similarly:
        
          >>> request.form['two.widgets.name'] = u'David'
          >>> wizard = Wizard(None, request)
          >>> html = wizard()
          >>> 'three' in html, 'Address' in html, 'City' in html, 'State' in html, 'Finish' in html
          (True, True, True, True, True)
        
        
        Step Three: Slaying the dragon
        ------------------------------
        
        Now let's press the Finish button.  We expect this to print out the value
        from step 2, thanks to the 'apply' method we implemented for that step.
        
        Remembering that in our wizard, we implemented ``finish`` to print out
        the data that it receives.  Here's the finishing move:
        
          >>> request.form['form.buttons.finish'] = u'Finish'
          >>> wizard = Wizard(None, request)
          >>> html = wizard()
          'Name from step 2: David'
        
          >>> messages = _decodeCookieValue(request.__annotations__.pop('statusmessages'))
          >>> [(m.message, m.type) for m in messages]
          [(u'Information submitted successfully.', u'info')]
        
        
        Example
        -------
        
        See the `collective.megaphone`_ package for an example of this library in use.
        
        .. _`collective.megaphone`: http://plone.org/products/megaphone
        
        
        AutoWizard
        ----------
        
        An AutoWizard creates steps out of plone.autoform fieldsets (including those
        in a plone.supermodel xml schema).
        
        First we define our schema:
        
          >>> from plone.supermodel.interfaces import FIELDSETS_KEY
          >>> from plone.supermodel.model import Fieldset
          >>> from zope.interface import Interface, taggedValue
          >>> class IMySchema(Interface):
          ...     age = schema.Int(title=u"Age")
          ...     name = schema.Int(title=u"Name")
          ...     taggedValue(FIELDSETS_KEY, [
          ...         Fieldset('one', label=u"One from fieldset", fields=['age']),
          ...         Fieldset('two', fields=['name']),
          ...         ])
        
        Then create the AutoWizard class:
        
          >>> from collective.z3cform.wizard import autowizard
          >>> class AutoWizard(autowizard.AutoWizard):
          ...     label = u"Automatically silly wizard."
          ...     schema = IMySchema
        
        
        We can now render the form:
        
          >>> request = TestRequest()
          >>> wizard = AutoWizard(None, request)
          >>> print wizard()
          <...
          <div class="form" id="wizard-step-form-one">
            <form action="http://127.0.0.1" method="post"
                  class="rowlike enableUnloadProtection kssattr-formname-127.0.0.1"
                  enctype="multipart/form-data">
                <h2>One from fieldset</h2>
                <p class="discreet"></p>
                <div class="field">
                  <label for="form-one-widgets-age">
                    <span>Age</span>
                  </label>...
                  <span class="fieldRequired"
                        title="Required">
                    (Required)
                  </span>
                  <div class="widget">
                    <input id="form-one-widgets-age" name="form.one.widgets.age"
                           class="text-widget required int-field" value=""
                           type="text" />
                  </div>
                </div>
            <div class="formControls wizard-buttons">
                <input id="form-buttons-continue"
                       name="form.buttons.continue"
                       class="submit-widget button-field" value="Continue"
                       type="submit" />
            </div>
            </form>
          </div>
        
        Otherwise it works in exactly the same way as the standard Wizard.
        
Keywords: z3c.form wizard session
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Zope2
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
