Author: bree
Date: Thu Nov 17 08:29:38 2005
New Revision: 1863

Added:
   azax/branches/json/README.json
   azax/branches/json/azax/azax_json.js
   azax/branches/json/azaxresponse_json.py   (contents, props changed)
   azax/branches/json/tests/test_azaxresponse_json.py   (contents, props 
changed)
Modified:
   azax/branches/json/__init__.py
   azax/branches/json/configure.zcml
   azax/branches/json/demos/azaxdemo/browser/azax_demo.pt
   azax/branches/json/demos/azaxdemo/browser/azax_two_select.pt
Log:
Make azax work with json

This is a first try, and thus it has many things undone.

TODO (first):

* make a separation of the transport layer
  - on the js importing level, make this or that js to be imported.
    This should be totally transparent to the client app.
  - make the AzaxResponse pluggable

* merge the codebases together, hopefully find a good separation line

* catch up with newest version

To make this work, you must also install the newest version
of the jsonserver product.



Added: azax/branches/json/README.json
==============================================================================
--- (empty file)
+++ azax/branches/json/README.json      Thu Nov 17 08:29:38 2005
@@ -0,0 +1,26 @@
+Make azax work with json
+
+This is a first try, and thus it has many things undone.
+
+TODO (first):
+
+* make a separation of the transport layer
+  - on the js importing level, make this or that js to be imported.
+    This should be totally transparent to the client app.
+  - make the AzaxResponse pluggable
+
+* merge the codebases together, hopefully find a good separation line
+
+* catch up with newest version
+
+To make this work, you must also install the newest version
+of the jsonserver product.
+
+You can find this in a bazaar (tla) archive in:
+
+       --yet to be added--
+
+Homepage of jsonserver:
+
+       http://jsonserver.ree.hu
+

Modified: azax/branches/json/__init__.py
==============================================================================
--- azax/branches/json/__init__.py      (original)
+++ azax/branches/json/__init__.py      Thu Nov 17 08:29:38 2005
@@ -1,3 +1,14 @@
 import mimetypes
 
 mimetypes.types_map['.azax'] = 'text/xml' 
+
+# json hook
+use_json = True
+
+if use_json:
+    # This is a terrible hack for rhe moment
+    # note that in addition there was a change in the five configuration, too
+    import azaxresponse, azaxresponse_json
+    azaxresponse.AzaxSelector = azaxresponse_json.AzaxSelector
+    azaxresponse.AzaxCommand = azaxresponse_json.AzaxCommand
+    azaxresponse.AzaxResponse = azaxresponse_json.AzaxResponse

Added: azax/branches/json/azax/azax_json.js
==============================================================================
--- (empty file)
+++ azax/branches/json/azax/azax_json.js        Thu Nov 17 08:29:38 2005
@@ -0,0 +1,333 @@
+/* azax */
+
+function Azax(){};
+
+// the results are collected in order to set up the events
+// on the new nodes. Should be eventually removed.
+
+Azax.storedResults = new Array();
+
+Azax.storeResults = function(results)
+{
+Azax.storedResults[Azax.storedResults.length] = results;
+}
+
+Azax.getLastResults = function()
+{
+  var length = Azax.storedResults.length;
+  if (length != 0)
+  {
+    return Azax.storedResults[length-1];
+  }
+}
+
+Azax.setupStyles = function()
+{
+  nodes = document.getElementsByTagName("link");
+  for (var i=0;i < nodes.length;i++)
+  {
+    if (nodes[i].rel=="azax")
+    {
+      href = nodes[i].href;
+      preprocessor = new AzaxPreProcessor();
+      domdoc = preprocessor.loadStyleSheet(href);
+      preprocessor.parseStyleDom(domdoc);
+      preprocessor.setupEvents();
+    }
+  }
+}
+
+
+// preprocessor 
+function AzaxPreProcessor() {
+  this.styles = new Array();
+}
+
+AzaxPreProcessor.prototype.loadStyleSheet = function(uri)
+{
+  var domDoc = Sarissa.getDomDocument();
+  domDoc.async = false;
+  domDoc.load(uri);
+  return domDoc;
+}
+
+AzaxPreProcessor.prototype.parseStyleDom = function(domDocument)
+{
+  styles = domDocument.getElementsByTagName("style");
+
+  for (var i=0;i < styles.length;i++)
+  {
+    var style = styles[i];
+    var childNodes = styles[i].childNodes;
+    selector = "";
+    event_ = "";
+    action = "";
+
+    selectorNodes = style.getElementsByTagName("selector");
+    if (selectorNodes.length == 1 && selectorNodes[0].childNodes.length != 0)
+    {
+      selector = selectorNodes[0].firstChild.nodeValue;
+    }
+
+    eventNodes = style.getElementsByTagName("event");
+    if (eventNodes.length == 1 && eventNodes[0].childNodes.length != 0)
+    {
+      event_ = eventNodes[0].firstChild.nodeValue;
+    }
+    
+    actionNodes = style.getElementsByTagName("action");
+    if (actionNodes.length == 1 && actionNodes[0].childNodes.length != 0)
+    {
+      action = actionNodes[0].firstChild.nodeValue;
+    }
+    
+    if (selector != "" && event_ != "" && action != "")
+    {
+      style = new AzaxStyle(selector, event_, action);
+      this.styles[this.styles.length] = style;
+    }
+  }
+}
+
+AzaxStyle = function(selector, event_, action)
+{
+  this.selector = selector;
+  this.event = event_;
+  this.action = action;
+}
+
+
+AzaxPreProcessor.prototype.setupEvents = function()
+{
+  styles = this.styles
+  for (var y=0;y < styles.length;y++)
+  {
+    style = styles[y];
+    this.setupEvent(style);  
+  }
+}
+
+
+// Code below is really changed in favour of json.
+// XXX Refactoring desired!
+
+var jsonrpc = importModule("jsonrpc");
+Azax.jsonaddr = ".";
+Azax.jsonproxy =  new jsonrpc.ServiceProxy(Azax.jsonaddr, []);
+
+AzaxPreProcessor.prototype.setupEvent = function(style)
+{
+    nodes = cssQuery(style.selector);
+    for (var y=0; y < nodes.length; y++)
+    {
+        node = nodes[y];
+        Azax.jsonproxy._addMethodNames([style.action]);
+        func = function() {Azax.notifyServer(style.action);}
+        registerEventListener(node, style.event, func);
+    }
+}
+
+// this did not change
+
+/* extracted from Plone */
+// cross browser function for registering event handlers
+function registerEventListener(elem, event, func) {
+    if (elem.addEventListener) {
+        elem.addEventListener(event, func, false);
+        return true;
+    } else if (elem.attachEvent) {
+        var result = elem.attachEvent("on"+event, func);
+        return result;
+    }
+    // maybe we could implement something with an array
+    return false;
+}
+
+function extractFormsDatas()
+{
+    forms = document.forms;
+    var data = new Object();
+
+    for (var i=0;i < forms.length;i++)
+    {
+        var form = forms[i];
+        var name = form.name;
+        if (name)
+        {
+            //var f = new Object();
+            elements = form.elements;
+            for (var y=0;y < elements.length;y++)
+            {
+                var element = elements[y];
+                
+                if (element.name)
+                {
+                    //f[element.name] = element.value;
+                    data[element.name] = element.value;
+                }
+            }
+            //data[name] = f;
+            //for (var p in f){
+            //    alert("array at position "+p+"="+f[p]);
+            //}
+        }
+    }
+    return data;
+}
+
+//var domDoc = new XMLHttpRequest();
+
+var pythonkw = importModule("pythonkw");
+
+Azax.notifyServer = function(action)
+{
+  // need to lock this so it's serialized
+  // sending form
+  form_data = extractFormsDatas();
+  //domDoc.open("POST", action, true);
+  //domDoc.onreadystatechange = Azax.notifyServer_done;
+  //domDoc.setRequestHeader("Content-Type", 
"application/x-www-form-urlencoded");
+  //domDoc.send(form_data);
+  //func(form_data, Azax.notifyServer_done);
+
+  var func = Azax.jsonproxy[action];
+  //special marshalling: will become keyword attrs in the request.
+  //keyword_repr = {"jsonclass": ["zope.kw", form_data]};
+  var keyword_repr = new pythonkw.PythonKw(form_data);
+  func(keyword_repr, Azax.notifyServer_json_done);
+}
+
+Azax.notifyServer_done = function()
+{
+    // need to lock this so it's serialized
+    if (domDoc.readyState == 4)
+    {
+        Azax.processResult(domDoc.responseXML);
+    }
+}
+
+Azax.notifyServer_json_done = function(result, err)
+{
+    if (!err) 
+    {
+        Azax.processResult(result);
+    } 
+    else 
+    {
+        // do something with err
+        alert(err);
+    }
+}
+
+var registeredEvents = new Array();
+
+Azax.processResult = function(selectors)
+{
+    for (var key in selectors)
+    {
+        var selector = selectors[key];
+        var selector_value = selector["value"];
+        var commands = selector["commands"];
+
+        for (var i=0;i < commands.length;i++)
+        {
+            var command = commands[i];
+            var command_data = command["data"];
+            var command_name = command["name"];
+
+            Azax.executeCommand(selector_value, command_name, command_data);
+        }
+    }
+}
+
+Azax.executeCommand = function(selector_value, command_name, command_data)
+{
+    nodes = cssQuery(selector_value);
+    for (var i=0;i < nodes.length;i++)
+    {
+        var node = nodes[i];
+        var results = Azax.commandFunctions[command_name](node, command_data);
+        Azax.storeResults(results);
+    }
+
+}
+
+// common parts start below here
+// only I had to start the fetching.
+
+var xml = importModule("xml");
+
+/* parse and apply azax styles when document is loaded */ 
+registerEventListener(window, "load", Azax.setupStyles);
+
+Azax.insertBefore = function(nodeFrom, parentNode, nodeTo) {
+    var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : 
nodeTo.ownerDocument;
+    var nodes = nodeFrom.childNodes;
+    var result = new Array();
+    if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
+        for(var i=0;i < nodes.length;i++) {
+            result[i] = parentNode.insertBefore(ownerDoc.importNode(nodes[i], 
true), nodeTo);
+        };
+    }
+    else{
+        for(var i=0;i < nodes.length;i++) {
+            result[i] = parentNode.insertBefore(nodes[i].cloneNode(true), 
nodeTo);
+        };
+    };
+    return result;
+}
+
+Azax.commandFunctions = new Array();
+Azax.commandFunctions['setHtmlAsChild']=function(node, command_data)
+{
+    //var content = document.importNode(command_data['html'], true);
+    //Sarissa.copyChildNodes(content, node);
+
+    // this would be the way, but innerHTML fails with the select
+    //node.innerHTML = command_data;
+
+    var oDomDoc = Sarissa.getDomDocument();
+    var xmlString = '<root xmlns="http://www.w3.org/1999/xhtml";>' + 
command_data + '</root>';
+     
+    oDomDoc = (new DOMParser()).parseFromString(xmlString, "text/xml");
+    var content = document.importNode(oDomDoc, true);
+    Sarissa.copyChildNodes(content, node);
+}
+
+Azax.commandFunctions['addAfter']=function(node, command_data)
+{
+    //var content = document.importNode(command_data['html'], true);
+    var content = document.importNode(command_data, true);
+    parentNode = node.parentNode;
+    toNode = node.nextSibling;
+    inserted = Azax.insertBefore(content, parentNode, toNode);
+    return inserted;
+}
+
+Azax.commandFunctions['clearChildren']=function(node, command_data)
+{
+    Sarissa.clearChildNodes(node);
+}
+
+Azax.commandFunctions['copyChildrenFrom']=function(node, command_data)
+{
+    //var id = command_data['html_id'].firstChild.nodeValue;
+    var id = command_data;
+    fromNode = document.getElementById(id);
+    Sarissa.copyChildNodes(fromNode, node);
+}
+
+Azax.commandFunctions['copyChildrenTo']=function(node, command_data)
+{
+    //var id = command_data['html_id'].firstChild.nodeValue;
+    var id = command_data;
+    toNode = document.getElementById(id);
+    Sarissa.copyChildNodes(node, toNode);
+}
+
+Azax.commandFunctions['executeCode']=function(node, command_data)
+{
+      //var code = command_data['code'].firstChild.nodeValue;
+      var code = command_data['code'].firstChild.nodeValue;
+      node.eval(code);
+}

Added: azax/branches/json/azaxresponse_json.py
==============================================================================
--- (empty file)
+++ azax/branches/json/azaxresponse_json.py     Thu Nov 17 08:29:38 2005
@@ -0,0 +1,161 @@
+# -*- coding: ISO-8859-15 -*-
+# Copyright (c) 2005
+# Authors:
+#   Godefroid Chapelle <[EMAIL PROTECTED]>
+#   Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+from StringIO import StringIO
+
+from zope.interface import implements
+
+from interfaces import IAzaxResponse
+#from lxml import etree
+# this is not really "doing" it, just needed to test (str repr):
+from Products.jsonserver import minjson as json
+
+class AzaxSelector(dict):
+    """ azax selector / JSON
+
+        it contains a set of commands related to the selector
+    """
+
+    def __init__(self, selectors_ob, selector):
+        #self.ob = etree.SubElement(selectors_ob, 'selector')
+        #self.value = etree.SubElement(self.ob, 'value')
+        #self.commands = etree.SubElement(self.ob, 'commands')
+        self['commands'] = []
+        self['value'] = selector
+
+    def addCommand(self, command):
+        return AzaxCommand(self['commands'], command)
+
+class AzaxCommand(dict):
+    """ azax command / JSON 
+    """
+    def __init__(self, commands_ob, name):
+        #self.ob = etree.SubElement(commands_ob, 'command')
+        #name_ob = etree.SubElement(self.ob, 'name')
+        #name_ob.text = name
+        self['name'] = name
+        self['data'] = {}
+        commands_ob.append(self)
+
+    def addData(self, name):
+        #data = etree.SubElement(self.ob, 'data')
+        #data.set('name', name)
+        #return data
+
+        # name is ignored... at the moment
+        # returns self so we can "add" to it from wrapInHtmlNamespace
+        return self
+
+    # hack
+    def _settext(self, text):
+        self['data'] = text
+    text = property(lambda: self['data'], _settext)
+    
+
+class AzaxResponse(object):
+    """ azax command Response / JSON
+    """
+    implements(IAzaxResponse)
+
+    def __init__(self, _response=None):
+        self.selectors = {}
+        # We don't generate the response now - but we must
+        # accept the parm as products might (will) supply it
+
+    def __str__(self):
+        """ renders  json 
+        
+        (not really important, since really the response
+        is coded from python object transparently but
+        we can use it for test/debugging)
+        """
+        return json.write(self.selectors)
+
+    def __call__(self):
+        """ set response content type, if given """
+        return self.selectors
+
+    def _getSelector(self, selector):
+        """ return a selector, given its value tag """
+        if self.selectors.has_key(selector):
+            return self.selectors[selector]
+        else:
+            return self._createSelector(selector)
+
+    def _createSelector(self, selector):
+        """ creates a selector branch """
+        result = AzaxSelector(self.selectors, selector)
+        self.selectors[selector] = result
+        return result
+
+    def wrapInHtmlNamespace(self, new_value, data):
+        #new_value = '<junk>' + new_value + '</junk>'
+        #valuetree = etree.fromstring(new_value.encode('latin1'))
+        #for elem in valuetree.getchildren():
+        #    elem.set('xmlns', 'http://www.w3.org/1999/xhtml')
+        #    data.append(elem)
+        data.text = new_value
+ 
+    # Common code follows, needs to be refactored
+    
+    def setHtmlAsChild(self, selector, new_value):
+        """ see interfaces.py """
+        selector_ob = self._getSelector(selector)
+        command = selector_ob.addCommand('setHtmlAsChild')
+        data = command.addData('html')
+        self.wrapInHtmlNamespace(new_value, data)        
+    
+    def addAfter(self, selector, new_value):
+        """ see interfaces.py """
+        selector_ob = self._getSelector(selector)
+        command = selector_ob.addCommand('addAfter')
+        data = command.addData('html')
+        self.wrapInHtmlNamespace(new_value, data)        
+   
+    def clearChildren(self, selector):
+        """ see interfaces.py """
+        selector_ob = self._getSelector(selector)
+        command = selector_ob.addCommand('clearChildren')
+        data = command.addData('none')
+
+    def copyChildrenFrom(self, selector, id):
+        """ see interfaces.py """
+        selector_ob = self._getSelector(selector)
+        command = selector_ob.addCommand('copyChildrenFrom')
+        data = command.addData('html_id')
+        data.text = id
+
+    def copyChildrenTo(self, selector, id):
+        """ see interfaces.py """
+        selector_ob = self._getSelector(selector)
+        command = selector_ob.addCommand('copyChildrenTo')
+        data = command.addData('html_id')
+        data.text = id
+
+    def moveChildrenTo(self, selector, id):
+        """ see interfaces.py """
+        self.copyChildrenTo(selector, id)
+        self.clearChildren(selector)
+
+    def executeCode(self, selector, code):
+        selector_ob = self._getSelector(selector)
+        command = selector_ob.addCommand('executeCode')
+        data = command.addData('code')
+        data.text = code 

Modified: azax/branches/json/configure.zcml
==============================================================================
--- azax/branches/json/configure.zcml   (original)
+++ azax/branches/json/configure.zcml   Thu Nov 17 08:29:38 2005
@@ -8,7 +8,7 @@
   />
 
   <browser:resource
-    file="azax/azax.js"
+    file="azax/azax_json.js"
     name="azax.js"
   />
 

Modified: azax/branches/json/demos/azaxdemo/browser/azax_demo.pt
==============================================================================
--- azax/branches/json/demos/azaxdemo/browser/azax_demo.pt      (original)
+++ azax/branches/json/demos/azaxdemo/browser/azax_demo.pt      Thu Nov 17 
08:29:38 2005
@@ -3,6 +3,10 @@
     <link rel="azax"
           tal:attributes="href 
string:${context/absolute_url}/++resource++azax_demo.azax"/>
     <script type="text/javascript"
+      tal:attributes="src 
string:${context/absolute_url}/++resource++jsolait.js;"
+      src="++resource++jsolait.js">
+    </script>
+    <script type="text/javascript"
       tal:attributes="src 
string:${context/absolute_url}/++resource++sarissa.js;"
       src="++resource++sarissa.js">
     </script>

Modified: azax/branches/json/demos/azaxdemo/browser/azax_two_select.pt
==============================================================================
--- azax/branches/json/demos/azaxdemo/browser/azax_two_select.pt        
(original)
+++ azax/branches/json/demos/azaxdemo/browser/azax_two_select.pt        Thu Nov 
17 08:29:38 2005
@@ -3,6 +3,10 @@
     <link rel="azax"
           tal:attributes="href 
string:${context/absolute_url}/++resource++azax_two_selects.azax"/>
     <script type="text/javascript"
+      tal:attributes="src 
string:${context/absolute_url}/++resource++jsolait.js;"
+      src="++resource++jsolait.js">
+    </script>
+    <script type="text/javascript"
       tal:attributes="src 
string:${context/absolute_url}/++resource++sarissa.js;"
       src="++resource++sarissa.js">
     </script>

Added: azax/branches/json/tests/test_azaxresponse_json.py
==============================================================================
--- (empty file)
+++ azax/branches/json/tests/test_azaxresponse_json.py  Thu Nov 17 08:29:38 2005
@@ -0,0 +1,81 @@
+# -*- coding: ISO-8859-15 -*-
+# Copyright (c) 2005
+# Authors:
+#   Godefroid Chapelle <[EMAIL PROTECTED]>
+#   Tarek Ziad� <[EMAIL PROTECTED]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+import unittest, os
+from zope.testing import doctest
+from Testing.ZopeTestCase import ZopeTestCase
+from lxml import etree
+
+from Products.azax.azaxresponse import AzaxResponse
+
+class AzaxResponseTestCase(ZopeTestCase):
+
+    def test_instanciation(self):
+        ob = AzaxResponse()
+        self.assertNotEquals(ob, None)
+
+    def test_str_(self):
+        ob = AzaxResponse()
+        self.assertEquals(str(ob), '{}')
+
+    def test__createSelector(self):
+        ob = AzaxResponse()
+        selector = ob._createSelector('div.class')
+        self.assertEquals(str(ob),
+        '{"div.class": {"commands": [], "value": "div.class"}}')
+#         
'<selectors><selector><value>div.class</value><commands/></selector></selectors>')
+
+# XXX do we need the equivalent of this?
+#        self.assertEquals(etree.tostring(selector),
+#         '<selector><value>div.class</value><commands/></selector>')
+
+    # XXX disabled since there is no updateTag.
+    def _XXX_test_updateTag(self):
+        ob = AzaxResponse()
+        ob.updateTag('div.class', 'new_content')
+        self.assertEquals(str(ob),
+         
'<selectors><selector><value>div.class</value><commands><command><name>innerHTML</name><data>new_content</data></command></commands></selector></selectors>')
+
+    def test__getSelector(self):
+        ob = AzaxResponse()
+        selector = ob._createSelector('div.class')
+        self.assertEquals(len(ob.selectors), 1)
+        selector2 = ob._getSelector('div.class')
+        self.assertEquals(len(ob.selectors), 1)
+        self.assertEquals(selector, selector2)
+
+    def test_addcommand(self):
+        ob = AzaxResponse()
+        ob.setHtmlAsChild('div#demo', '<h1>it worked</h1>')
+        ob.setHtmlAsChild('div#demo', '<h1>it worked again</h1>')
+        self.assertEquals(ob(), {'div#demo': 
+                                    {'commands': [
+                                        {'data': '<h1>it worked</h1>', 'name': 
'setHtmlAsChild'}, 
+                                        {'data': '<h1>it worked again</h1>', 
'name': 'setHtmlAsChild'},
+                                        ], 
+                                    'value': 'div#demo'}
+                                }
+                            )
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(AzaxResponseTestCase),
+        doctest.DocTestSuite('Products.azax.azaxresponse'),
+        ))
-- 
http://lists.nuxeo.com/mailman/listinfo/z3lab-checkins

Reply via email to