some experimental treelist thing
authorTero Marttila <terom@fixme.fi>
Sun, 19 Dec 2010 18:39:54 +0200
changeset 1 06451697083a
parent 0 b28a1681e79b
child 2 e8b3f3884233
some experimental treelist thing
static/icons/treelist-more.png
static/icons/treelist-open.png
static/js/treelist.js
static/layout.css
static/treelist.css
svv/wsgi.py
Binary file static/icons/treelist-more.png has changed
Binary file static/icons/treelist-open.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/js/treelist.js	Sun Dec 19 18:39:54 2010 +0200
@@ -0,0 +1,24 @@
+/**
+ * Dynamically expandable tree-form lists
+ */
+
+/* Document startup */
+function treelist_init () 
+{
+    $$('.treelist li').each(function (item_li) {
+        item_handle = item_li.down('div.item');
+
+        item_handle.on('click', function (event, element) {
+            // only target clicks directly in div, not in element inside it
+            if (!element.match('div.item'))
+                return;
+
+            if (item_li.hasClassName('more'))
+                item_li.toggleClassName('open');
+        });
+    });
+}
+
+
+Event.on(window, 'load', treelist_init);
+
--- a/static/layout.css	Sat Dec 18 15:09:47 2010 +0200
+++ b/static/layout.css	Sun Dec 19 18:39:54 2010 +0200
@@ -111,6 +111,8 @@
 div#content
 {
     margin-left: 180px;
+
+    padding: 10px 50px 10px 25px;
 }
 
 /* Full-width Footer at bottom of page */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/treelist.css	Sun Dec 19 18:39:54 2010 +0200
@@ -0,0 +1,85 @@
+/*
+ * Structured tree-form lists
+ */
+
+ul.treelist,
+.treelist ul
+{
+    list-style-type: none;
+
+    padding: 0px;
+
+    /* Lists of items are vertically separated, visually more so than plain list items */
+    margin: 10px 0px;
+}
+
+.treelist li
+{
+    /* Items in a list are vertically separated */
+    margin-top: 5px;
+}
+
+.treelist li ul
+{
+    /* A nested list is indented */
+    padding-left: 2em;
+}
+
+.treelist li > div
+{
+    /* The handle fits to the left of the text block */
+    padding-left: 28px;
+
+    /* The item description need to be full-width */
+    width: 50%;
+}
+
+.treelist li > div a
+{
+    /* The text inside the li consitutes the clickable part */
+    display: block;
+    
+    /* The contents are adequately spaced */
+    padding: 10px;
+}
+
+/* 
+ * Treelist item states 
+ */
+.treelist li > ul
+{
+    /* Nested lists are closed per default */
+    display: none;
+}
+
+.treelist li.open > ul
+{
+    /* The sub-list inside an open item is displayed */
+    display: block;
+}
+
+.treelist li > div a
+{
+    /* A normal treelist item does not look special */
+    background-color: #ffffff;
+    border: thin solid #e8e8e8;
+}
+
+.treelist li.more > div
+{
+    background: transparent url(icons/treelist-more.png) no-repeat center left;
+}
+
+.treelist li.open > div
+{
+    background: transparent url(icons/treelist-open.png) no-repeat center left;
+}
+
+/*
+ * Checkbox styles
+ */
+.treelist li > div input[type=checkbox]
+{
+    background: #ffffff;
+    border: 1px solid green;
+}
--- a/svv/wsgi.py	Sat Dec 18 15:09:47 2010 +0200
+++ b/svv/wsgi.py	Sun Dec 19 18:39:54 2010 +0200
@@ -10,7 +10,9 @@
 
 class AppHandler (object):
     """
-        Per-request handler context
+        Per-request handler type, containing the request context and implementing the response.
+
+        Works on a generic level, i.e. WSGI/Werkzeug URL-mapped request in, response out.
     """
 
     # default content type for response
@@ -28,30 +30,32 @@
             Handle request that was mapped to ourselves via the URL routing, using given dict of values from URL.
         """
 
-        # render
-        html = unicode(self.render(**url_values))
-
-        # XXX: unicode
-        return Response(html, mimetype='text/html')
-
-    def render (self, **args) :
-        """
-            Handling a GET request, returning the proper response HTML.
-        """
-
         raise NotImplementedError()
 
 import html
 from html import tags
 
-class Index (AppHandler) :
-    def render (self) :
+class PageHandler (AppHandler) :
+    """
+        Specialized AppHandler for normal HTML page views.
+
+        Renders the layout template and HTML.
+    """
+
+    def respond (self, url_values) :
         title = "Index"
-        css = ["/static/layout.css", "/static/style.css"]
+        css = ["/static/layout.css", "/static/style.css", "/static/treelist.css"]
+        scripts = [
+                "/static/js/prototype.js", 
+                "/static/js/scriptaculous/scriptaculous.js", 
+                "/static/js/treelist.js"
+        ]
 
         head = (
             tags.title(title),
             (tags.link(rel='Stylesheet', type="text/css", href=src) for src in css),
+            # XXX: script can't self-close >_<
+            (tags.script(src=src)(" ") for src in scripts),
         )
 
         header = ("Foo List")
@@ -59,10 +63,9 @@
         menu = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Menu A', 'Menu B', 'Menu C'])]
         footer = ("Copyright?")
 
-        content = (
-            tags.ul(tags.li("Item #%d" % i) for i in xrange(10))
-        )
-
+        # render page HTML
+        content = self.render(**url_values)
+        
         layout = (
             tags.div(id='header')(header),
             tags.div(id='container')(
@@ -73,7 +76,67 @@
             tags.div(id='footer')(footer),
         )
         
-        return html.document(head, layout)
+        # perform the actual rendering (run generators etc.)
+        html_text = unicode(html.document(head, layout))
+        
+        # response object
+        # XXX: unicode?
+        return Response(html_text, mimetype='text/html')
+
+    def render (self, **args) :
+        """
+            Render and return HTML for page content.
+
+            XXX: must be HTML object, support just text?
+        """
+
+        raise NotImplementedError()
+
+class Index (PageHandler) :
+    DATA = (
+        (100, "Top A", []),
+        (200, "Top B", [
+            (210, "Mid BA", [
+                (211, "Sub BAA", []),
+                (212, "Sub BAB", []),
+            ]),
+            (220, "Mid BB", []),
+        ]),
+        (300, "Top C", [
+            (310, "Mid CA", []),
+            (320, "Mid CB", []),
+        ]),
+    )
+
+    def render (self) :
+        # build data set
+        data = self.DATA
+
+        def render_item (id, text, children) :
+            return tags.li(
+                tags.div(class_='item')(
+                    # item text
+                    tags.a(tags.input(type='checkbox', name_=id, checked=(
+                        'checked' if self.request.form.get(str(id)) else None
+                    )), text, class_='text'),
+                ),
+
+                # children
+                tags.ul(render_item(*item) for item in children if item) if children else None,
+
+                # 
+                class_=('more open' if children else None),
+            )
+
+        # render it
+        return (
+            tags.h3("Item list"),
+            tags.form(action='.', method='post')(
+                tags.ul(class_='treelist')(render_item(*item) for item in data),
+                tags.input(type='submit'),
+            ),
+        )
+
 
 class WSGIApp (object) :
     """