KSS inline validation
=====================

First, let's set up KSS debug mode:

    >>> from zope.interface import alsoProvides
    >>> from Testing.ZopeTestCase import ZopeLite
    >>> from Testing.makerequest import makerequest
    >>> from kss.core.tests.base import IDebugRequest
    >>> from zope.annotation.interfaces import IAttributeAnnotatable

    >>> app = ZopeLite.app()
    >>> def make_request(form={}, lang='en'):
    ...     request = makerequest(app, environ = {'HTTP_ACCEPT_LANGUAGE': lang}).REQUEST
    ...     request.form.update(form)
    ...     alsoProvides(request, IDebugRequest)
    ...     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.app.z3cform.layout import FormWrapper

    >>> 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
    ...
    ...     @button.buttonAndHandler(u'Apply')
    ...     def handleApply(self, action):
    ...         data, errors = self.extractData()
    ...         print data['age'] # ... or do stuff

    >>> class MyFormWrapper(FormWrapper):
    ...     form = MyForm
    ...     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
    >>> from zope.interface import Interface, implements
    >>> from Acquisition import Implicit
    >>> class Bar(Implicit):
    ...     implements(Interface)
    ...     def restrictedTraverse(self, name):
    ...         # fake traversal to the form
    ...         if name.startswith('@@'):
    ...             return getMultiAdapter((self, self._REQUEST), Interface, name[2:]).__of__(self)
    ...         else:
    ...             return getattr(self, name)
    ...         
    >>> context = Bar()
    >>> request = make_request()
    >>> context._REQUEST = request # evil test fake
    >>> formWrapper = getMultiAdapter((context, request), name=u"test-form")
    >>> formWrapper
    <Products.Five.metaclass.MyFormWrapper object ...>
    >>> formWrapper.form
    <class 'plone.app.z3cform.tests.example.MyForm'>

    >>> del context, request

Inline validation
-----------------

Inline validation is invoked via the @@kss_z3cform_inline_validation view.

    >>> context = Bar()
    >>> request = make_request(form={'form.widgets.age': 'Title'})
    >>> context._REQUEST = request
    >>> view = getMultiAdapter((context, request), name=u"kss_z3cform_inline_validation")

This is wired up with KSS. When the user leaves a form control with inline
validation enabled, it will be called with the following parameters:

    >>> view.validate_input(formname=u'test-form', fieldname=u'form.widgets.age', value='Title')
    [{'selectorType': 'css', 'params': {}, 'name': 'clearChildNodes', 'selector': u'#formfield-form-widgets-age div.fieldErrorBox'},
     {'selectorType': 'css',
      'params': {'value': u'error warning'},
      'name': 'addClass',
      'selector': u'#formfield-form-widgets-age'}]

    >>> request = make_request(form={'form.widgets.age': '20'})
    >>> context._REQUEST = request
    >>> view = getMultiAdapter((context, request), name=u"kss_z3cform_inline_validation")
    >>> view.validate_input(formname=u'test-form', fieldname=u'form.widgets.age', value='20')
    [{'selectorType': 'css', 'params': {}, 'name': 'clearChildNodes', 'selector': u'#formfield-form-widgets-age div.fieldErrorBox'},
     {'selectorType': 'css', 'params': {'value': u'error'}, 'name': 'removeClass', 'selector': u'#formfield-form-widgets-age'},
     {'selectorType': 'css', 'params': {'value': u'warning'}, 'name': 'removeClass', 'selector': u'#formfield-form-widgets-age'},
     {'selectorType': 'css', 'params': {'name': u'display', 'value': u'none'}, 'name': 'setStyle', 'selector': '.portalMessage'},
     {'selectorType': 'htmlid', 'params': {'html': u'<![CDATA[<dt>Info</dt><dd></dd>]]>', 'withKssSetup': u'True'},
      'name': 'replaceInnerHTML', 'selector': 'kssPortalMessage'},
     {'selectorType': 'htmlid', 'params': {'name': u'class', 'value': u'portalMessage info'},
      'name': 'setAttribute', 'selector': 'kssPortalMessage'},
     {'selectorType': 'htmlid', 'params': {'name': u'display', 'value': u'none'}, 'name': 'setStyle', 'selector': 'kssPortalMessage'}]

Inline validation with groups
-----------------------------

We use plone.app.z3cform.tests.example.MyGroupFormWrapper and validate the 
field 'name' that's part of a group. Inline validation is invoked via the 
@@kss_z3cform_inline_validation view.

    >>> request = make_request(form={'form.widgets.name': ''})
    >>> context._REQUEST = request
    >>> view = getMultiAdapter((context, request), name=u"kss_z3cform_inline_validation")

The validation view takes an Attribute fieldset with the index of the group.

    >>> view.validate_input(formname=u'test-group-form', fieldname=u'form.widgets.name', fieldset="0", value='')
    [{'selectorType': 'css', 'params': {}, 'name': 'clearChildNodes', 'selector': u'#fieldset-0 #formfield-form-widgets-name div.fieldErrorBox'},
     {'selectorType': 'css',
      'params': {'value': u'error warning'},
      'name': 'addClass',
      'selector': u'#fieldset-0 #formfield-form-widgets-name'}]

    >>> request = make_request(form={'form.widgets.name': u'Name'})
    >>> context._REQUEST = request
    >>> view = getMultiAdapter((context, request), name=u"kss_z3cform_inline_validation")
    >>> view.validate_input(formname=u'test-group-form', fieldname=u'form.widgets.name', fieldset="0", value=u'Name')
    [{'selectorType': 'css', 'params': {}, 'name': 'clearChildNodes', 'selector': u'#fieldset-0 #formfield-form-widgets-name div.fieldErrorBox'},
     {'selectorType': 'css', 'params': {'value': u'error'}, 'name': 'removeClass', 'selector': u'#fieldset-0 #formfield-form-widgets-name'},
     {'selectorType': 'css', 'params': {'value': u'warning'}, 'name': 'removeClass', 'selector': u'#fieldset-0 #formfield-form-widgets-name'},
     {'selectorType': 'css', 'params': {'name': u'display', 'value': u'none'}, 'name': 'setStyle', 'selector': '.portalMessage'},
     {'selectorType': 'htmlid', 'params': {'html': u'<![CDATA[<dt>Info</dt><dd></dd>]]>', 'withKssSetup': u'True'},
      'name': 'replaceInnerHTML', 'selector': 'kssPortalMessage'},
     {'selectorType': 'htmlid', 'params': {'name': u'class', 'value': u'portalMessage info'},
      'name': 'setAttribute', 'selector': 'kssPortalMessage'},
     {'selectorType': 'htmlid', 'params': {'name': u'display', 'value': u'none'}, 'name': 'setStyle', 'selector': 'kssPortalMessage'}]


Inline-Validation and Translation of ErrorSnippets
--------------------------------------------------

We use plone.app.z3cform.tests.example.MyGroupFormWrapper and validate the 
field 'name' that's part of a group. Inline validation is invoked via the 
@@kss_z3cform_inline_validation view.

    >>> request = make_request(form={'form.widgets.name': ''}, lang='de',)
    >>> context._REQUEST = request
    >>> view = getMultiAdapter((context, request), name=u"kss_z3cform_inline_validation")

The validation view takes an Attribute fieldset with the index of the group.
The error is only shown when warning_only is explicitly switched off (matching
the behavior of archetypes.)

    >>> view.validate_input(formname=u'test-group-form', fieldname=u'form.widgets.name', fieldset="0", value='', warning_only=False)
    [{'selectorType': 'css', 'params': {'html': u'<![CDATA[Erforderliche Eingabe fehlt.]]>', 'withKssSetup': u'True'},
      'name': 'replaceInnerHTML',
      'selector': u'#fieldset-0 #formfield-form-widgets-name div.fieldErrorBox'},
     {'selectorType': 'css',
      'params': {'value': u'error'},
      'name': 'addClass',
      'selector': u'#fieldset-0 #formfield-form-widgets-name'}]


Forms embedded inside normal views
-----------------------------------

It's possible to embed z3c.form Forms inside a normal BrowserView via viewlets,
portlets or tiles.

Currently the name of the form to be validated is gotten from the URL. For embedded
forms this can't work since the URL only has the containing view's name.

Until a lasting solution is found, we just make sure that validation
doesn't raise an exception if it receives a normal browerview as the supposed
form.

    >>> from zope.publisher.browser import BrowserView
    >>> class MyNormalView(BrowserView):
    ...     """ """

    >>> provideAdapter(adapts=(Interface, IBrowserRequest),
    ...                provides=Interface,
    ...                factory=MyNormalView,
    ...                name=u"my-view")

Let's verify that it gets called...

    >>> context = Bar()
    >>> request = make_request()
    >>> view = getMultiAdapter((context, request), name=u"my-view")
    >>> view
    <MyNormalView object ...>

Inline validation is invoked via the @@kss_z3cform_inline_validation view. But
in this case no validation output should be returned.

    >>> context = Bar()
    >>> request = make_request(form={'form.widgets.age': 'Title'})
    >>> view = getMultiAdapter((context, request), name=u"kss_z3cform_inline_validation")
    >>> view.validate_input(formname=u'my-view', fieldname=u'form.widgets.age', value='Title')
    []

