[Checkins] SVN: z3c.listjs/ Initial import.

Martijn Faassen faassen at infrae.com
Tue Jan 6 15:36:22 EST 2009


Log message for revision 94552:
  Initial import.
  

Changed:
  A   z3c.listjs/
  A   z3c.listjs/trunk/
  A   z3c.listjs/trunk/CHANGES.txt
  A   z3c.listjs/trunk/buildout.cfg
  A   z3c.listjs/trunk/setup.py
  A   z3c.listjs/trunk/src/
  A   z3c.listjs/trunk/src/z3c/
  A   z3c.listjs/trunk/src/z3c/__init__.py
  A   z3c.listjs/trunk/src/z3c/listjs/
  A   z3c.listjs/trunk/src/z3c/listjs/__init__.py
  A   z3c.listjs/trunk/src/z3c/listjs/configure.zcml
  A   z3c.listjs/trunk/src/z3c/listjs/ftesting.zcml
  A   z3c.listjs/trunk/src/z3c/listjs/ftests.py
  A   z3c.listjs/trunk/src/z3c/listjs/listjswidget.pt
  A   z3c.listjs/trunk/src/z3c/listjs/listjswidget_record.pt
  A   z3c.listjs/trunk/src/z3c/listjs/resources/
  A   z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js
  A   z3c.listjs/trunk/src/z3c/listjs/testing.py
  A   z3c.listjs/trunk/src/z3c/listjs/widget.py

-=-
Added: z3c.listjs/trunk/CHANGES.txt
===================================================================
--- z3c.listjs/trunk/CHANGES.txt	                        (rev 0)
+++ z3c.listjs/trunk/CHANGES.txt	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,7 @@
+CHANGES
+*******
+
+0.1 (unreleased)
+================
+
+* Initial public release.

Added: z3c.listjs/trunk/buildout.cfg
===================================================================
--- z3c.listjs/trunk/buildout.cfg	                        (rev 0)
+++ z3c.listjs/trunk/buildout.cfg	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,12 @@
+[buildout]
+develop = . 
+parts = test
+extends = http://grok.zope.org/releaseinfo/grok-0.14.cfg
+versions = versions
+
+[versions]
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.listjs
+defaults = ['--tests-pattern', '^f?tests$', '-v']

Added: z3c.listjs/trunk/setup.py
===================================================================
--- z3c.listjs/trunk/setup.py	                        (rev 0)
+++ z3c.listjs/trunk/setup.py	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,30 @@
+from setuptools import setup, find_packages
+import sys, os
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(
+    name='z3c.listjs',
+    version='0.1dev',
+    description="A formlib list widget that uses Javascript",
+    classifiers=[],
+    keywords='',
+    author='Martijn Faassen',
+    author_email='faassen at startifact.com',
+    license='',
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
+    namespace_packages=['z3c'],
+    include_package_data=True,
+    zip_safe=False,
+    install_requires=[
+        'setuptools',
+        'zope.schema',
+        'zope.app.form',
+        'grokcore.component',
+        'hurry.resource',
+        'hurry.zoperesource >= 0.3',
+        ],
+    entry_points={},
+    )

Added: z3c.listjs/trunk/src/z3c/__init__.py
===================================================================
--- z3c.listjs/trunk/src/z3c/__init__.py	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/__init__.py	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: z3c.listjs/trunk/src/z3c/listjs/__init__.py
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/__init__.py	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/__init__.py	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1 @@
+from z3c.listjs.widget import ListJsWidget

Added: z3c.listjs/trunk/src/z3c/listjs/configure.zcml
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/configure.zcml	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/configure.zcml	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,11 @@
+<configure
+  xmlns="http://namespaces.zope.org/zope"
+  xmlns:browser="http://namespaces.zope.org/browser">
+
+  <include package="hurry.zoperesource" />
+
+  <browser:resourceDirectory 
+      name="z3c.listjs"
+      directory="resources" />
+  
+</configure>

Added: z3c.listjs/trunk/src/z3c/listjs/ftesting.zcml
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/ftesting.zcml	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/ftesting.zcml	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,38 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   i18n_domain="z3c.listjs"
+   package="z3c.listjs"
+   >
+
+  <include package="zope.app.zcmlfiles" file="meta.zcml" />
+  <include package="zope.securitypolicy" file="meta.zcml" />
+
+  <include package="zope.app.zcmlfiles" />
+  <include package="zope.app.authentication" />
+
+  <include package="z3c.listjs" />
+
+  <!-- Typical functional testing security setup -->
+  <securityPolicy
+      component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy"
+      />
+
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User"
+      />
+  <grant
+      permission="zope.View"
+      principal="zope.anybody"
+      />
+  <principal
+      id="zope.mgr"
+      title="Manager"
+      login="mgr"
+      password="mgrpw"
+      />
+
+  <role id="zope.Manager" title="Site Manager" />
+  <grantAll role="zope.Manager" />
+  <grant role="zope.Manager" principal="zope.mgr" />
+</configure>

Added: z3c.listjs/trunk/src/z3c/listjs/ftests.py
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/ftests.py	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/ftests.py	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,19 @@
+import unittest
+
+from zope.app.testing.setup import setUpTestAsModule, tearDownTestAsModule
+from zope.app.testing.functional import FunctionalDocFileSuite
+from z3c.listjs.testing import FunctionalLayer
+
+def setUp(test):
+    setUpTestAsModule(test, name='__builtin__')
+
+def test_suite():
+    globs = {}
+#     readme = FunctionalDocFileSuite(
+#         'README.txt',
+#         globs = globs,
+#         setUp=setUp,
+#         tearDown=tearDownTestAsModule,
+#         )
+    readme.layer = FunctionalLayer
+    return unittest.TestSuite([readme])

Added: z3c.listjs/trunk/src/z3c/listjs/listjswidget.pt
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/listjswidget.pt	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/listjswidget.pt	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,35 @@
+<table border="0" class="sequencewidget" 
+  tal:attributes="id string:${view/name}.table"
+  i18n:domain="zope">
+  <tr tal:repeat="widget view/widgets" class="list_item">
+    <td>
+      <input class="editcheck" type="checkbox"
+             tal:attributes="
+                 name string:${view/name}.remove_${repeat/widget/index}"
+             tal:condition="view/need_delete" />
+    </td>
+    <td>
+      <span tal:define="error widget/error"
+            tal:replace="structure error" tal:condition="error" />
+      <input tal:replace="structure widget" />
+    </td>
+  </tr>
+  <tr tal:attributes="id string:${view/name}.buttons">
+    <td colspan="2">
+      <input type="button" value="Remove selected items"
+             tal:attributes="name string:${view/name}.remove;
+                             onClick string:Z3C.listjs.remove('${view/name}')"
+             i18n:attributes="value remove-selected-items" />
+      <input type="button" value="Add foo"
+             tal:attributes="name string:${view/name}.add;
+                             value view/addButtonLabel;
+                             onClick string:Z3C.listjs.add('${view/name}')"
+             />
+    </td>
+  </tr>
+</table>
+<input type="hidden" tal:attributes="
+            name string:${view/name}.template;
+            id string:${view/name}.template;
+            value view/record_template" />
+<input tal:replace="structure view/marker" />

Added: z3c.listjs/trunk/src/z3c/listjs/listjswidget_record.pt
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/listjswidget_record.pt	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/listjswidget_record.pt	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,9 @@
+    <td>
+      <input class="editcheck" type="checkbox"
+             tal:attributes="
+                 name string:${view/name}.remove_0" />
+    </td>
+    <td>
+      <input tal:replace="structure view/widgetTemplate" />
+    </td>
+

Added: z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/resources/listjs.js	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,145 @@
+// create the top-level Z3C namespace if needed
+if (typeof Z3C == "undefined" || !Z3C) {
+    var Z3C = {};
+}
+
+// create a new namespace (under Z3C)
+Z3C.namespace = function(name) {
+    var ns = Z3C;
+    var parts = name.split(".");
+    if (parts[0] == "Z3C") {
+        parts = parts.slice(1);
+    }
+    for (var i = 0; i < parts.length; i++) {
+        var part = parts[i];
+        ns[part] = ns[part] || {};
+        ns = ns[part];
+    }
+    return ns;
+};
+
+(function() {
+    Z3C.namespace('listjs');
+        
+    // return true if string starts with a prefix
+    var startswith = function(s, prefix) {
+        return (s.substring(0, prefix.length) == prefix);
+    };
+
+    // check whether a particular object is a number
+    var isNumber = function(o) {
+        return typeof o === 'number' && isFinite(o);
+    };
+
+    // change all numbers in a string with a dotted name to a new number
+    // also renumber remove_X
+    var renumber = function(s, nr) {
+        var i;
+        var fragment;
+        var fragments = s.split('.');
+        var result = [];
+        for (i = 0; i < fragments.length; i++ ) {
+            fragment = fragments[i];
+            if (isNumber(parseInt(fragment))) {
+                result[result.length] = nr.toString();
+            } else if (startswith(fragment, 'remove_')) {
+                result[result.length] = 'remove_' + nr.toString();
+            } else {
+                result[result.length] = fragment;
+            }
+        };
+        return result.join('.');
+    };
+
+    
+    // simplistic implementation that doesn't understand 
+    // multiple classes per element
+    var getElementsByClassName = function(class_name, root_el, tag) {
+        tag = tag || '*';
+        
+        var result = [];
+        var elements = root_el.getElementsByTagName(tag);
+        
+        for (var i = 0, len = elements.length; i < len; ++i) {
+            if (elements[i].className) {
+                result[result.length] = elements[i];
+            }
+        }
+        return result;
+    };
+
+    // number all relevant attributes under el with nr
+    var updateNumbers = function(el, nr, prefix) {
+        // optimization - skip non-element nodes (ELEMENT_NODE 1)
+        if (el.nodeType != 1) {
+            return;
+        }
+        var i;
+        var attributes = ['id', 'name', 'for'];
+        for (i = 0; i < attributes.length; i++) {
+            attr = el.getAttribute(attributes[i]);
+            if (attr && startswith(attr, prefix)) {
+                el.setAttribute(attributes[i], renumber(attr, nr));
+            }
+        }
+        // recursion
+        var node = el.firstChild;
+        while (node) {
+            updateNumbers(node, nr, prefix);
+            node = node.nextSibling;
+        }   
+    };
+    
+    // update all numbers in el root
+    var updateAllNumbers = function(prefix) {
+        var table_el = document.getElementById(prefix + '.table');
+        // update numbering in table
+        var els = getElementsByClassName('list_item', table_el, 'tr');
+        var i;
+        for (i = 0; i < els.length; i++) {
+            updateNumbers(els[i], i, 'form.');
+        }
+        // update count
+        var count_el = document.getElementById(prefix + '.count');
+        count_el.value = els.length;
+    }
+
+    // add a new repeating element to the list
+    Z3C.listjs.add = function(prefix) {
+        var table_el = document.getElementById(prefix + '.table');
+        var template_el = document.getElementById(prefix + '.template');
+        var template_text = template_el.value;
+        var buttons_el = document.getElementById(prefix + '.buttons');
+
+        var new_tr = document.createElement('tr');
+        new_tr.className = 'list_item';
+        buttons_el.parentNode.insertBefore(new_tr, buttons_el); 
+        new_tr.innerHTML = template_text;
+
+        updateAllNumbers(prefix);
+    };
+   
+    // remove all selected repeating elements from the list
+    Z3C.listjs.remove = function(prefix) {
+        var table_el = document.getElementById(prefix + '.table');
+
+        // find all elements that are checked
+        var els = getElementsByClassName('editcheck', table_el, 'input');
+        var i;
+        var to_remove = [];
+        for (i = 0; i < els.length; i++) {
+            if (els[i].checked) {
+                // remove the tr (two levels up from the input box)
+                to_remove[to_remove.length] = els[i].parentNode.parentNode;
+            }
+        }
+        // now actually remove them
+        for (i = 0; i < to_remove.length; i++) {
+            to_remove[i].parentNode.removeChild(to_remove[i]);
+        }
+        
+        updateAllNumbers(prefix);
+    };
+
+
+})();

Added: z3c.listjs/trunk/src/z3c/listjs/testing.py
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/testing.py	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/testing.py	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,7 @@
+import os
+import z3c.listjs
+from zope.app.testing.functional import ZCMLLayer
+
+ftesting_zcml = os.path.join(
+    os.path.dirname(z3c.listjs.__file__), 'ftesting.zcml')
+FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer')

Added: z3c.listjs/trunk/src/z3c/listjs/widget.py
===================================================================
--- z3c.listjs/trunk/src/z3c/listjs/widget.py	                        (rev 0)
+++ z3c.listjs/trunk/src/z3c/listjs/widget.py	2009-01-06 20:36:22 UTC (rev 94552)
@@ -0,0 +1,35 @@
+from zope.app.form.browser import ListSequenceWidget
+from zope.app.form.interfaces import IInputWidget
+from zope.app.form.browser.widget import renderElement
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+
+from zope import component
+
+from hurry.resource import Library, ResourceInclusion
+
+listjs_lib = Library('z3c.listjs')
+listjs_resource = ResourceInclusion(listjs_lib, 'listjs.js')
+
+class _ListJsWidget(ListSequenceWidget):
+
+    template = ViewPageTemplateFile('listjswidget.pt')
+    record_template = ViewPageTemplateFile('listjswidget_record.pt')
+
+    def widgetTemplate(self):
+        # XXX hack: always get a widget that isn't in the sequence
+        sequence = self._getRenderedValue()
+        return self._getWidget(len(sequence))()
+    
+    def __call__(self):
+        result = ListSequenceWidget.__call__(self)
+        listjs_resource.need()
+        return result
+    
+    def _getPresenceMarker(self, count=0):
+        return ('<input type="hidden" id="%s.count" name="%s.count" value="%d" />'
+                % (self.name, self.name, count))
+
+
+def ListJsWidget(field, request):
+    return _ListJsWidget(field, field, request)
+



More information about the Checkins mailing list