<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mFabrik - mobile sites, apps, HTML5 and CMS software development &#187; ajax</title>
	<atom:link href="http://blog.mfabrik.com/tag/ajax/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mfabrik.com</link>
	<description>Freedom delivered.</description>
	<lastBuildDate>Wed, 03 Aug 2011 09:47:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>AJAX proxy view with Python, urllib and Plone</title>
		<link>http://blog.mfabrik.com/2011/08/02/ajax-proxy-view-with-python-urllib-and-plone/</link>
		<comments>http://blog.mfabrik.com/2011/08/02/ajax-proxy-view-with-python-urllib-and-plone/#comments</comments>
		<pubDate>Tue, 02 Aug 2011 08:26:42 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[plone]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[access control]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[allow-access-origin]]></category>
		<category><![CDATA[cors]]></category>
		<category><![CDATA[cross domain]]></category>
		<category><![CDATA[getjson]]></category>
		<category><![CDATA[grok]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[restful]]></category>

		<guid isPermaLink="false">http://blog.mfabrik.com/?p=1365</guid>
		<description><![CDATA[Old web browsers do not support Allow-acces-origin HTTP header needed to do cross-domain AJAX requests (IE6, IE7). Below is an example how to work around this for jQuery getJSON() calls by Detecting browsers which do not support this using jQuery.support API Doing an alternative code path through a local website proxy view which uses Python [...]]]></description>
			<content:encoded><![CDATA[<div class="body">
<p>Old web browsers do not support <a class="reference external" href="https://developer.mozilla.org/en/HTTP_access_control">Allow-acces-origin HTTP header</a> needed to do cross-domain AJAX requests (IE6, IE7).</p>
<p>Below is an example how to work around this for jQuery getJSON() calls by</p>
<ul class="simple">
<li>Detecting browsers which do not support this using jQuery.support API</li>
<li>Doing an alternative code path through a local website proxy view which uses Python <tt class="docutils literal">urllib</tt> to make server-to-server call and return it as it would be a local call, thus working around cross-domain restriction</li>
</ul>
<p>This example is for Plone/Grok, but the code is easily port to other Python web frameworks.</p>
<div class="note">
<p class="last"><em>Note: This is not a full example code. Basic Python and Javascript skills are needed to interpret and adapt the code for your use case.</em></p>
</div>
<p>Javascript example</p>
<pre class="literal-block">/**
 * Call a RESTful service vie AJAX
 *
 * The final URL is constructed by REST function name, based
 * on a base URL from the global settings.
 *
 * If the browser does not support cross domain AJAX calls
 * we'll use a proxy function on the local server. For
 * performance reasons we do this only when absolutely needed.
 *
 * @param {String} functionName REST function name to a call
 *
 * @param {Object} Arguments as a dictionary like object, passed to remote call
 */
function callRESTful(functionName, args, callback) {

    var src = myoptions.restService + "/" +functionName;

    // set to true to do proxied request on every browser
    // useful if you want to use Firebug to debug your server-side proxy view
    var debug = false;

        console.log("Doing remote call to:" + src)

        // We use jQuery API to detect whether a browser supports cross domain AJAX calls
        // http://api.jquery.com/jQuery.support/
        if(!jQuery.support.cors || debug) {
                // http://alexn.org/blog/2011/03/24/cross-domain-requests.html
                // Opera 10 doesn't have this feature, neither do IExplorer &lt; 8, Firefox &lt; 3.5

                console.log("Mangling getJSON to go through a local proxy")

                // Change getJSON to go to our proxy view on a local server
                // and pass the orignal URL as a parameter
                // The proxy view location is given as a global JS variable
                args.url = src;
                src = myoptions.portalUrl + "/@@proxy";
        }

        // Load data from the server
        $.getJSON(src, args, function(data) {
                // Parse incoming data and construct Table rows according to it
                console.log("Data succesfully loaded");
                callback(data, args);

     });

}</pre>
<p>The server-side view:</p>
<pre class="literal-block">import socket
import urllib
import urllib2
from urllib2 import HTTPError

from five import grok
from Products.CMFCore.interfaces import ISiteRoot
from mysite.app import options

class Proxy(grok.CodeView):
    """
    Pass a AJAX call to a remote server. This view is mainly indended to be used
    with jQuery.getJSON() requests.

    This will work around problems when a browser does not support Allow-Access-Origin HTTP header (IE).

    Asssuming only HTTP GET requests are made.s
    """

    # This view is available only at the root of Plone site
    grok.context(ISiteRoot)

    def isAllowed(self, url):
        """
        Check whether we are allowed to call the target URL.

        This prevents using your service as an malicious proxy
        (to call any internet service).
        """

        allowed_prefix = options.REST_SERVICE_URL

        if url.startswith(allowed_prefix):
            return True

        return False

    def render(self):
        """
        Use HTTP GET ``url`` query parameter for the target of the real request.
        """

        # Make sure any theming layer won't think this is HTML
        # http://stackoverflow.com/questions/477816/the-right-json-content-type
        self.request.response.setHeader("Content-type", "application/json")

        url = self.request.get("url", None)
        if not url:
            self.request.response.setStatus(500, "url parameter missing")

        if not self.isAllowed(url):
            # The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeate
            self.request.response.setStatus(403, "proxying to the target URL not allowed")
            return

        # Pass other HTTP GET query parameters direclty to the target server
        params = {}
        for key, value in self.request.form.items():
            if key != "url":
                params[key] = value

        # http://www.voidspace.org.uk/python/articles/urllib2.shtml
        data = urllib.urlencode(params)

        full_url = url + "?" + data
        req = urllib2.Request(full_url)

        try:

            # Important or if the remote server is slow
            # all our web server threads get stuck here
            # But this is UGLY as Python does not provide per-thread
            # or per-socket timeouts thru urllib
            orignal_timeout = socket.getdefaulttimeout()
            try:
                socket.setdefaulttimeout(10)

                response = urllib2.urlopen(req)
            finally:
                # restore orignal timeoout
                socket.setdefaulttimeout(orignal_timeout)

            # XXX: How to stream respone through Zope
            # AFAIK - we cannot do it currently

            return response.read()

        except HTTPError, e:
            # Have something more useful to log output as plain urllib exception
            # using Python logging interface
            # http://docs.python.org/library/logging.html
            logger.error("Server did not return HTTP 200 when calling remote proxy URL:" + url)
            for key, value in params.items():
                logger.error(key + ": "  + value)

            # Print the server-side stack trace / error page
            logger.error(e.read())

            raise e</pre>
</div>
<p class="signature">
<a href="http://mfabrik.com/@@zoho-contact-form"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/mfabrik-24.png"></a> <a href="http://mfabrik.com/@@zoho-contact-form">Get developers</a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml"><img valign="middle" src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt="" style="vertical-align:middle;border:0"/></a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml">Subscribe mFabrik blog in a reader</a> <a href="http://twitter.com/mfabrik"> <img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/twitter-24.png"></a> <a href="http://twitter.com/moo9000">Follow me on Twitter</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2011/08/02/ajax-proxy-view-with-python-urllib-and-plone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lazily load elements becoming visible using jQuery</title>
		<link>http://blog.mfabrik.com/2011/03/09/lazily-load-elements-becoming-visible-using-jquery/</link>
		<comments>http://blog.mfabrik.com/2011/03/09/lazily-load-elements-becoming-visible-using-jquery/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 09:57:52 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[plone]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[comments]]></category>
		<category><![CDATA[discussion]]></category>
		<category><![CDATA[disqus]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[lazy load]]></category>
		<category><![CDATA[static]]></category>
		<category><![CDATA[varnish]]></category>

		<guid isPermaLink="false">http://blog.mfabrik.com/?p=1078</guid>
		<description><![CDATA[It is a useful trick to lazily load comments or such elements at the bottom of page. Some elements may be loaded only when they are scrolled visible. All users are not interested in the information and do not necessary read the article long enough to see it By lazily loading such elements one can [...]]]></description>
			<content:encoded><![CDATA[<p>It is a useful trick to lazily load comments or such elements at the bottom of page. Some elements may be loaded only when they are scrolled visible.</p>
<ul>
<li>All users are not interested in the information and do not necessary read the article long enough to see it</li>
<li>By lazily loading such elements one can speed up the initial page load time</li>
<li>You save bandwidth</li>
<li>If you use AJAX for the dynamic elements of the page you can more easily cache your pages in static page cache (Varnish) even if the pages contain personalized bits</li>
</ul>
<p>For example, Disqus is doing this (see <a href="http://api.jquery.com/jQuery.ajax/">comments in jQuery API documentation</a>).</p>
<p>You can achieve this with <a href="http://remysharp.com/2009/01/26/element-in-view-event-plugin/">in-view plug-in for jQuery</a>.</p>
<p>Below is an example for Plone triggering <span style="text-decoration: underline;"><em>productappreciation_view</em></span> loading when our placeholder <em>div</em> tag becomes visible.</p>
<pre>...
&lt;head&gt;
  &lt;script type="text/javascript" tal:attributes="src string:${portal_url}/++resource++your.app/in-view.js"&gt;&lt;/script&gt;
&lt;/head&gt;
...
&lt;div id="comment-placefolder"&gt;

 &lt;!-- Display spinning AJAX indicator gif until our AJAX call completes --&gt;

 &lt;p&gt;
 &lt;!-- Image is in Products.CMFPlone/skins/plone_images --&gt;
 &lt;img tal:attributes="src string:${context/@@plone_portal_state/portal_url}/spinner.gif" /&gt; Loading comments
 &lt;/p&gt;

 &lt;!-- Hidden link to a view URL which will render the view containing the snippet for comments --&gt;                       
 &lt;a rel="nofollow" style="display:none" tal:attributes="href string:${context/absolute_url}/productappreciation_view" /&gt;

 &lt;script&gt;

 jq(document).ready(function() {

   // http://remysharp.com/2009/01/26/element-in-view-event-plugin/                                        
   jq("#comment-placeholder").bind("inview", function() {

     // This function is executed when the placeholder becomes visible

     // Extract URL from HTML page
     var commentURL = jq("#comment-placeholder a").attr("href");

     if (commentURL) {
     // Trigger AJAX call
       jq("#comment-placeholder").load(commentURL);
     }

   });                                     

 });     
 &lt;/script&gt;
&lt;/div&gt;</pre>
<p class="signature">
<a href="http://mfabrik.com/@@zoho-contact-form"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/mfabrik-24.png"></a> <a href="http://mfabrik.com/@@zoho-contact-form">Get developers</a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml"><img valign="middle" src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt="" style="vertical-align:middle;border:0"/></a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml">Subscribe mFabrik blog in a reader</a> <a href="http://twitter.com/mfabrik"> <img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/twitter-24.png"></a> <a href="http://twitter.com/moo9000">Follow me on Twitter</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2011/03/09/lazily-load-elements-becoming-visible-using-jquery/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Disabling cross-domain security check for AJAX development in Google Chrome</title>
		<link>http://blog.mfabrik.com/2010/11/29/disabling-cross-domain-security-check-for-ajax-development-in-google-chrome/</link>
		<comments>http://blog.mfabrik.com/2010/11/29/disabling-cross-domain-security-check-for-ajax-development-in-google-chrome/#comments</comments>
		<pubDate>Mon, 29 Nov 2010 11:39:54 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[chrome]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[cross browser]]></category>
		<category><![CDATA[CSRF]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.mfabrik.com/?p=839</guid>
		<description><![CDATA[This tip is for those who need to test Javascript / HTML5 web application functionality against a production server from their local HTML and Javascript files (not localhost). Start Google Chrome with no security from command lin, OSX: /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-web-security Start Google Chrome from command line, Ubuntu/Linux: chromium-browser --disable-web-security After this cross-domain AJAX [...]]]></description>
			<content:encoded><![CDATA[<p>This tip is for those who need to test Javascript / HTML5 web application functionality against a production server from their local HTML and Javascript files (not localhost).</p>
<p>Start Google Chrome with no security from command lin, OSX:</p>
<pre>
<div id="_mcePaste">/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-web-security</div>
</pre>
<p>Start Google Chrome from command line, Ubuntu/Linux:</p>
<pre>chromium-browser --disable-web-security</pre>
<div>After this cross-domain AJAX requests work.</div>
<p class="signature">
<a href="http://mfabrik.com/@@zoho-contact-form"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/mfabrik-24.png"></a> <a href="http://mfabrik.com/@@zoho-contact-form">Get developers</a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml"><img valign="middle" src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt="" style="vertical-align:middle;border:0"/></a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml">Subscribe mFabrik blog in a reader</a> <a href="http://twitter.com/mfabrik"> <img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/twitter-24.png"></a> <a href="http://twitter.com/moo9000">Follow me on Twitter</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2010/11/29/disabling-cross-domain-security-check-for-ajax-development-in-google-chrome/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Plone, KSS, Javascript, field validation and the cup of WTF</title>
		<link>http://blog.mfabrik.com/2008/06/12/plone-kss-javascript-field-validation-and-the-cup-of-wtf/</link>
		<comments>http://blog.mfabrik.com/2008/06/12/plone-kss-javascript-field-validation-and-the-cup-of-wtf/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 00:43:39 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[Plone (old)]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[archetypes]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[field]]></category>
		<category><![CDATA[heisenbug]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[kss]]></category>
		<category><![CDATA[validation]]></category>
		<category><![CDATA[zope]]></category>
		<category><![CDATA[zope 3]]></category>

		<guid isPermaLink="false">http://blog.redinnovation.com/?p=46</guid>
		<description><![CDATA[Knowledge does hurt. Today I had my sweet cup of WTF. We are developing a medical database based on Plone 3.1. It uses very advanced AJAX framework called KSS &#8211; basically you can avoid the pain of writing pure Javascript by crafting special CSS like stylesheets which bind server-side Python code to any Javascript event. [...]]]></description>
			<content:encoded><![CDATA[<p>Knowledge <em>does</em> hurt. Today I had my sweet cup of WTF. We are developing a medical database based on Plone 3.1. It uses very advanced AJAX framework called <a href="http://kssproject.org/">KSS</a> &#8211; basically you can avoid the pain of writing pure Javascript by crafting special CSS like stylesheets which bind server-side Python code to any Javascript event. This makes AJAX programming a joy. You can easily combine server-side logic with user interface events, like field validation.</p>
<p>Well&#8230; then there was an error. KSS validation was not working for the text fields on a certain pages&#8230;. or it did sometimes. We were not sure. This is so called <a href="http://en.wikipedia.org/wiki/Heisenbug#Heisenbugs">Heisenbug</a>. I armed myself with sleepy eyes, Firebug and a lot of energy drinks.</p>
<p>I saw a KSS error in the Firebug log window and failed HTTP POST in the server logs.</p>
<p style="padding-left: 30px;"><strong> Invalid request.</strong></p>
<p style="padding-left: 30px;">The parameter, <em>value,</em> was omitted from the request.</p>
<p>Looks like the field value was not properly posted for the field validation.</p>
<p>The first thing was locate the error and get function traceback for the messy situation. Unfortunately Firefox Javascript engine or Firebug cannot show tracebacks properly&#8230; <a href="http://www.microsoft.com/express/vwd/">the grass is so much greener on the other side of the fence</a>. So I had to manually search through the codebase by manually plotting console.log() calls here and there.</p>
<p>Finally I thought I pinpointed the cause of the failure. By shaking finger (excitement, tireness and all that extra caffeinen from energy drinks), I opened the Javascript file just to realize why Javascript is utterly utterly shitty and why no sane person wants to do low level Javascript development. If ECMA standard committee had been clever and had been able to enforce anything long time ago, the following piece could be replaced with one function call.</p>
<pre>fo.getValueOfFormElement = function(element) {
    // Returns the value of the form element / or null
    // First: update the field in case an editor is lurking
    // in the background
    this.fieldUpdateRegistry.doUpdate(element);
    if (element.disabled) {
        return null;
    }
    // Collect the data
    if (element.selectedIndex != undefined) {
        // handle single selects first
        if(!element.multiple) {
                if (element.selectedIndex &lt; 0) {
                    value="";
                } else {
                    var option = element.options[element.selectedIndex];
                    // on FF and safari, option.value has the value
                    // on IE, option.text needs to be used
                    value = option.value || option.text;
                }
        // Now process selects with the multiple option set
        } else {
            var value = [];
            for(i=0; i&lt;element.options.length; i++) {
                var option = element.options[i];
                if(option.selected) {
                    // on FF and safari, option.value has the value
                    // on IE, option.text needs to be used
                    value.push(option.value || option.text);
                }
            }
        }
    // Safari 3.0.3 no longer has "item", instead it works
    // with direct array access []. Although other browsers
    // seem to support this as well, we provide checking
    // in both ways. (No idea if item is still needed.)
    } else if (typeof element.length != 'undefined' &amp;&amp;
        ((typeof element[0] != 'undefined' &amp;&amp;
        element[0].type == "radio") ||
        (typeof element.item(0) != 'undefined' &amp;&amp;
        element.item(0).type == "radio"))) {
        // element really contains a list of input nodes,
        // in this case.
        var radioList = element;
        value = null;
        for (var i=0; i &lt; radioList.length; i++) {
            var radio = radioList[i] || radioList.item(i);
            if (radio.checked) {
                value = radio.value;
            }
        }
    } else if (element.type == "radio" || element.type == "checkbox") {
        if (element.checked) {
           value = element.value;
        } else {
            value = null;
        }
    } else if ((element.tagName.toLowerCase() == 'textarea')
               || (element.tagName.toLowerCase() == 'input' &amp;&amp;
                    element.type != 'submit' &amp;&amp; element.type != 'reset')
              ) {
        value = element.value;
    } else {
        value = null;
    }
    return value;
};
</pre>
<p>It turned out that the element in this case was an empty list of radio buttons. When you are tab keying through a radio button group without any value selected, like in the case a content object is just created, KSS validation is triggered even though there is no value in any of the radio buttons. This makes KSS think the value is null and it does not properly handle the situation. This does not cause any user visible effects unless you have Javascript debugging on (Firebug + debugging mode in Plone&#8217;s Javascript registry).</p>
<p>But this was not the bug I was looking for. It was just masking the original bug, because I had an empty radio button group next to the text field whose validation was not correctly done. More server side debugging&#8230;</p>
<p>I inserted some funky debug prints to Archetypes.Field.validate_validators():</p>
<pre>validate_validators()</pre>
<pre>Calling validators:(('isEmptyNoError', V_SUFFICIENT), ('validDecRange03', V_REQUIRED))</pre>
<p>We can see that not triggered validator, validDecRange03, is still with us. Then I add more debug prints to see where things go wrong, this time to to Products.validation.chain.__call__.</p>
<pre>Calling validators:(('isEmptyNoError', V_SUFFICIENT), ('validDecRange03', V_REQUIRED))
Name:isEmptyNoError value:234234234234234234234234234232342342342344534232342344234534554 result:True</pre>
<p>Ok &#8211; we have a case here. isEmptyNoError validator is executed before our custom validator. Since this validator is flagged as &#8220;sufficient&#8221; other validators are not evaluated. I think this has not been the case before and our validator have worked properly&#8230; maybe there was API change in Plone 3.1 which broke the things?</p>
<p>After digging and digging and digging I found <a href="https://dev.plone.org/archetypes/ticket/591">this 4 years old bug</a>. Let&#8217;s open the famous isEmptyNoError source code in Products.validation.validators.EmptyValidator:</p>
<pre>class EmptyValidator:
    __implements__ = IValidator

    def __init__(self, name, title='', description='', showError=True):
        self.name = name
        self.title = title or name
        self.description = description
        self.showError = showError

    def __call__(self, value, *args, **kwargs):
        isEmpty  = kwargs.get('isEmpty', False)
        instance = kwargs.get('instance', None)
        field    = kwargs.get('field', None)

        # XXX: This is a temporary fix. Need to be fixed right for AT 2.0
        #      content_edit / BaseObject.processForm() calls
        #      widget.process_form a second time!
        if instance and field:
            widget  = field.widget
            request = getattr(instance, 'REQUEST', None)
            if request and request.form:
                form   = request.form
                result = widget.process_form(instance, field, form,
                                             empty_marker=_marker,
                                             emptyReturnsMarker=True)
                if result is _marker or result is None:
                    isEmpty = True

        if isEmpty:
            return True
        elif value == '' or value is None:
            return True
        else:
            if getattr(self, 'showError', False):
                return ("Validation failed(%(name)s): '%(value)s' is not empty." %
                       { 'name' : self.name, 'value': value})
            else:
                return False
</pre>
<p>There is my WTF. Or XXX &#8211; thanks for the kisses. My guess is that because KSS validation is executed in special context, the magical REQUEST might not be there. The &#8220;is sufficient&#8221; validator fails because of the some sort of god forgotten magic and thus <strong>all custom validators fail in KSS when the field is not required</strong>.</p>
<p>The workaround: I add my own greetings to the code:</p>
<pre>        # XXX: This is a temporary fix. Need to be fixed right for AT 2.0
        #      content_edit / BaseObject.processForm() calls
        #      widget.process_form a second time!
        if instance and field:
            widget  = field.widget
            request = getattr(instance, 'REQUEST', None)

            # XXX: Whatever this all does, it does not work for KSS validation
            # requests and we should ignore this
            if "fieldname" in request:
              return False

            if request and request.form:
                form   = request.form
                result = widget.process_form(instance, field, form,
                                             empty_marker=_marker,
                                             emptyReturnsMarker=True)
                if result is _marker or result is None:
                    isEmpty = True
</pre>
<p>If Zope 3 drives you smoking Plone 3 drives me drinking. No wonder newbies steer away from Plone &#8211; if you hadn&#8217;t been armed with 8 years of web development experience you would never have figured out what&#8217;s going on with such a simple thing as adding a custom validator. <a href="http://dev.plone.org/plone/ticket/7589#comment:4">A comment added to the bug tracker</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2008/06/12/plone-kss-javascript-field-validation-and-the-cup-of-wtf/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

