[Checkins] SVN: z3c.formjs/trunk/s I needed to do some changes to get the JS Validator demo working.

Stephan Richter srichter at cosmos.phy.tufts.edu
Thu Jul 5 12:41:06 EDT 2007


Log message for revision 77473:
  I needed to do some changes to get the JS Validator demo working.
  

Changed:
  U   z3c.formjs/trunk/setup.py
  U   z3c.formjs/trunk/src/z3c/formjs/interfaces.py
  A   z3c.formjs/trunk/src/z3c/formjs/jsvalidator.py
  A   z3c.formjs/trunk/src/z3c/formjs/jsvalidator.txt

-=-
Modified: z3c.formjs/trunk/setup.py
===================================================================
--- z3c.formjs/trunk/setup.py	2007-07-05 16:40:24 UTC (rev 77472)
+++ z3c.formjs/trunk/setup.py	2007-07-05 16:41:06 UTC (rev 77473)
@@ -71,6 +71,7 @@
         'setuptools',
         'z3c.form',
         'z3c.formui',
+	'z3c.traverser',
         'zope.app.pagetemplate',
         'zope.component',
         'zope.interface',

Modified: z3c.formjs/trunk/src/z3c/formjs/interfaces.py
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/interfaces.py	2007-07-05 16:40:24 UTC (rev 77472)
+++ z3c.formjs/trunk/src/z3c/formjs/interfaces.py	2007-07-05 16:41:06 UTC (rev 77473)
@@ -124,3 +124,24 @@
 
     def update():
         """Setup actions."""
+
+
+class IAJAXValidator(Interface):
+    """A validator that sends back validation data sent from an ajax request."""
+
+    ValidationRenderer = schema.Object(
+                    schema=Interface,
+                    title=u"Validation Renderer")
+
+    def validate():
+        """return validation data."""
+
+
+class IJSMessageValidationRenderer(Interface):
+    """renders a js expression for sending/processing ajax validation requests."""
+
+    def __init__(form, field, request):
+        """store the form field and request, because this adapts those items."""
+
+    def render():
+        """Render the js expression."""

Copied: z3c.formjs/trunk/src/z3c/formjs/jsvalidator.py (from rev 77470, Sandbox/pcardune/z3cFormJS/trunk/src/z3c/formjs/jsvalidator.py)
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsvalidator.py	                        (rev 0)
+++ z3c.formjs/trunk/src/z3c/formjs/jsvalidator.py	2007-07-05 16:41:06 UTC (rev 77473)
@@ -0,0 +1,110 @@
+import zope.interface
+import zope.component
+
+from z3c.traverser.traverser import SingleAttributeTraverserPlugin
+from z3c.traverser.interfaces import IPluggableTraverser, ITraverserPlugin
+from z3c.form.interfaces import IWidget, IField
+
+from jquery.layer import IJQueryJavaScriptBrowserLayer
+
+from z3c.formjs import interfaces
+
+
+## @zope.component.adapter(IWidget, IJQueryJavaScriptBrowserLayer)
+## @zope.interface.implementer(interfaces.IJSErrorMessageRenderer)
+## def JQueryErrorMessageRenderer(widgetID):
+##     return '''$.get()'''
+
+
+class JQueryBaseValidationRenderer(object):
+
+    def __init__(self, form, widgetID, request):
+        self.form = form
+        self.widgetID = widgetID
+        self.request = request
+
+    def _ajaxURL(self):
+        # build js expression for extracting widget value
+        # XXX: Maybe we should adapt the widget to IJSValueExtractorRenderer?
+        valueString = '$("#%s").val()' % self.widgetID
+
+        # build a js expression that joins valueString expression
+        queryString = '"?widget-id=%s&%s=" + %s' % (self.widgetID, self.widgetID.replace('-','.'), valueString)
+
+        # build a js expression that joins form url, validate path, and query string
+        ajaxURL = '"'+self.form.request.getURL() + '/validate" + ' + queryString
+
+        # it should look something like this now:
+        # "path/to/form.html/validate" + "?widget-id=some-id&value=" + $("#some-id").val()
+        return ajaxURL
+
+
+class JQueryMessageValidationRenderer(JQueryBaseValidationRenderer):
+
+    zope.interface.implements(interfaces.IJSMessageValidationRenderer)
+    zope.component.adapts(interfaces.IAJAXValidator,
+                          zope.interface.Interface,
+                          IJQueryJavaScriptBrowserLayer)
+
+    def render(self):
+        ajaxURL = self._ajaxURL()
+        # build a js expression that shows the user the error message
+        # XXX: later this should query for a renderer based on the widget
+        #     jsrenderer = zope.component.queryMultiAdapter(
+        #         (widget, self.request), interfaces.IJSErrorMessageRenderer)
+        #     messageSetter = jsrenderer.render()
+        messageSetter = 'alert(data);'
+        ajax = '$.get(%s,\nfunction(data){\n%s\n})' % (ajaxURL, messageSetter)
+        return ajax
+
+
+class MessageValidationRenderer(object):
+    """An intermediate class that performs adapter look ups.
+
+    This way you don't have to do as many adapter look ups in your Form class.
+    """
+
+    def __init__(self, form, field):
+        self.form = form
+        self.field = field
+
+    def render(self):
+        jsrenderer = zope.component.queryMultiAdapter(
+            (self.form, self.field, self.form.request), interfaces.IJSMessageValidationRenderer)
+        return jsrenderer.render()
+
+
+class BaseValidator(object):
+    zope.interface.implements(interfaces.IAJAXValidator,
+                              IPluggableTraverser)
+
+    ValidationRenderer = None
+
+    def _validate(self):
+        widgetID = self.request.get('widget-id')
+        fieldName = widgetID.replace('form-widgets-','')
+        self.fields = self.fields.select(fieldName)
+        self.updateWidgets()
+        return self.widgets.extract()
+
+    def publishTraverse(self, request, name):
+        # 1. Look at all the traverser plugins, whether they have an answer.
+        for traverser in zope.component.subscribers((self, request),
+                                     ITraverserPlugin):
+            try:
+                return traverser.publishTraverse(request, name)
+            except NotFound:
+                pass
+
+
+class MessageValidator(BaseValidator):
+    '''Validator that sends error messages for widget in questiodn.'''
+    ValidationRenderer = MessageValidationRenderer
+
+    def validate(self):
+        data, errors = self._validate()
+        if errors:
+            return errors[0].message
+        return u'' # all OK
+
+ValidateTraverser = SingleAttributeTraverserPlugin('validate')

Copied: z3c.formjs/trunk/src/z3c/formjs/jsvalidator.txt (from rev 77470, Sandbox/pcardune/z3cFormJS/trunk/src/z3c/formjs/jsvalidator.txt)
===================================================================
--- z3c.formjs/trunk/src/z3c/formjs/jsvalidator.txt	                        (rev 0)
+++ z3c.formjs/trunk/src/z3c/formjs/jsvalidator.txt	2007-07-05 16:41:06 UTC (rev 77473)
@@ -0,0 +1,63 @@
+==========================
+JavaScript Form Validation
+==========================
+
+Server-side validation via AJAX
+
+Message Validator
+-----------------
+
+This validator returns an error message for a given widget.
+
+    >>> from z3c.formjs import interfaces as jsinterfaces
+    >>> from z3c.formjs import jsvalidator, jsevent
+    >>> from z3c.form import form, field, interfaces
+
+    >>> from z3c.form.testing import setupFormDefaults
+    >>> setupFormDefaults()
+
+    >>> import zope.interface
+    >>> import zope.schema
+    >>> class IAddress(zope.interface.Interface):
+    ...     zip = zope.schema.Int(title=u"Zip Code")
+
+
+    >>> class AddressEditForm(jsvalidator.MessageValidator, form.AddForm):
+    ...     fields = field.Fields(IAddress)
+    ...
+    ...     @jsevent.handler(interfaces.IField, event=jsevent.CHANGE)
+    ...     def fieldValidator(self, field):
+    ...         return self.ValidationRenderer(self, field).render()
+
+    >>> from z3c.formjs.testing import TestRequest
+    >>> request = TestRequest()
+    >>> edit = AddressEditForm(None, request)
+    >>> edit.update()
+
+We will register a jquery renderer.
+
+    >>> import zope.component
+    >>> zope.component.provideAdapter(jsvalidator.JQueryMessageValidationRenderer)
+    >>> print edit.fieldValidator(edit, edit.fields['zip'])
+    $.get("http://127.0.0.1/validate" + "?widget-id=form-widgets-zip&value=" + $("#form-widgets-zip").val(),
+    function(data){
+    alert(data);
+    })
+
+    >>> from zope.publisher.interfaces import IPublisherRequest
+    >>> from z3c.traverser import traverser
+    >>> zope.component.provideSubscriptionAdapter(traverser.AttributeTraverserPlugin,
+    ...                                           (jsinterfaces.IAJAXValidator, IPublisherRequest))
+    >>> from z3c.traverser.traverser import PluggableTraverser
+    >>> request = TestRequest(form={'widget-id':'form-widgets-zip',
+    ...                             'form.widgets.zip':'29132'})
+    >>> edit = AddressEditForm(None, request)
+    >>> edit.update()
+    >>> PluggableTraverser(edit, request).publishTraverse(request, 'validate')()
+    u''
+    >>> request = TestRequest(form={'widget-id':'form-widgets-zip',
+    ...                             'form.widgets.zip':'notazipcode'})
+    >>> edit = AddressEditForm(None, request)
+    >>> edit.update()
+    >>> PluggableTraverser(edit, request).publishTraverse(request, 'validate')()
+    u''
\ No newline at end of file



More information about the Checkins mailing list