[Checkins] SVN: jquery.jsontree/trunk/src/jquery/jsontree/ Added initial version of json tree

Roger Ineichen roger at projekt01.ch
Mon Jun 11 16:15:26 EDT 2007


Log message for revision 76625:
  Added initial version of json tree
  Added minimal tests
  
  TODO:
  - Add more tests
  - Implement better way for render HTML based on JSON callback
  - Implement a sample for z3c.website

Changed:
  A   jquery.jsontree/trunk/src/jquery/jsontree/README.txt
  A   jquery.jsontree/trunk/src/jquery/jsontree/SETUP.cfg
  A   jquery.jsontree/trunk/src/jquery/jsontree/__init__.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/base.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/__init__.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/configure.zcml
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/img/
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeCollapsed.gif
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeExpanded.gif
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeStatic.gif
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.css
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.js
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/li.pt
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/tests.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.pt
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/browser/ul.pt
  A   jquery.jsontree/trunk/src/jquery/jsontree/configure.zcml
  A   jquery.jsontree/trunk/src/jquery/jsontree/interfaces.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/jquery.jsontree-configure.zcml
  A   jquery.jsontree/trunk/src/jquery/jsontree/json.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/tests/
  A   jquery.jsontree/trunk/src/jquery/jsontree/tests/__init__.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/tests/output/
  A   jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_1.xml
  A   jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_2.xml
  A   jquery.jsontree/trunk/src/jquery/jsontree/tests/util.py
  A   jquery.jsontree/trunk/src/jquery/jsontree/util.py

-=-
Added: jquery.jsontree/trunk/src/jquery/jsontree/README.txt
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/README.txt	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/README.txt	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,28 @@
+======
+README
+======
+
+Version: Alpha
+
+
+Description
+-----------
+
+The jsontree is a <ul> tag tree loading child items via JSON form a context.
+
+NOTE:
+
+Description will follow after I changed the JOSN loader method. See TODO.txt
+
+
+TODO
+----
+
+- Improve rendering of JSON loader result. Allow to render HTML content and 
+  skip default.
+
+- write tests
+
+- write documentation
+
+- add a sampe for z3c.website

Added: jquery.jsontree/trunk/src/jquery/jsontree/SETUP.cfg
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/SETUP.cfg	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/SETUP.cfg	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+  jquery.jsontree-*.zcml
+</data-files>

Added: jquery.jsontree/trunk/src/jquery/jsontree/__init__.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/__init__.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/__init__.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""

Added: jquery.jsontree/trunk/src/jquery/jsontree/base.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/base.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/base.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,449 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import string
+import zope.interface
+import zope.component
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.traversing import api
+from zope.traversing.interfaces import TraversalError
+from zope.security.interfaces import Unauthorized
+from zope.security.interfaces import Forbidden
+from zope.traversing.browser import absoluteURL
+from zope.traversing.namespace import getResource
+from zope.viewlet.interfaces import IViewlet
+from zope.contentprovider.interfaces import IContentProvider
+from zope.app.container.interfaces import IReadContainer
+from zope.app.component import hooks
+from z3c.template.template import getPageTemplate
+
+from jquery.jsontree import interfaces
+from jquery.jsontree.interfaces import JSON_TREE_ID
+from jquery.jsontree.interfaces import JSON_TREE_VIEW_NAME
+from jquery.jsontree.interfaces import JSON_TOGGLE_ICON_COLLAPSED
+from jquery.jsontree.interfaces import JSON_TOGGLE_ICON_EXPANDED
+from jquery.jsontree.interfaces import JSON_TOGGLE_ICON_STATIC
+from jquery.jsontree.interfaces import JSON_LI_CSS_EXPANDED
+from jquery.jsontree.interfaces import JSON_LI_CSS_COLLAPSED
+from jquery.jsontree.interfaces import JSON_LI_CSS_STATIC
+from jquery.jsontree.interfaces import STATE_EXPANDED
+from jquery.jsontree.interfaces import STATE_COLLAPSED
+from jquery.jsontree.interfaces import STATE_STATIC
+from jquery.jsontree import util
+
+
+class TreeBase(object):
+    """Tree iterator base implementation."""
+
+    root = None
+    childTags = None
+    rootChilds = None
+    items = []
+
+    jsonTreeId = JSON_TREE_ID
+    jsonTreeName = JSON_TREE_ID
+    jsonTreeClass = JSON_TREE_ID
+
+    viewName = JSON_TREE_VIEW_NAME
+
+    # LI tag CSS names
+    expandedCSSName = JSON_LI_CSS_EXPANDED
+    collapsedCSSName = JSON_LI_CSS_COLLAPSED
+    staticCSSName = JSON_LI_CSS_STATIC
+
+    # toggle icon names
+    collapsedIconName = JSON_TOGGLE_ICON_COLLAPSED
+    expandedIconNamen = JSON_TOGGLE_ICON_EXPANDED
+    staticIconName = JSON_TOGGLE_ICON_STATIC
+
+    def getRoot(self):
+        if not self.root:
+            self.root = hooks.getSite()
+        return self.root
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def getSubItems(self, item):
+        items = []
+        append = items.append
+        if IReadContainer.providedBy(item):
+            keys = list(item.keys())
+        else:
+            keys = []
+        for name in keys:
+            # Only include items we can traverse to
+            subItem = api.traverse(item, name, None)
+            if subItem is not None:
+                append(subItem)
+        return items
+
+    def getIconURL(self, item, request, name='icon'):
+        return util.getIconURL(item, request, name=name)
+
+    def getParents(self):
+        root = self.getRoot()
+        return util.getParentsFromContextToObject(self.context, root)
+
+    def hasSubItems(self, item):
+        res = False
+        if IReadContainer.providedBy(item):
+            try:
+                if len(item) > 0:
+                    res = True
+            except(Unauthorized, Forbidden):
+                pass
+        return res
+
+    def update(self):
+        """Returns HTML code for representing a <ul> tag tree with the 
+        siblings and parents of an object.
+
+        There is only one branch expanded, in other words, the tree is
+        filled with the object, its siblings and its parents with
+        their respective siblings. This tree is stateless.
+
+        If we access the tree via a virtual host, the root is adjusted to
+        the right root object.
+
+        """
+        childTags = None
+        stackItem = self.context
+        parents = self.getParents()
+
+        for item in parents:
+            tagList = []
+            append = tagList.append
+
+            for subItem in self.getSubItems(item):
+                if self.hasSubItems(subItem):
+
+                    if subItem == stackItem:
+                        append(self.renderUL(subItem, childTags))
+                    else:
+                        append(self.renderUL(subItem))
+
+                else:
+                    append(self.renderLI(subItem))
+
+            childTags = ' '.join(tagList)
+            stackItem = item
+
+        self.childTags = childTags
+
+
+class PythonRendererMixin(object):
+    """Mixin class for template less tree generation.
+    
+    This renderer is responsible for rendering all HTML elements for the items
+    found in the tree. This means evrey item will be presented in the same way.
+    Use this renderer only if you like to get the same representation for each
+    item. If you need custom representation for each item, use the template 
+    based renderer which allows you to define for each item a custom class and
+    template.
+    """
+
+    def getRootName(self):
+        root = self.getRoot()
+        name = api.getName(self.root)
+        if name is None:
+            name = u'[top]'
+        return name
+
+    def getToggleIcon(self, item, state):
+        """Returns a toggle icon including settings for json url."""
+        if state == STATE_COLLAPSED:
+            iconName = self.collapsedIconName
+        elif state == STATE_EXPANDED:
+            iconName = self.expandedIconNamen
+        else:
+            iconName = self.staticIconName
+        icon = zope.component.getMultiAdapter((item, self.request), 
+            name=iconName)
+        resource = getResource(icon.context, icon.rname, self.request)
+        src = resource()
+        longDescURL = absoluteURL(item, self.request)
+        return ('<img src="%s" alt="toggle icon" width="%s" height="%s" ' 
+                'border="0" longDesc="%s" />' % (src, icon.width, 
+                   icon.height, longDescURL))
+
+    def renderLI(self, item):
+        name = api.getName(item)
+        url = absoluteURL(item, self.request) +'/'+ self.viewName
+        iconURL = self.getIconURL(item, self.request)
+        id = self.getId(item)
+
+        res = u''
+        toggleIcon = self.getToggleIcon(item, STATE_STATIC)
+        res += '<li id="%s" class="jsonTreeItem">%s' % (id, toggleIcon)
+        if iconURL != '':
+            res += '<img src="%s" width="16" height="16" />' % iconURL
+        res += '<a href="%s">%s</a>' % (url, name)
+        res += '</li>'
+        return res
+
+    def renderUL(self, item, childTags=None):
+        """Renders <li> tag with already rendered child tags."""
+        name = api.getName(item)
+        url = absoluteURL(item, self.request) +'/'+ self.viewName
+        iconURL = self.getIconURL(item, self.request)
+        id = self.getId(item)
+
+        if item == self.context:
+            state = STATE_COLLAPSED
+            liClass = self.collapsedCSSName
+        else:
+            state = STATE_EXPANDED
+            liClass = self.expandedCSSName
+
+        if childTags is None:
+            state = STATE_COLLAPSED
+            liClass = self.collapsedCSSName
+        
+        toggleIcon = self.getToggleIcon(item, state)
+
+        res = u''
+        res +=  '<li id="%s" class="%s">%s' % (id, liClass, toggleIcon)
+        if iconURL != '':
+            res += '<img src="%s" class="" width="16" height="16" />' % iconURL
+        res += '<a href="%s">%s</a>' % (url, name)
+        res += '  <ul>'
+        if childTags is not None:
+            res += '    %s' % childTags
+        res += '  </ul>'
+        res += '</li>'
+        return res
+
+    @property
+    def tree(self):
+        root = self.getRoot()
+        if root is None:
+            raise ValueError("Missing tree root object.")
+        id = self.getId(root)
+        rootName = self.getRootName()
+        url = absoluteURL(root, self.request) +'/'+ self.viewName
+
+        # setup root item
+        if self.childTags is None:
+            rootChilds = ''
+            liClass = self.collapsedCSSName
+            state = STATE_COLLAPSED
+        else:
+            rootChilds = '<ul>%s</ul>' % self.childTags
+            liClass = self.expandedCSSName
+            state = STATE_EXPANDED
+
+        # setup root toggle icon
+        toggleIcon = self.getToggleIcon(self.context, state)
+
+        # setup root link
+        rootLink = '<a href="%s">%s</a>' % (url, rootName)
+        rootItem = '<li id="%s" class="%s">%s%s%s</li>' % \
+            (id, liClass, toggleIcon, rootLink, rootChilds)
+
+        # render the <ul> tag tree
+        jsonTree = u''
+        jsonTree += '<ul class="%s" id="%s" name="%s">%s</ul>' % (
+            self.jsonTreeClass, self.jsonTreeId, self.jsonTreeName, rootItem)
+        return jsonTree
+
+
+class TemplateRendererMixin(object):
+    """Mixin class for template based tree generation.
+    
+    This implementation uses IContentProvider for element tag rendering. This 
+    makes it very flexible.
+    
+    Note: Don't forget to define custom JSONTreeItems methods which reflect the
+    custom rendering. Or you will get the default rendering behavior for JSON
+    loaded items.
+    """
+
+    zope.interface.implements(interfaces.ITemplateRenderer)
+
+    def renderLI(self, item):
+        provider = zope.component.getMultiAdapter(
+            (item, self.request, self), IContentProvider, 
+            self.liProviderName)
+        provider.state = STATE_STATIC
+        provider.update()
+        return provider.render()
+
+    def renderUL(self, item, childTags=None):
+        """Renders <li> tag with already rendered child tags."""
+        if item == self.context:
+            state = STATE_COLLAPSED
+        else:
+            state = STATE_EXPANDED
+
+        if childTags is None:
+            state = STATE_COLLAPSED
+
+        provider = zope.component.getMultiAdapter(
+            (item, self.request, self), IContentProvider, 
+            self.ulProviderName)
+        provider.childTags = childTags
+        provider.state = state
+        provider.update()
+        return provider.render()
+
+    @property
+    def tree(self):
+        root = self.getRoot()
+        if root is None:
+            raise ValueError("Missing tree root object.")
+
+        if self.childTags is None:
+            state = STATE_COLLAPSED
+        else:
+            state = STATE_EXPANDED
+
+        provider = zope.component.getMultiAdapter(
+            (root, self.request, self), IContentProvider, 
+            self.treeProviderName)
+        provider.childTags = self.childTags
+        provider.state = state
+        provider.update()
+        return provider.render()
+
+
+class IdGeneratorMixin(object):
+    """This mixin class generates Object Ids based on the the objects path.
+
+    Note: The objects must be traversable by it's path. You can implement a 
+    a custom path traverse concept in the getObjectByPath it you need to use
+    another traverse concept.
+
+    This ids must conform the w3c recommendation described in:
+    http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-name
+    """
+
+    def getId(self, item):
+        """Returns the DOM id for a given object.
+
+        Note: we encode the upper case letters because the Dom element id are 
+        not case sensitive in HTML. We prefix each upper case letter with ':'.
+        """
+        path = api.getPath(item)
+        newPath = u''
+        for letter in path:
+            if letter in string.uppercase:
+                newPath += ':' + letter
+            else:
+                newPath += letter
+        
+        # we use a dot as a root representation, this also avoids to get the 
+        # same id for the ul and the first li tag
+        if newPath == '/':
+            newPath = '.'
+        # add additinal dot which separates the tree id and the path, this is
+        # used for get the tree id out of the string in the javascript using 
+        # ids = id.split("."); treeId = ids[0];
+        id = self.jsonTreeId +'.'+ newPath
+        # convert '/' path separator to marker '::', because the path '/'' is  
+        # not allowed as DOM id. See also:
+        # http://www.w3.org/TR/1999/REC-html401-19991224/types.html#type-name
+        return id.replace('/', '::')
+
+    def id(self):
+        """Returns the DOM id for a given context."""
+        return self.getId(self.context)
+
+
+class ProviderBase(object):
+    """Base class for element provider."""
+
+    template = getPageTemplate()
+
+    state = None
+    childTags = None
+    viewName = u'@@SelectedManagementView.html'
+    iconName = 'icon'
+
+    # LI tag CSS names
+    collapsedCSSName = JSON_LI_CSS_COLLAPSED
+    expandedCSSName = JSON_LI_CSS_EXPANDED
+    staticCSSName = JSON_LI_CSS_STATIC
+
+    # toggle icon names
+    collapsedIconName = JSON_TOGGLE_ICON_COLLAPSED
+    expandedIconNamen = JSON_TOGGLE_ICON_EXPANDED
+    staticIconName = JSON_TOGGLE_ICON_STATIC
+
+    def __init__(self, context, request, view):
+        self.context = context
+        self.request = request
+        self.view = view
+
+    @property
+    def className(self):
+        if self.state == STATE_COLLAPSED:
+            return self.collapsedCSSName
+        elif self.state == STATE_EXPANDED:
+            return self.expandedCSSName
+        else:
+            return self.staticCSSName
+
+    @property
+    def toggleIcon(self):
+        """Returns a toggle icon including settings for json url."""
+        if self.state == STATE_COLLAPSED:
+            iconName = self.collapsedIconName
+        elif self.state == STATE_EXPANDED:
+            iconName = self.expandedIconNamen
+        else:
+            iconName = self.staticIconName
+        icon = zope.component.getMultiAdapter((self.context, self.request), 
+            name=iconName)
+        resource = getResource(icon.context, icon.rname, self.request)
+        src = resource()
+        longDescURL = absoluteURL(self.context, self.request)
+        return ('<img src="%s" alt="toggle icon" width="%s" height="%s" ' 
+                'border="0" longDesc="%s" />' % (src, icon.width, 
+                   icon.height, longDescURL))
+
+    def icon(self):
+        """Returns a toggle icon including settings for json url."""
+        icon = zope.component.queryMultiAdapter((self.context, self.request), 
+            name=self.iconName)
+        if icon is not None:
+            resource = getResource(icon.context, icon.rname, self.request)
+            src = resource()
+            longDescURL = absoluteURL(self.context, self.request)
+            return ('<img src="%s" alt="toggle icon" width="%s" height="%s" ' 
+                    'border="0" />' % (src, icon.width, icon.height))
+        return u''
+
+    @property
+    def name(self):
+        return api.getName(self.context)
+
+    @property
+    def url(self):
+        return absoluteURL(self.context, self.request) +'/'+ self.viewName
+
+    def update(self):
+        pass
+
+    def render(self):
+        template = zope.component.getMultiAdapter((self, self.request), 
+            IPageTemplate)
+        return template(self)
+

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/__init__.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/__init__.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/__init__.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+
+from zope.viewlet import viewlet
+
+
+JSONTreeCSSViewlet = viewlet.CSSViewlet('jsontree.css')
+JSONTreeJavaScriptViewlet = viewlet.JavaScriptViewlet('jsontree.js')

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/configure.zcml
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/configure.zcml	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/configure.zcml	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,62 @@
+<configure 
+    xmlns:zope="http://namespaces.zope.org/zope"
+    xmlns="http://namespaces.zope.org/browser"
+    xmlns:z3c="http://namespaces.zope.org/z3c"
+    i18n_domain="jquery">
+
+  <!-- provider and template for content providers -->
+  <zope:adapter
+      name="tree"
+      factory=".tree.TreeProvider"
+      />
+  <z3c:template
+      template="tree.pt"
+      for="jquery.jsontree.interfaces.ITreeProvider"
+      layer="zope.publisher.interfaces.browser.IBrowserRequest"
+      />
+
+  <zope:adapter
+      name="li"
+      factory=".tree.LITagProvider"
+      />
+  <z3c:template
+      template="li.pt"
+      for="jquery.jsontree.interfaces.ILITagProvider"
+      layer="zope.publisher.interfaces.browser.IBrowserRequest"
+      />
+
+  <zope:adapter
+      name="ul"
+      factory=".tree.ULTagProvider"
+      />
+  <z3c:template
+      template="ul.pt"
+      for="jquery.jsontree.interfaces.IULTagProvider"
+      layer="zope.publisher.interfaces.browser.IBrowserRequest"
+      />
+
+
+  <!-- default icons -->
+  <icon
+      name="jsonTreeCollapsedIcon"
+      for="zope.interface.Interface"
+      file="img/jsonTreeCollapsed.gif"
+      layer="zope.publisher.interfaces.browser.IBrowserRequest"
+      />
+
+  <icon
+      name="jsonTreeExpandedIcon"
+      for="zope.interface.Interface"
+      file="img/jsonTreeExpanded.gif"
+      layer="zope.publisher.interfaces.browser.IBrowserRequest"
+      />
+
+  <icon
+      name="jsonTreeStaticIcon"
+      for="zope.interface.Interface"
+      file="img/jsonTreeStatic.gif"
+      layer="zope.publisher.interfaces.browser.IBrowserRequest"
+      />
+
+
+</configure>
\ No newline at end of file

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeCollapsed.gif
===================================================================
(Binary files differ)


Property changes on: jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeCollapsed.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeExpanded.gif
===================================================================
(Binary files differ)


Property changes on: jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeExpanded.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeStatic.gif
===================================================================
(Binary files differ)


Property changes on: jquery.jsontree/trunk/src/jquery/jsontree/browser/img/jsonTreeStatic.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.css
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.css	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.css	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,42 @@
+
+ul.jsonTree {
+    list-style-type: none;
+    margin: 0px;
+    padding: 0px;
+} 
+
+ul.jsonTree ul {
+    margin-left: 12px;
+    padding: 0px;
+}
+
+ul.jsonTree li {
+    list-style: none;
+    white-space: nowrap;
+    margin: 0px;
+    padding: 0px;
+}
+
+ul.jsonTree img {
+    height: 16px;
+}
+
+ul.jsonTree a {
+    text-decoration: none;
+}
+
+ul.jsonTree .jsonTreeIcon {
+    cursor: pointer;
+}
+
+ul.jsonTree li.jsonTreeItem .jsonTreeIcon {
+    cursor: default;
+}
+
+ul.jsonTree li.jsonTreeExpanded ul {
+    display: block;
+}
+
+ul.jsonTree li.jsonTreeCollapsed ul {
+    display: none;
+}

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.js
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.js	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/jsontree.js	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,159 @@
+//----------------------------------------------------------------------------
+/** 
+ * @fileoverview JSON supported unordered list based tree 
+ * 
+ * @author Roger Ineichen dev at projekt01 dot org.
+ * @version Initial, not documented 
+ */
+//----------------------------------------------------------------------------
+/* zrt-replace: "./jsonTreeIMG" tal"string:${context/++resource++jsonTreeIMG}" */
+
+/* TODO: use metadata plugin for get/set the json loader uri */
+
+//----------------------------------------------------------------------------
+// public API
+//----------------------------------------------------------------------------
+
+
+(function($) {
+$.fn.jsonTree = function (settings) {
+	settings = $.extend({
+        jsonTreeCollapsedGif: './jsonTreeIMG/jsonTreeCollapsed.gif',
+        jsonTreeExpandedGif: './jsonTreeIMG/jsonTreeExpanded.gif',
+        jsonTreeStaticGif: './jsonTreeIMG/jsonTreeStatic.gif',
+        jsonTreeCollapsedClass: 'jsonTreeCollapsed',
+        jsonTreeExpandedClass: 'jsonTreeExpanded',
+        jsonTreeStaticClass: 'jsonTreeItem',
+        jsonTreeIconClass: 'jsonTreeIcon',
+        loadItemsMethodName: 'loadJSONTreeItems'
+	}, settings);
+
+    function jsonTreeToggleItem(img) {
+        ele = img.parentNode;
+        var uri = $(img).attr('longDesc');
+        if ($.className.has(ele, settings.jsonTreeExpandedClass)) {
+            ele.className = settings.jsonTreeCollapsedClass;
+            $(img).attr("src", settings.jsonTreeCollapsedGif);
+        }
+        else {
+            /* check for sub items */
+            if ($(ele).find('li').length == 0){
+                /* load childs from server via JSON */
+                id = $(ele).attr('id');
+                jsonTreeLoadItems(uri, id);
+            }
+            ele.className = settings.jsonTreeExpandedClass;
+            $(img).attr("src", settings.jsonTreeExpandedGif);
+        }
+        return false;
+    }
+
+    function jsonTreeLoadItems(uri, id) {
+        /* each different json tree uses a own function for calling the childs */
+        loader = settings.loadItemsMethodName;
+    	var jsonProxy = new JSONRPC(uri);
+    	jsonProxy.addMethod(loader, jsonTreeAddItems, id);
+        /* call the child loader method */
+        var loaderMethod = jsonProxy[loader];
+    	loaderMethod(id);
+    }
+    
+    function jsonTreeAddItems(response, requestId) {
+        var res = response['treeChilds'];
+        var childs = res['childs'];
+        ele = document.getElementById(res['id']);
+        var ele = $(ele);
+        var ul = null;
+        
+        /* find ul tag which will contain the new childs */
+        var ul = ele.find('ul')[0]
+        if (!ul){
+            ele.append('<ul></ul>')
+        }
+        var ul = ele.find('ul')[0]
+        
+        /* render and append the new childs to the existing empty <ul> tag */
+        for (var i=0; i<childs.length; i++) {
+            var itemInfo = childs[i];
+            var iconSrc = itemInfo['iconURL'];
+            var hasChilds = itemInfo['hasChilds'];
+            var linkHandler = itemInfo['linkHandler'];
+            var contextURL = itemInfo['contextURL'];
+
+            /* create toggle icon */
+            if (iconSrc != '') {
+                var icon = $('<img></img>');
+                icon.attr("src", iconSrc);
+            }
+            /* create li tag */
+            var li = $('<li></li>');
+            li.attr("id", itemInfo['id']);
+
+            /* create toggle image */
+            var img = $('<img></img>');;
+            img.attr("width", "16");
+            img.attr("height", "16");
+            if (hasChilds) {
+                img.className = settings.jsonTreeIconClass;
+                img.attr('longDesc', contextURL);
+                img.click(function(){
+                    jsonTreeToggleItem(this)
+                });
+                img.attr("src", settings.jsonTreeCollapsedGif);
+                li.className = settings.jsonTreeCollapsedClass;
+            }
+            else{
+                li.className = settings.jsonTreeStaticClass;
+                img.attr("src", settings.jsonTreeStaticGif);
+            }
+            /* create link or handler */
+            var a = $('<a href=""></a>');
+            if (linkHandler != '') {
+                a.click(eval(linkHandler));
+                a.attr("href", '#');
+            }else {
+                a.attr("href", itemInfo['url']);
+            }
+            /* append content to link */
+            a.html(itemInfo['content']);
+            li.append(a);
+            /* append link to  to link */
+            if (iconSrc != '') {
+                icon.insertBefore(a);
+                img.insertBefore(icon);
+            }
+            else {
+                img.insertBefore(a);
+            }
+            $(ul).append(li);
+        }
+    }
+
+    // render tree
+    function renderTree(ul) {
+        if ($(ul).length == 0) {
+            return;
+        }
+        for (var i=0; i<ul.childNodes.length; i++) {
+            var item = ul.childNodes[i];
+            if (item.nodeName == "LI") {
+                for (var si=0; si<item.childNodes.length; si++) {
+                    var subitem = item.childNodes[si];
+                    if (subitem.nodeName == "UL") {
+                        renderTree(subitem, false);
+                    }
+                }
+                img = $(item.firstChild);
+                img.click(function(){
+                    jsonTreeToggleItem(this)
+                });
+            }
+        }
+    }
+
+    // initialize json trees
+    return $(this).each(function(){
+        renderTree(this);
+    });
+};
+})(jQuery);

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/li.pt
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/li.pt	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/li.pt	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,11 @@
+<li id="" class=""
+    tal:attributes="id view/id;
+                    class view/className"
+  ><img src="" width="16" height="16"
+       tal:replace="structure view/toggleIcon" 
+  /><img src="" width="16" height="16"
+       tal:replace="structure view/icon" 
+  /><a href=""
+     tal:attributes="href view/url"
+     tal:content="structure view/name"></a>
+</li>

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/tests.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/tests.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/tests.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,85 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import unittest
+
+import zope.component
+import zope.app.security
+from zope.app.component import hooks
+from zope.configuration.xmlconfig import XMLConfig
+from zope.pagetemplate.tests.util import check_xml
+from zope.publisher.browser import TestRequest
+from zope.app.component import testing
+
+from z3c.testing import TestCase
+from jquery.jsontree.tests import util
+from jquery.jsontree.browser import tree
+
+
+class TestView(tree.SimpleJSONTree):
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+
+class TestJSONTreeView(testing.PlacefulSetup, TestCase):
+
+    def setUp(self):
+        testing.PlacefulSetup.setUp(self, site=True)
+        self.rootFolder.__name__ = 'rootFolder'
+        hooks.setSite(self.rootFolder)
+        import zope.app.publication
+        import zope.app.publisher.browser
+        import z3c.template
+        import jquery.jsontree
+        import zif.jsonserver
+        XMLConfig('meta.zcml', zope.component)()
+        XMLConfig('meta.zcml', zope.app.security)()
+        XMLConfig('meta.zcml', zope.app.publication)()
+        XMLConfig('meta.zcml', zope.app.publisher.browser)()
+        XMLConfig('meta.zcml', z3c.template)()
+        XMLConfig('meta.zcml', zif.jsonserver)()
+        XMLConfig('configure.zcml', jquery.jsontree)()
+
+    def test_getTree_folder1(self):
+        context = self.rootFolder['folder1']
+        request = TestRequest()
+        view = TestView(context, request)
+        view.update()
+        ultree = view.tree
+        check_xml(ultree, util.read_output('tree_1.xml'))
+
+    def test_getTree_folder2_1_1(self):
+        """This test includes cyrillic letters."""
+        context = self.rootFolder['folder2']['folder2_1']['folder2_1_1']
+        request = TestRequest()
+        view = TestView(context, request)
+        view.update()
+        ultree = view.tree
+        check_xml(ultree, util.read_output('tree_2.xml'))
+
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(TestJSONTreeView),
+        ))
+
+
+if __name__=='__main__':
+    unittest.main(defaultTest='test_suite')

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.pt
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.pt	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.pt	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,20 @@
+<ul class="" id="" name=""
+    tal:attributes="id view/jsonTreeId;
+                    class view/jsonTreeClass;
+                    name view/jsonTreeName">
+  <li id="" class=""
+      tal:define="childTags view/childTags"
+      tal:attributes="id view/id;
+                      class view/className"
+    ><img src="" width="16" height="16"
+         tal:replace="structure view/toggleIcon" 
+    /><img src="" width="16" height="16"
+         tal:replace="structure view/icon" 
+    /><a href=""
+       tal:attributes="href view/url"
+       tal:content="structure view/name"></a>
+    <ul tal:condition="childTags"
+        tal:content="structure childTags">
+    </ul>
+  </li>
+</ul>

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/tree.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,131 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.interface
+import zope.component
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.traversing import api
+from zope.traversing.browser import absoluteURL
+from zope.viewlet.interfaces import IViewlet
+from zope.contentprovider.interfaces import IContentProvider
+from zope.app.container.interfaces import IReadContainer
+from zope.app.intid.interfaces import IIntIds
+from z3c.template.template import getPageTemplate
+
+from jquery.jsontree import interfaces
+from jquery.jsontree.interfaces import JSON_TREE_ID
+from jquery.jsontree import base
+
+
+# simple trees
+class SimpleJSONTree(base.TreeBase, base.PythonRendererMixin, 
+    base.IdGeneratorMixin):
+    """Simple JSON tree using inline methods for rendering elements and
+    using traversable path for item lookup.
+    """
+
+    zope.interface.implements(interfaces.ISimpleJSONTree)
+
+    def update(self):
+        super(SimpleJSONTree, self).update()
+
+
+# simple tree viewlet
+class SimpleJSONTreeViewlet(SimpleJSONTree):
+    """Simple JSON tree viewlet."""
+
+    zope.interface.implements(IViewlet)
+
+    def __init__(self, context, request, view, manager):
+        super(SimpleJSONTreeViewlet, self).__init__(context, request)
+        self.__parent__ = view
+        self.context = context
+        self.request = request
+        self.manager = manager
+
+
+# generic template based tree
+class LITagProvider(base.ProviderBase, base.IdGeneratorMixin):
+    """LI tag content provider."""
+
+    zope.interface.implements(interfaces.ILITagProvider)
+    zope.component.adapts(zope.interface.Interface, IBrowserRequest, 
+        interfaces.ITemplateRenderer)
+
+    jsonTreeId = JSON_TREE_ID
+
+
+class ULTagProvider(base.ProviderBase, base.IdGeneratorMixin):
+    """UL tag contet provider."""
+
+    zope.interface.implements(interfaces.IULTagProvider)
+    zope.component.adapts(zope.interface.Interface, IBrowserRequest, 
+        interfaces.ITemplateRenderer)
+
+    childTags = None
+
+    jsonTreeId = JSON_TREE_ID
+
+
+class TreeProvider(base.ProviderBase, base.IdGeneratorMixin):
+    """UL tag contet provider."""
+
+    zope.interface.implements(interfaces.ITreeProvider)
+    zope.component.adapts(zope.interface.Interface, IBrowserRequest, 
+        interfaces.ITemplateRenderer)
+
+    # provider id, class and name
+    jsonTreeId = JSON_TREE_ID
+    jsonTreeClass = JSON_TREE_ID
+    jsonTreeName = JSON_TREE_ID
+    childTags = None
+
+
+class GenericJSONTree(base.TreeBase, base.TemplateRendererMixin, 
+    base.IdGeneratorMixin):
+    """IntId base object lookup and template base rendering.
+    
+    This implementation uses IContentProvider for element tag rendering.
+    This content provider are resonsible for represent a node. This allows us 
+    to embed html or javascript calls in the html representation in a smart 
+    way.
+    """
+
+    zope.interface.implements(interfaces.IGenericJSONTree)
+
+    liProviderName = 'li'
+    ulProviderName = 'ul'
+    treeProviderName = 'tree'
+
+    def update(self):
+        super(GenericJSONTree, self).update()
+
+
+# generic tree viewlet
+class GenericJSONTreeViewlet(GenericJSONTree):
+    """Generic JSON tree viewlet."""
+
+    zope.interface.implements(IViewlet)
+
+    def __init__(self, context, request, view, manager):
+        super(GenericJSONTreeViewlet, self).__init__(context, request)
+        self.__parent__ = view
+        self.context = context
+        self.request = request
+        self.manager = manager

Added: jquery.jsontree/trunk/src/jquery/jsontree/browser/ul.pt
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/browser/ul.pt	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/browser/ul.pt	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,15 @@
+<li id="" class=""
+    tal:define="childTags view/childTags"
+    tal:attributes="id view/id;
+                    class view/className"
+  ><img src="" width="16" height="16"
+       tal:replace="structure view/toggleIcon" 
+  /><img src="" width="16" height="16"
+       tal:replace="structure view/icon" 
+  /><a href=""
+     tal:attributes="href view/url"
+     tal:content="structure view/name"></a>
+  <ul tal:condition="childTags"
+      tal:content="structure childTags">
+  </ul>
+</li>

Added: jquery.jsontree/trunk/src/jquery/jsontree/configure.zcml
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/configure.zcml	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/configure.zcml	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,16 @@
+<configure 
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:jsonrpc="http://namespaces.zope.org/jsonrpc"
+    i18n_domain="jquery">
+
+  <include package=".browser" />
+
+  <!-- this method only returns what the user has permission for -->
+  <jsonrpc:view
+      for="*"
+      class="jquery.jsontree.json.JSONTreeItems"
+      permission="zope.Public"
+      methods="loadJSONTreeItems"
+      />
+
+</configure>
\ No newline at end of file

Added: jquery.jsontree/trunk/src/jquery/jsontree/interfaces.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/interfaces.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/interfaces.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,164 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.interface
+from zope.contentprovider.interfaces import IContentProvider
+
+# DOM id and name for json tree ``<UL>`` tag
+JSON_TREE_ID = u'jsonTree'
+JSON_TREE_VIEW_NAME = u'@@SelectedManagementView.html'
+
+JSON_TOGGLE_ICON_COLLAPSED = 'jsonTreeCollapsedIcon'
+JSON_TOGGLE_ICON_EXPANDED = 'jsonTreeExpandedIcon'
+JSON_TOGGLE_ICON_STATIC = 'jsonTreeStaticIcon'
+
+JSON_LI_CSS_EXPANDED = u'jsonTreeExpanded'
+JSON_LI_CSS_COLLAPSED = u'jsonTreeCollapsed'
+JSON_LI_CSS_STATIC = u'jsonTreeStatic'
+
+STATE_EXPANDED = 'expanded'
+STATE_COLLAPSED = 'collapsed'
+STATE_STATIC = 'static'
+
+
+class IDOMContentProvider(IContentProvider):
+
+    state = zope.interface.Attribute(
+        """The collapsed, expanded or static state .""")
+
+    childTags = zope.interface.Attribute(
+        """A list of rendered child tags.""")
+
+    viewName = zope.interface.Attribute(
+        """The view name which get called on the context.""")
+
+    collapsedCSSName = zope.interface.Attribute(
+        """Class name for the collapsed <LI> tag.""")
+    expandedCSSName = zope.interface.Attribute(
+        """Class name for the expanded <LI> tag.""")
+    staticCSSName = zope.interface.Attribute(
+        """Class name for the static <LI> tag.""")
+
+    # context icon
+    iconName = zope.interface.Attribute(
+        """The icon name for the context icon.""")
+
+    # toggle icon
+    collapsedIconName = zope.interface.Attribute(
+        """The icon name for the collapsed icon.""")
+    expandedIconNamen = zope.interface.Attribute(
+        """The icon name for the expanded icon.""")
+    staticIconName = zope.interface.Attribute(
+        """The icon name for the static icon.""")
+
+    # properties
+    className = zope.interface.Attribute(
+        """The CSS class name for the rendered <LI> tag.""")
+
+    toggleIcon = zope.interface.Attribute(
+        """The toggle icon including settings for json url.""")
+
+    icon = zope.interface.Attribute("""The icon for the given context.""")
+
+    name = zope.interface.Attribute("""The context name""")
+
+    url = zope.interface.Attribute("""The context url""")
+
+    def update():
+        """Must get called before render."""
+
+    def render():
+        """Render the template."""
+
+
+# content provider using templates
+class ILITagProvider(IDOMContentProvider):
+    """Content provider for ``LI`` tag."""
+
+
+class IULTagProvider(IDOMContentProvider):
+    """Content provider for ``UL`` tag."""
+
+
+class ITreeProvider(IDOMContentProvider):
+    """Content provider for tree (main) ``UL`` tag."""
+
+
+# tree renderer interfaces
+class ITreeRenderer(zope.interface.Interface):
+    """Knows how to render elements fo the tree items."""
+
+    def renderLI(item):
+        """Renders <LI> tags."""
+
+    def renderUL(item, childTags=None):
+        """Renders <li> tag including rendered child tags."""
+
+    tree = zope.interface.Attribute(
+        """Renders <ul> tree tag including rendered child tags.""")
+
+
+class IPythonRenderer(ITreeRenderer):
+    """Uses python methods for rendering the tree items."""
+
+
+class ITemplateRenderer(ITreeRenderer):
+    """Uses IContentProvider classes within templates for rendereing the items.
+    """
+
+
+class IIdGenerator(zope.interface.Interface):
+    """Knows how to get ids for the tree items."""
+
+    def getId(item):
+        """Returns the DOM id for a given object.
+
+        Note: we encode the upper case letters because the Dom element id are 
+        not case sensitive in HTML. We prefix each upper case letter with ':'.
+        """
+
+    def id():
+        """Returns the DOM id for a given context."""
+
+
+class IJSONTree(ITreeRenderer, IIdGenerator):
+    """Complete JSON tree definition.
+    
+    Don't care about the javascript part, just implement all methods define in 
+    this interfaces.
+    """
+
+
+class ISimpleJSONTree(IJSONTree):
+    """Simple JSON tree implementation.
+    
+    Simple JSON tree using inline methods for rendering elements and
+    traversable path for item lookup.
+    """
+
+
+class IGenericJSONTree(IJSONTree):
+    """Generic JSON tree implementation.
+    
+    IntId base object lookup and template base rendering.
+    
+    This implementation uses IContentProvider for element tag rendering.
+    This content provider are resonsible for represent a node. This allows us 
+    to embed html or javascript calls in the html representation in a smart 
+    way.
+    """

Added: jquery.jsontree/trunk/src/jquery/jsontree/jquery.jsontree-configure.zcml
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/jquery.jsontree-configure.zcml	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/jquery.jsontree-configure.zcml	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1 @@
+<include package="jquery.jsontree" />

Added: jquery.jsontree/trunk/src/jquery/jsontree/json.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/json.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/json.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+from zope.traversing import api
+from zope.traversing.browser import absoluteURL
+from zope.app.container.interfaces import IReadContainer
+from zope.app.intid.interfaces import IIntIds
+
+from zif.jsonserver.jsonrpc import MethodPublisher
+
+from jquery.jsontree import interfaces
+from jquery.jsontree.interfaces import JSON_TREE_ID
+from jquery.jsontree.interfaces import JSON_TREE_VIEW_NAME
+from jquery.jsontree import base
+from jquery.jsontree import util
+
+
+class JSONTreeItems(MethodPublisher, base.IdGeneratorMixin):
+    """Returns the data of the childs from the path for the json tree.
+    
+    This is a simple implementation which uses the traversal concept.
+    If you need to lookup items for other conponents then ocntianers,
+    e.g. for a widget, you need to implement your own child loader class.
+    """
+
+    viewName = JSON_TREE_VIEW_NAME
+    jsonTreeId = JSON_TREE_ID
+    linkHandler = ''
+
+    @property
+    def subItems(self):
+        """Returns a list of items for the given context."""
+        items = []
+        keys = []
+        append = items.append
+        if IReadContainer.providedBy(self.context):
+            try:
+                keys = list(self.context.keys())
+            except(Unauthorized, Forbidden):
+                return items
+        for name in keys:
+            # Only include items we can traverse to
+            subItem = api.traverse(self.context, name, None)
+            if subItem is not None:
+                append(subItem)
+        return items
+
+    def hasSubItems(self, item):
+        """Returns a True or False if the sub item has subitems."""
+        res = False
+        if IReadContainer.providedBy(item):
+            try:
+                if len(item) > 0:
+                    res = True
+            except(Unauthorized, Forbidden):
+                pass
+        return res
+
+    def getIconURL(self, item, request, name='icon'):
+        return util.getIconURL(item, request, name=name)
+
+    def loadJSONTreeItems(self, id):
+        """Returns child information for the object with the given path in a 
+           JSON format.
+
+        """
+        res = {}
+        childs = []
+        append = childs.append
+
+        for subItem in self.subItems:
+
+            if self.hasSubItems(subItem):
+                hasChilds = True
+            else:
+                hasChilds = False
+
+            info = {}
+            url = absoluteURL(subItem, self.request)
+            info['id'] = self.getId(subItem)
+            info['content'] = api.getName(subItem)
+            info['url'] = url +'/'+ self.viewName
+            info['iconURL'] = util.getIconURL(subItem, self.request)
+            info['linkHandler'] = self.linkHandler
+            info['hasChilds'] = hasChilds
+            info['contextURL'] = url
+            append(info)
+        
+        res['treeChilds'] = {'id':id, 'childs':childs}
+        
+        return res

Added: jquery.jsontree/trunk/src/jquery/jsontree/tests/__init__.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/tests/__init__.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/tests/__init__.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""

Added: jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_1.xml
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_1.xml	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_1.xml	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1 @@
+<ul class="jsonTree" id="jsonTree" name="jsonTree"><li id="jsonTree.." class="jsonTreeExpanded"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeExpandedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder1" /><a href="http://127.0.0.1/rootFolder/@@SelectedManagementView.html"></a><ul><li id="jsonTree.::folder1" class="jsonTreeCollapsed"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeCollapsedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder1" /><a href="http://127.0.0.1/rootFolder/folder1/@@SelectedManagementView.html">folder1</a><ul></ul></li><li id="jsonTree.::folder2" class="jsonTreeCollapsed"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeCollapsedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder2" /><a href="http://127.0.0.1/rootFolder/folder2/@@SelectedManagementView.html">folder2</a><ul></ul></li><li id="jsonTree.::папка3" class="jsonTreeCollapsed"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeCollapsedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/%D0%BF%D0%B0%D0%BF%D0%BA%D0%B03" /><a href="http://127.0.0.1/rootFolder/%D0%BF%D0%B0%D0%BF%D0%BA%D0%B03/@@SelectedManagementView.html">папка3</a><ul></ul></li></ul></li></ul>

Added: jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_2.xml
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_2.xml	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/tests/output/tree_2.xml	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1 @@
+<ul class="jsonTree" id="jsonTree" name="jsonTree"><li id="jsonTree.." class="jsonTreeExpanded"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeExpandedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder2/folder2_1/folder2_1_1" /><a href="http://127.0.0.1/rootFolder/@@SelectedManagementView.html"></a><ul><li id="jsonTree.::folder1" class="jsonTreeCollapsed"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeCollapsedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder1" /><a href="http://127.0.0.1/rootFolder/folder1/@@SelectedManagementView.html">folder1</a><ul></ul></li><li id="jsonTree.::folder2" class="jsonTreeExpanded"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeExpandedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder2" /><a href="http://127.0.0.1/rootFolder/folder2/@@SelectedManagementView.html">folder2</a><ul><li id="jsonTree.::folder2::folder2_1" class="jsonTreeExpanded"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeExpandedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder2/folder2_1" /><a href="http://127.0.0.1/rootFolder/folder2/folder2_1/@@SelectedManagementView.html">folder2_1</a><ul><li id="jsonTree.::folder2::folder2_1::folder2_1_1" class="jsonTreeItem"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeStaticIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/folder2/folder2_1/folder2_1_1" /><a href="http://127.0.0.1/rootFolder/folder2/folder2_1/folder2_1_1/@@SelectedManagementView.html">folder2_1_1</a></li></ul></li></ul></li><li id="jsonTree.::папка3" class="jsonTreeCollapsed"><img src="http://127.0.0.1/rootFolder/@@/zope-interface-Interface-jsonTreeCollapsedIcon.gif" alt="toggle icon" width="16" height="16" border="0" longDesc="http://127.0.0.1/rootFolder/%D0%BF%D0%B0%D0%BF%D0%BA%D0%B03" /><a href="http://127.0.0.1/rootFolder/%D0%BF%D0%B0%D0%BF%D0%BA%D0%B03/@@SelectedManagementView.html">папка3</a><ul></ul></li></ul></li></ul>
\ No newline at end of file

Added: jquery.jsontree/trunk/src/jquery/jsontree/tests/util.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/tests/util.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/tests/util.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import os
+
+def read_output(filename):
+    import jquery.jsontree.tests
+    dir = os.path.dirname(jquery.jsontree.tests.__file__)
+    output_dir = os.path.join(dir, 'output')
+    filename = os.path.join(output_dir, filename)
+    return open(filename, 'r').read().decode("utf-8")

Added: jquery.jsontree/trunk/src/jquery/jsontree/util.py
===================================================================
--- jquery.jsontree/trunk/src/jquery/jsontree/util.py	                        (rev 0)
+++ jquery.jsontree/trunk/src/jquery/jsontree/util.py	2007-06-11 20:15:25 UTC (rev 76625)
@@ -0,0 +1,70 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = 'restructuredtext'
+
+import zope.component
+from zope.traversing import api
+from zope.proxy import sameProxiedObjects
+from zope.traversing.interfaces import TraversalError
+
+
+def getIconURL(item, request, name='icon'):
+    url = ''
+    icon = zope.component.queryMultiAdapter((item, request), name=name)
+    if icon is not None:
+        try:
+            url = icon.url()
+        except TraversalError:
+            return url
+    return url
+
+
+def isChildOf(child, parent):
+    """Check if object is a child of the parent."""
+    if parent in api.getParents(child):
+        return True
+    else:
+        return False
+
+
+def getParentsFromContextToObject(context, obj):
+    """Returns a list starting with the given context's parent followed by
+    each of its parents till we reach the object.
+
+    If the child object is not a child of the parent a empty list
+    will return.
+    """
+    if not isChildOf(context, obj):
+        return []
+    
+    if sameProxiedObjects(context, obj):
+        return []
+
+    parents = []
+    w = context
+
+    while 1:
+        w = w.__parent__
+        if sameProxiedObjects(w, obj):
+            parents.append(w)
+            break
+        if w is None:
+            break
+        
+        parents.append(w)
+
+    return parents



More information about the Checkins mailing list