[rhmessaging-commits] rhmessaging commits: r3161 - in mgmt/trunk: cumin/python/cumin and 3 other directories.

rhmessaging-commits at lists.jboss.org rhmessaging-commits at lists.jboss.org
Wed Mar 18 11:33:33 EDT 2009


Author: justi9
Date: 2009-03-18 11:33:33 -0400 (Wed, 18 Mar 2009)
New Revision: 3161

Added:
   mgmt/trunk/cumin/resources/app.css
   mgmt/trunk/cumin/resources/app.js
   mgmt/trunk/wooly/python/wooly/pages.strings
   mgmt/trunk/wooly/resources/wooly.css
Modified:
   mgmt/trunk/basil/python/basil/page.py
   mgmt/trunk/basil/python/basil/page.strings
   mgmt/trunk/basil/python/basil/server.py
   mgmt/trunk/cumin/python/cumin/__init__.py
   mgmt/trunk/cumin/python/cumin/widgets.py
   mgmt/trunk/cumin/python/cumin/widgets.strings
   mgmt/trunk/wooly/python/wooly/__init__.py
   mgmt/trunk/wooly/python/wooly/pages.py
   mgmt/trunk/wooly/python/wooly/parameters.py
   mgmt/trunk/wooly/resources/wooly.js
Log:
This change introduces infrastructure for automatic widget updates,
based on periodic background partial page renders.  A widget may
render updates by doing the following:

  * Set widget.update_enabled = True, usually in the widget's
    constructor

  * Make sure the widget has a top-level element with an id of the
    widget's path

It introduces HtmlPage, a page that brings with it a set of pages
related to serving typical wooly html: JavascriptPage, CssPage, and
UpdatePage.

It realigns the static css and javascript resources so that there is
now a standard chain:

  wooly.css    wooly.js      <-- Factory settings
  app.css      app.js        <-- App-specific overrides and additions
  ${page}.css  ${page}.js    <-- Widget-specific settings



Modified: mgmt/trunk/basil/python/basil/page.py
===================================================================
--- mgmt/trunk/basil/python/basil/page.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/basil/python/basil/page.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -1,6 +1,7 @@
 import struct
 
 from wooly import *
+from wooly.pages import *
 from wooly.tables import *
 from wooly.resources import *
 
@@ -8,7 +9,7 @@
 
 strings = StringCatalog(__file__)
 
-class BasilPage(Page):
+class BasilPage(HtmlPage):
     def __init__(self, app, page):
         super(BasilPage, self).__init__(app, page)
 
@@ -154,6 +155,8 @@
         self.stats = ObjectStatistics(app, "stats", self.objid)
         self.add_child(self.stats)
 
+        self.update_enabled = True
+
     def render_name(self, session):
         id = self.objid.get(session)
 

Modified: mgmt/trunk/basil/python/basil/page.strings
===================================================================
--- mgmt/trunk/basil/python/basil/page.strings	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/basil/python/basil/page.strings	2009-03-18 15:33:33 UTC (rev 3161)
@@ -1,55 +1,23 @@
-[BasilPage.css]
-body {
-  font-size: 0.9em;
-  font-family: "DejaVu LGC Sans", "Bitstream Vera Sans", "Lucida Grande",
-               "Trebuchet MS", verdana, helvetica, arial, sans-serif;
-}
-
-h3 {
-  font-size: 0.9em;
-}
-
-a {
-  text-decoration: none;
-  color: blue;
-}
-
-a.selected {
-  color: black;
-  background-color: #ff6;
-}
-
-[BasilPage.html]
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-  <head>
-    <title>{title}</title>
-    <link rel="stylesheet" type="text/css" href="index.css"/>
-  </head>
-  <body>
-    {content}
-  </body>
-</html>
-
 [ObjectView.html]
-<h2>{name}</h2>
+<div id="{id}">
+  <h2>{name}</h2>
 
-<table class="PropertySet">
-  <thead>
-    <tr><th><a>Name</a></th><th><a>Value</a></th></tr>
-  </thead>
-  <tbody>
-    <tr><td>Created</td><td>{create_time}</td></tr>
-    <tr><td>Updated</td><td>{update_time}</td></tr>
-    <tr><td>Deleted</td><td>{delete_time}</td></tr>
-  </tbody>
-</table>
+  <table class="PropertySet">
+    <thead>
+      <tr><th><a>Name</a></th><th><a>Value</a></th></tr>
+    </thead>
+    <tbody>
+      <tr><td>Created</td><td>{create_time}</td></tr>
+      <tr><td>Updated</td><td>{update_time}</td></tr>
+      <tr><td>Deleted</td><td>{delete_time}</td></tr>
+    </tbody>
+  </table>
 
-<h3>Properties</h3>
+  <h3>Properties</h3>
 
-{props}
+  {props}
 
-<h3>Statistics</h3>
+  <h3>Statistics</h3>
 
-{stats}
+  {stats}
+</div>

Modified: mgmt/trunk/basil/python/basil/server.py
===================================================================
--- mgmt/trunk/basil/python/basil/server.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/basil/python/basil/server.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -1,7 +1,7 @@
 from qmf.console import *
 from wooly import Application
 from wooly.server import WebServer
-from wooly.pages import CssPage
+from wooly.pages import CssPage, ResourcePage
 
 from model import BasilModel
 from page import BasilPage
@@ -15,14 +15,16 @@
         super(BasilApplication, self).__init__()
 
         self.model = BasilModel()
-        self.model.add_broker_url("amqp://north-15.lab.bos.redhat.com")
+        self.model.add_broker_url("amqp://mrg2.lab.bos.redhat.com")
 
-        self.main_page = BasilPage(self, "index.html")
+        self.main_page = BasilPage(self, "index")
 
         self.add_page(self.main_page)
         self.set_default_page(self.main_page)
 
-        page = CssPage(self, "index.css")
+        self.add_resource_dir("/home/jross/checkouts/mgmt/trunk/cumin-test-0/resources-wooly") # XXX
+
+        page = ResourcePage(self, "resource")
         self.add_page(page)
 
         self.enable_debug()

Modified: mgmt/trunk/cumin/python/cumin/__init__.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/__init__.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/cumin/python/cumin/__init__.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -4,7 +4,7 @@
 from parsley.config import Config, ConfigParameter
 from parsley.loggingex import *
 from wooly import Application, Session, Page
-from wooly.pages import CssPage, JavascriptPage, ResourcePage
+from wooly.pages import ResourcePage
 from wooly.server import WebServer
 from wooly.devel import DevelPage
 from wooly.parameters import IntegerParameter
@@ -40,7 +40,7 @@
 
         self.model = CuminModel(self, self.config.data)
 
-        self.main_page = MainPage(self, "index.html")
+        self.main_page = MainPage(self, "index")
         self.add_page(self.main_page)
         self.set_default_page(self.main_page)
 
@@ -52,22 +52,17 @@
 
         unprotected = set()
 
+        unprotected.add(self.main_page.css_page)
+        unprotected.add(self.main_page.javascript_page)
+
         self.login_page = LoginPage(self, "login.html")
         self.add_page(self.login_page)
         unprotected.add(self.login_page)
 
-        page = CssPage(self, "cumin.css")
-        self.add_page(page)
-        unprotected.add(page)
-
-        page = JavascriptPage(self, "cumin.js")
-        self.add_page(page)
-        unprotected.add(page)
-
         page = ResourcePage(self, "resource")
         self.add_page(page)
         unprotected.add(page)
-        
+
         self.unprotected_pages = unprotected
 
         self.user_sessions_by_id = dict()

Modified: mgmt/trunk/cumin/python/cumin/widgets.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/cumin/python/cumin/widgets.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -2,6 +2,7 @@
 from sqlobject import sqlhub
 from sqlobject.sresults import SelectResults
 from wooly import *
+from wooly.pages import *
 from wooly.widgets import *
 from wooly.forms import *
 from wooly.tables import *
@@ -16,7 +17,7 @@
 
 strings = StringCatalog(__file__)
 
-class CuminPage(Page):
+class CuminPage(HtmlPage):
     def __init__(self, app, name):
         super(CuminPage, self).__init__(app, name)
 
@@ -37,7 +38,7 @@
         return self.__frames.get(session)
 
     def render_class(self, session):
-        return self.__modal.get(session) and "modal" or "modeless"
+        return self.__modal.get(session) and "modal" or "_"
 
     class FramesAttribute(Attribute):
         def get_default(self, session):

Modified: mgmt/trunk/cumin/python/cumin/widgets.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/widgets.strings	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/cumin/python/cumin/widgets.strings	2009-03-18 15:33:33 UTC (rev 3161)
@@ -1,541 +1,3 @@
-[CuminPage.css]
-body {
-  margin: 0;
-  padding: 0;
-  background-color: #fff;
-  font-family: "DejaVu LGC Sans", "Bitstream Vera Sans", "Lucida Grande",
-               "Trebuchet MS", verdana, helvetica, arial, sans-serif;
-  font-size: 0.9em;
-}
-
-body.modal {
-  background-color: #f7f7f7;
-}
-
-img {
-  border: none;
-}
-
-a {
-  color: #06c;
-  text-decoration: none;
-}
-
-a.selected {
-  color: black;
-}
-
-ul {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-ul > ul {
-  padding: 1em;
-}
-
-h1 {
-  font-size: 1.1em;
-}
-
-h2 {
-  font-size: 1em;
-  margin: 0;
-}
-
-span.none {
-  font-style: italic;
-  color: #999;
-}
-
-.oblock {
-  padding: 0;
-  background-color: white;
-}
-
-.iblock {
-  margin: 1em 0;
-  padding: 0 1em;
-}
-
-.notice {
-  margin: 2em;
-  padding: 2em;
-  border: 1px dotted black;
-  width: 66%;
-  text-align: center;
-}
-
-ul.actions {
-  padding: 0;
-  margin: 0 0 1em 0;
-  list-style: none;
-}
-
-ul.actions li {
-  display: inline;
-}
-ul.actions.disabled a {
-	color: #666666;
-}
-ul.actions.disabled li a.nav:before {
-	color: #666666;
-}
-
-ul.actions.disabled a:hover {
-	background-color: #f7f7f7;
-}
-a.nav:before {
-  content: "\00BB \0020";
-  font-weight: bold;
-  color: #dc9f2e;
-}
-
-div.sactions {
-  margin: 0;
-  padding: 0.35em 0.75em;
-  background-color: #e7e7f7;
-}
-
-div.sactions h2 {
-  display: inline;
-  font-size: 0.9em;
-  font-weight: normal;
-  margin: 0 0.5em 0 0;
-}
-
-div.sactions select {
-  margin: 0 0.5em 0 0;
-}
-
-div.mobject div.mactions h2 {
-  display: inline;
-  font-size: 0.9em;
-  font-weight: normal;
-  margin: 0 0.5em 0 0;
-}
-
-button, ul.actions a, a.action {
-  margin: 0;
-  border-top: 1px solid #ddd;
-  border-left: 1px solid #ddd;
-  border-bottom: 1px solid #bbb;
-  border-right: 1px solid #bbb;
-  padding: 0.25em 0.5em 0.30em 0.5em;
-  background: url(resource?name=button-background.png) repeat;
-  color: #000;
-  font-size: 0.9em;
-  -moz-border-radius: 0.4em;
-  -webkit-border-radius: 0.4em;
-}
-
-button:hover, ul.actions a:hover, a.action:hover {
-  background-color: white;
-}
-
-button.disabled {
-  color: #bbb;
-  border: 1px solid #ddd;
-}
-button.disabled:hover {
-  background-color: #f7f7f7;
-}
-
-ul.mobjects {
-  list-style: none;
-  margin: 0;
-  padding: 0;
-}
-
-ul.mobjects li {
-  margin: 0;
-  border-top: 1px solid #ccc;
-  padding: 0.5em 0;
-}
-
-ul.mobjects li:first-child {
-  margin: 0;
-  border: none;
-}
-
-ul.mobjects li a.action {
-  float: right;
-}
-
-ul.mobjects .flags {
-  font-size: small;
-  font-style: italic;
-}
-
-ul.mobjects .config {
-  padding: 0 0 0 2em;
-}
-
-ul.mobjects .status {
-  padding: 0 0 0 2em;
-  color: #936;
-}
-
-table.mobjects {
-  width: 100%;
-  border-collapse: collapse;
-  margin: 0;
-}
-
-table.mobjects tr {
-  border-top: 1px dotted #ccc;
-  vertical-align: top;
-}
-
-table.mobjects td {
-  padding: 0.35em 0.5em;
-}
-
-table.mobjects th {
-  padding: 0.35em 0.5em;
-}
-
-table.mobjects th {
-  text-align: left;
-  font-weight: normal;
-  background-color: #f7f7f7;
-}
-
-form.mform {
-  width: 50em;
-  border: 1px solid #ddd;
-  background-color: #fff;
-}
-
-form.mform fieldset {
-  border: none;
-  padding: 0.75em;
-}
-
-form.mform .legend {
-  font-weight: bold;
-}
-
-form.mform .head, .mform .body, .mform .foot {
-  padding: 0.5em 0.75em;
-  margin: 0;
-}
-
-form.mform .head {
-  font-weight: bold;
-  color: white;
-  background-color: #685b8a;
-  /* background-color: #564979; */
-}
-
-form.mform .head h1 {
-  margin: 0;
-  font-size: 1.1em;
-}
-
-form.mform .foot {
-  text-align: right;
-  border-top: 1px solid #ddd;
-}
-
-form.mform .field {
-  margin: 0.25em 0;
-}
-
-form.mform .field input {
-  border-style: groove;
-}
-
-form.mform ul.errors {
-  list-style: none;
-  display: block;
-  float: right;
-  color: red;
-  padding: 0.25em 0.5em;
-  border: 1px solid red;
-  margin: 0 0.5em;
-  max-width: 20em;
-}
-
-form.mform button, form.mform a.help {
-  margin: 0.5em;
-  padding: 0.25em 0.25em 0 0.25em;
-}
-
-form.mform a.help {
-  float: left;
-  margin: 0.5em;
-  padding: 0.25em 0.35em 0 0.5em;
-}
-
-form.mform a.help:before {
-  content: url(resource?name=help-20.png);
-  padding: 0 0.25em 0 0;
-  vertical-align: -35%;
-}
-
-form.mform button.cancel:before {
-  content: url(resource?name=cancel-20.png);
-  padding: 0 0.25em 0 0;
-  vertical-align: -35%;
-}
-
-form.mform button.submit:before {
-  content: url(resource?name=submit-20.png);
-  padding: 0 0.25em 0 0;
-  vertical-align: -35%;
-}
-
-form.mform td {
-  vertical-align: top;
-}
-
-ul.radiotabs {
-  list-style: none;
-  margin: 0 0 1em 0;
-  padding: 0;
-}
-
-ul.radiotabs li {
-  display: inline;
-  padding: 0 0.75em 0 0;
-}
-
-ul.radiotabs li:last-child {
-  display: inline;
-  margin: 0;
-}
-
-ul.radiotabs li a:before {
-  content: url(resource?name=radio-button.png);
-  margin: 0 0.5em 0 0;
-  vertical-align: -15%;
-}
-
-ul.radiotabs li a.selected {
-  color: black;
-}
-
-ul.radiotabs li a.selected:before {
-  content: url(resource?name=radio-button-checked.png);
-}
-
-ul.radiotabs li a.disabled:before {
-  content: url(resource?name=radio-button.png);
-}
-ul.radiotabs li a.disabled {
-	color: #666666;
-}
-
-div.statuslight {
-  float: left;
-  width: 1em;
-  height: 1em;
-  margin: 0.25em 1px 0 0;
-  padding: 0.15em;
-  font-size: 0.8em;
-  text-align: center;
-  line-height: 1.1em;
-}
-
-div.statuslight.red {
-  background-color: #e33;
-  color: #fd3;
-}
-
-div.statuslight.yellow {
-  background-color: #fd3;
-  color: #e33;
-}
-
-div.statuslight.green {
-  background-color: #9e9;
-}
-
-pre.code {
-  background-color: #f7f7f7;
-  padding: 1em;
-  border: 1px dotted #ddd;
-}
-
-ul.comma {
-  list-style: none;
-}
-
-ul.comma li {
-  display: inline;
-}
-
-ul.comma li:after {
-  content: ", "
-}
-
-ul.comma li:last-child:after {
-  content: ""
-}
-
-ul.slist a:before {
-  content: url(resource?name=radio-button.png);
-  vertical-align: -10%;
-  margin: 0 0.5em 0 0;
-}
-
-ul.slist a.selected:before {
-  content: url(resource?name=radio-button-checked.png);
-}
-
-table.twocol {
-  width: 100%;
-}
-
-table.twocol > tbody > tr > td {
-  width: 50%;
-  vertical-align: top;
-}
-
-table.twocol > tbody > tr > td:first-child {
-  padding: 0 1.5em 0 0;
-}
-
-table.twocol > tbody > tr > td:last-child {
-  padding: 0 0 0 1.5em;
-}
-
-.ralign, table.mobjects .ralign, div.mstatus table .ralign {
-  text-align: right;
-}
-
-form.inline {
-  display: inline;
-}
-
-span.count {
-  font-size: 0.9em;
-  color: #999;
-}
-
-.rfloat {
-  float: right;
-}
-
-.rclear {
-  font-size:0.01em;
-  width: 0.01px;
-  clear:right;
-  line-height:0.01px;
-}
-
-table.Editable input.edit_string,
-table.Editable textarea.edit_bigstring,
-div.inline_help span.edit_string {
-	border: 1px solid #CCCCCC;
-}
-table.Editable input.edit_number,
-div.inline_help span.edit_number {
-	border: 1px dashed #66CCFF;
-}	
-table.Editable input.numeric_error,
-div.inline_help span.numeric_error {
-	border: 1px dashed #FF0000;
-}
-table.Editable span.edit_readonly {
-	background-color: #FFFFFF;
-	color: #444444;
-}
-
-table.Editable input.edit_string,
-table.Editable input.edit_number,
-table.Editable input.numeric_error {
-	width: 20em;
-}
-table.Editable textarea.edit_bigstring {
-	width: 25em;
-}
-table.Editable div.error {
-	color: #FF0000;
-	font-size: 0.9em;
-}
-
-form.editform {
-	border:0 none !important;
-	width: 100% !important;
-}
-
-div.inline_help {
-	margin: 1em;
-}
-
-div.inline_help span.edit_string,
-div.inline_help span.edit_number,
-div.inline_help span.numeric_error {
-	color: #444444;
-	font-weight: normal;
-	margin-right: 0.5em;
-	padding:0.05em 0.2em;
-}	
-div.inline_help h2 {
-	margin-right: 1em;
-}
-
-span.prop_example {
-	font-size: 0.9em;
-}
-span.prop_example:before {
-  content: "Example:";
-  padding-right: 0.25em;
-}
-
-[CuminPage.javascript]
-var cumin;
-
-(function() {
-    cumin = new Cumin();
-
-    function Cumin() {
-        this.modelListeners = new Object();
-        this.objectListeners = new Object();
-
-        this.runModelListeners = function(model) {
-            for (var id in this.modelListeners) {
-                this.modelListeners[id](id, model);
-            }
-        }
-
-        this.runObjectListeners = function(object) {
-            for (var id in this.objectListeners) {
-                this.objectListeners[id](id, object);
-            }
-        }
-    }
-}())
-function addEvent(obj, event_type, funct) { 
-	if (obj.addEventListener) 
-		obj.addEventListener(event_type, funct, false); 
-	else if (obj.attachEvent) 
-		obj.attachEvent("on"+event_type, funct); 
-}
-
-[CuminPage.html]
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-  <head>
-    <meta http-equiv="X-UA-Compatible" content="IE=7" />
-    <title>{title}</title>
-    <link rel="stylesheet" type="text/css" href="cumin.css"/>
-    <link rel="shortcut icon" href="resource?name=favicon.ico" type="image/x-icon"/>
-    <script src="resource?name=wooly.js" type="text/javascript"> </script>
-    <script src="cumin.js" type="text/javascript"> </script>
-<!--[if IE]>
-	<link rel="stylesheet" type="text/css" href="resource?name=ie.css" />
-<![endif]-->    
-  </head>
-  <body class="{class}">
-    {mode}
-  </body>
-</html>
-
 [BindingSet.sql]
 select
   b.id,

Added: mgmt/trunk/cumin/resources/app.css
===================================================================
--- mgmt/trunk/cumin/resources/app.css	                        (rev 0)
+++ mgmt/trunk/cumin/resources/app.css	2009-03-18 15:33:33 UTC (rev 3161)
@@ -0,0 +1,466 @@
+body.modal {
+  background-color: #f7f7f7;
+}
+
+ul {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+ul > ul {
+  padding: 1em;
+}
+
+h2 {
+  margin: 0;
+}
+
+span.none {
+  font-style: italic;
+  color: #999;
+}
+
+.oblock {
+  padding: 0;
+  background-color: white;
+}
+
+.iblock {
+  margin: 1em 0;
+  padding: 0 1em;
+}
+
+.notice {
+  margin: 2em;
+  padding: 2em;
+  border: 1px dotted black;
+  width: 66%;
+  text-align: center;
+}
+
+ul.actions {
+  padding: 0;
+  margin: 0 0 1em 0;
+  list-style: none;
+}
+
+ul.actions li {
+  display: inline;
+}
+ul.actions.disabled a {
+	color: #666666;
+}
+ul.actions.disabled li a.nav:before {
+	color: #666666;
+}
+
+ul.actions.disabled a:hover {
+	background-color: #f7f7f7;
+}
+a.nav:before {
+  content: "\00BB \0020";
+  font-weight: bold;
+  color: #dc9f2e;
+}
+
+div.sactions {
+  margin: 0;
+  padding: 0.35em 0.75em;
+  background-color: #e7e7f7;
+}
+
+div.sactions h2 {
+  display: inline;
+  font-size: 0.9em;
+  font-weight: normal;
+  margin: 0 0.5em 0 0;
+}
+
+div.sactions select {
+  margin: 0 0.5em 0 0;
+}
+
+div.mobject div.mactions h2 {
+  display: inline;
+  font-size: 0.9em;
+  font-weight: normal;
+  margin: 0 0.5em 0 0;
+}
+
+button, ul.actions a, a.action {
+  margin: 0;
+  border-top: 1px solid #ddd;
+  border-left: 1px solid #ddd;
+  border-bottom: 1px solid #bbb;
+  border-right: 1px solid #bbb;
+  padding: 0.25em 0.5em 0.30em 0.5em;
+  background: url(resource?name=button-background.png) repeat;
+  color: #000;
+  font-size: 0.9em;
+  -moz-border-radius: 0.4em;
+  -webkit-border-radius: 0.4em;
+}
+
+button:hover, ul.actions a:hover, a.action:hover {
+  background-color: white;
+}
+
+button.disabled {
+  color: #bbb;
+  border: 1px solid #ddd;
+}
+button.disabled:hover {
+  background-color: #f7f7f7;
+}
+
+ul.mobjects {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+}
+
+ul.mobjects li {
+  margin: 0;
+  border-top: 1px solid #ccc;
+  padding: 0.5em 0;
+}
+
+ul.mobjects li:first-child {
+  margin: 0;
+  border: none;
+}
+
+ul.mobjects li a.action {
+  float: right;
+}
+
+ul.mobjects .flags {
+  font-size: small;
+  font-style: italic;
+}
+
+ul.mobjects .config {
+  padding: 0 0 0 2em;
+}
+
+ul.mobjects .status {
+  padding: 0 0 0 2em;
+  color: #936;
+}
+
+table.mobjects {
+  width: 100%;
+  border-collapse: collapse;
+  margin: 0;
+}
+
+table.mobjects tr {
+  border-top: 1px dotted #ccc;
+  vertical-align: top;
+}
+
+table.mobjects td {
+  padding: 0.35em 0.5em;
+}
+
+table.mobjects th {
+  padding: 0.35em 0.5em;
+}
+
+table.mobjects th {
+  text-align: left;
+  font-weight: normal;
+  background-color: #f7f7f7;
+}
+
+form.mform {
+  width: 50em;
+  border: 1px solid #ddd;
+  background-color: #fff;
+}
+
+form.mform fieldset {
+  border: none;
+  padding: 0.75em;
+}
+
+form.mform .legend {
+  font-weight: bold;
+}
+
+form.mform .head, .mform .body, .mform .foot {
+  padding: 0.5em 0.75em;
+  margin: 0;
+}
+
+form.mform .head {
+  font-weight: bold;
+  color: white;
+  background-color: #685b8a;
+  /* background-color: #564979; */
+}
+
+form.mform .head h1 {
+  margin: 0;
+  font-size: 1.1em;
+}
+
+form.mform .foot {
+  text-align: right;
+  border-top: 1px solid #ddd;
+}
+
+form.mform .field {
+  margin: 0.25em 0;
+}
+
+form.mform .field input {
+  border-style: groove;
+}
+
+form.mform ul.errors {
+  list-style: none;
+  display: block;
+  float: right;
+  color: red;
+  padding: 0.25em 0.5em;
+  border: 1px solid red;
+  margin: 0 0.5em;
+  max-width: 20em;
+}
+
+form.mform button, form.mform a.help {
+  margin: 0.5em;
+  padding: 0.25em 0.25em 0 0.25em;
+}
+
+form.mform a.help {
+  float: left;
+  margin: 0.5em;
+  padding: 0.25em 0.35em 0 0.5em;
+}
+
+form.mform a.help:before {
+  content: url(resource?name=help-20.png);
+  padding: 0 0.25em 0 0;
+  vertical-align: -35%;
+}
+
+form.mform button.cancel:before {
+  content: url(resource?name=cancel-20.png);
+  padding: 0 0.25em 0 0;
+  vertical-align: -35%;
+}
+
+form.mform button.submit:before {
+  content: url(resource?name=submit-20.png);
+  padding: 0 0.25em 0 0;
+  vertical-align: -35%;
+}
+
+form.mform td {
+  vertical-align: top;
+}
+
+ul.radiotabs {
+  list-style: none;
+  margin: 0 0 1em 0;
+  padding: 0;
+}
+
+ul.radiotabs li {
+  display: inline;
+  padding: 0 0.75em 0 0;
+}
+
+ul.radiotabs li:last-child {
+  display: inline;
+  margin: 0;
+}
+
+ul.radiotabs li a:before {
+  content: url(resource?name=radio-button.png);
+  margin: 0 0.5em 0 0;
+  vertical-align: -15%;
+}
+
+ul.radiotabs li a.selected {
+  color: black;
+}
+
+ul.radiotabs li a.selected:before {
+  content: url(resource?name=radio-button-checked.png);
+}
+
+ul.radiotabs li a.disabled:before {
+  content: url(resource?name=radio-button.png);
+}
+ul.radiotabs li a.disabled {
+	color: #666666;
+}
+
+div.statuslight {
+  float: left;
+  width: 1em;
+  height: 1em;
+  margin: 0.25em 1px 0 0;
+  padding: 0.15em;
+  font-size: 0.8em;
+  text-align: center;
+  line-height: 1.1em;
+}
+
+div.statuslight.red {
+  background-color: #e33;
+  color: #fd3;
+}
+
+div.statuslight.yellow {
+  background-color: #fd3;
+  color: #e33;
+}
+
+div.statuslight.green {
+  background-color: #9e9;
+}
+
+pre.code {
+  background-color: #f7f7f7;
+  padding: 1em;
+  border: 1px dotted #ddd;
+}
+
+ul.comma {
+  list-style: none;
+}
+
+ul.comma li {
+  display: inline;
+}
+
+ul.comma li:after {
+  content: ", ";
+}
+
+ul.comma li:last-child:after {
+  content: "";
+}
+
+ul.slist a:before {
+  content: url(resource?name=radio-button.png);
+  vertical-align: -10%;
+  margin: 0 0.5em 0 0;
+}
+
+ul.slist a.selected:before {
+  content: url(resource?name=radio-button-checked.png);
+}
+
+table.twocol {
+  width: 100%;
+}
+
+table.twocol > tbody > tr > td {
+  width: 50%;
+  vertical-align: top;
+}
+
+table.twocol > tbody > tr > td:first-child {
+  padding: 0 1.5em 0 0;
+}
+
+table.twocol > tbody > tr > td:last-child {
+  padding: 0 0 0 1.5em;
+}
+
+.ralign, table.mobjects .ralign, div.mstatus table .ralign {
+  text-align: right;
+}
+
+form.inline {
+  display: inline;
+}
+
+span.count {
+  font-size: 0.9em;
+  color: #999;
+}
+
+.rfloat {
+  float: right;
+}
+
+.rclear {
+  font-size:0.01em;
+  width: 0.01px;
+  clear:right;
+  line-height:0.01px;
+}
+
+table.Editable input.edit_string,
+table.Editable textarea.edit_bigstring,
+div.inline_help span.edit_string {
+	border: 1px solid #CCCCCC;
+}
+
+table.Editable input.edit_number,
+div.inline_help span.edit_number {
+	border: 1px dashed #66CCFF;
+}	
+
+table.Editable input.numeric_error,
+div.inline_help span.numeric_error {
+	border: 1px dashed #FF0000;
+}
+
+table.Editable span.edit_readonly {
+	background-color: #FFFFFF;
+	color: #444444;
+}
+
+table.Editable input.edit_string,
+table.Editable input.edit_number,
+table.Editable input.numeric_error {
+	width: 20em;
+}
+
+table.Editable textarea.edit_bigstring {
+	width: 25em;
+}
+
+table.Editable div.error {
+	color: #FF0000;
+	font-size: 0.9em;
+}
+
+form.editform {
+	border:0 none !important;
+	width: 100% !important;
+}
+
+div.inline_help {
+	margin: 1em;
+}
+
+div.inline_help span.edit_string,
+div.inline_help span.edit_number,
+div.inline_help span.numeric_error {
+	color: #444444;
+	font-weight: normal;
+	margin-right: 0.5em;
+	padding:0.05em 0.2em;
+}	
+
+div.inline_help h2 {
+	margin-right: 1em;
+}
+
+span.prop_example {
+	font-size: 0.9em;
+}
+
+span.prop_example:before {
+  content: "Example:";
+  padding-right: 0.25em;
+}

Added: mgmt/trunk/cumin/resources/app.js
===================================================================
--- mgmt/trunk/cumin/resources/app.js	                        (rev 0)
+++ mgmt/trunk/cumin/resources/app.js	2009-03-18 15:33:33 UTC (rev 3161)
@@ -0,0 +1,34 @@
+var cumin;
+
+(function() {
+    cumin = new Cumin();
+
+    function runModelListeners(model) {
+        for (var id in this.modelListeners) {
+            this.modelListeners[id](id, model);
+        }
+    }
+
+    function runObjectListeners(object) {
+        for (var id in this.objectListeners) {
+            this.objectListeners[id](id, object);
+        }
+    }
+
+    function Cumin() {
+        this.modelListeners = new Object();
+        this.objectListeners = new Object();
+
+        this.runModelListeners = runModelListeners;
+        this.runObjectListeners = runObjectListeners;
+    }
+}())
+
+// XXX move this
+function addEvent(obj, eventType, funct) { 
+    if (obj.addEventListener) {
+        obj.addEventListener(eventType, funct, false);
+    } else if (obj.attachEvent) {
+        obj.attachEvent("on"+eventType, funct);
+    }
+}

Modified: mgmt/trunk/wooly/python/wooly/__init__.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/__init__.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/wooly/python/wooly/__init__.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -93,6 +93,12 @@
         self.attributes = list()
         self.parameters = list()
 
+        self.sealed = False
+
+        # Configuration
+        self.html_class = "_"
+        self.update_enabled = False
+
         # These are set in the init() pass
         self.ancestors = None
         self.path = None
@@ -103,15 +109,12 @@
 
         app.add_widget(self)
 
+        # XXX eliminate this
         for cls in self.__class__.__mro__:
             app.add_widget_class(cls)
             if cls is Widget:
                 break
 
-        self.html_class = "_"
-
-        self.sealed = False
-
     def init(self):
         #print "Initializing %s" % str(self)
 
@@ -138,6 +141,8 @@
         assert isinstance(self.ancestors[-1], Page)
         self.page = self.ancestors[-1]
 
+        self.page.widgets_by_path[self.path] = self
+
         self.sealed = True
 
         self.init_children()
@@ -226,6 +231,9 @@
                               self, session, None)
             call.open()
 
+        if self.update_enabled:
+            self.page.enable_update(session, self)
+
         args = self.get_args(session)
         self.do_process(session, *args)
 
@@ -314,11 +322,13 @@
         self.add_parameter(self.current_frame)
         self.set_default_frame(self)
 
+        self.widgets_by_path = dict()
+
         self.__saved_params = dict()
 
         self.agent = Attribute(app, "agent")
         self.add_attribute(self.agent)
-        
+
     def init(self):
         assert not self.sealed
         assert self.parent is None
@@ -332,6 +342,9 @@
 
         self.init_children()
 
+    def render_id(self, session, *args):
+        return self.name
+
     def get_last_modified(self, session):
         return datetime.utcnow()
 
@@ -354,6 +367,9 @@
     def save_session(self, session):
         pass
 
+    def enable_update(self, session, widget):
+        pass
+
     def set_redirect_url(self, session, url):
         self.redirect.set(session, url)
 
@@ -377,7 +393,7 @@
 
     def set_agent(self, session, agent):
         self.agent.set(session, agent)
-        
+
     def set_default_frame(self, frame):
         self.current_frame.default = frame
 
@@ -442,6 +458,10 @@
         if page.parent:
             raise Exception("Page '%s' is not a root widget" % page.name)
 
+        if page.name in self.pages:
+            raise Exception \
+                ("A page called '%s' has already been added" % page.name)
+
         self.pages[page.name] = page
 
         page.init()

Modified: mgmt/trunk/wooly/python/wooly/pages.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/pages.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/wooly/python/wooly/pages.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -1,11 +1,107 @@
 from datetime import datetime
 
-from wooly import Page, Parameter, Writer
+from wooly import *
+from wooly.parameters import ListParameter
+from wooly.resources import StringCatalog
 
+strings = StringCatalog(__file__)
+
+class HtmlPage(Page):
+    def __init__(self, app, name):
+        super(HtmlPage, self).__init__(app, name)
+
+        self.updates = self.UpdatesAttribute(app, "updates")
+        self.add_attribute(self.updates)
+
+        self.update_page = UpdatePage(app, name + ".update", self)
+        self.app.add_page(self.update_page)
+
+        self.css_page = CssPage(app, name + ".css")
+        self.css_page.html_page = self
+        self.app.add_page(self.css_page)
+
+        self.javascript_page = JavascriptPage(app, name + ".js")
+        self.javascript_page.html_page = self
+        self.app.add_page(self.javascript_page)
+
+    def enable_update(self, session, widget):
+        self.updates.get(session).append(widget)
+
+    def render_update_url(self, session):
+        return self.get_update_url(session, self.updates.get(session))
+
+    def get_update_url(self, session, widgets):
+        sess = Session(self.page.update_page)
+
+        self.page.update_page.widgets.set(sess, widgets)
+        self.page.update_page.session.set(sess, session)
+
+        return sess.marshal()
+
+    class UpdatesAttribute(Attribute):
+        def get_default(self, session):
+            return list()
+
+class UpdatePage(Page):
+    def __init__(self, app, name, html_page):
+        super(UpdatePage, self).__init__(app, name)
+
+        self.widget_tmpl = Template(self, "widget_html")
+
+        self.html_page = html_page
+
+        self.session = self.SessionParameter(app, "session")
+        self.add_parameter(self.session)
+
+        item = self.WidgetParameter(app, "item", self.html_page)
+
+        self.widgets = ListParameter(app, "widget", item)
+        self.add_parameter(self.widgets)
+
+    def get_content_type(self, session):
+        return self.xml_content_type
+
+    def do_process(self, session):
+        self.html_page.process(self.session.get(session))
+
+    def render_widgets(self, session):
+        writer = Writer()
+        sess = self.session.get(session)
+        widgets = self.widgets.get(session)
+
+        for widget in widgets:
+            self.widget_tmpl.render(writer, sess, widget)
+
+        return writer.to_string()
+
+    def render_widget_id(self, session, widget):
+        return widget.path
+
+    def render_widget(self, session, widget):
+        return widget.render(session)
+
+    class SessionParameter(Parameter):
+        def do_marshal(self, session):
+            return session.marshal()
+
+        def do_unmarshal(self, string):
+            return Session.unmarshal(self.app, string)
+
+    class WidgetParameter(Parameter):
+        def __init__(self, app, name, page):
+            self.page = page
+
+        def do_marshal(self, widget):
+            return widget.path
+
+        def do_unmarshal(self, path):
+            return self.page.widgets_by_path.get(path)
+
 class CssPage(Page):
     def __init__(self, app, name):
         super(CssPage, self).__init__(app, name)
 
+        self.html_page = None
         self.__then = datetime.utcnow()
         self.__css = None
 
@@ -40,6 +136,7 @@
     def __init__(self, app, name):
         super(JavascriptPage, self).__init__(app, name)
 
+        self.html_page = None
         self.__then = datetime.utcnow()
         self.__javascript = None
 

Added: mgmt/trunk/wooly/python/wooly/pages.strings
===================================================================
--- mgmt/trunk/wooly/python/wooly/pages.strings	                        (rev 0)
+++ mgmt/trunk/wooly/python/wooly/pages.strings	2009-03-18 15:33:33 UTC (rev 3161)
@@ -0,0 +1,36 @@
+[HtmlPage.html]
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+  <head>
+    <title>{title}</title>
+
+    <meta http-equiv="X-UA-Compatible" content="IE=7"/>
+
+    <link rel="shortcut icon" href="resource?name=favicon.ico" type="image/x-icon"/>
+
+    <link rel="stylesheet" type="text/css" href="resource?name=wooly.css"/>
+    <link rel="stylesheet" type="text/css" href="resource?name=app.css"/>
+    <link rel="stylesheet" type="text/css" href="{id}.css"/>
+    <!--[if IE]><link rel="stylesheet" type="text/css" href="resource?name=ie.css"/><![endif]-->
+
+    <script type="text/javascript" src="resource?name=wooly.js"> </script>
+    <script type="text/javascript" src="resource?name=app.js"> </script>
+    <script type="text/javascript" src="{id}.js"> </script>
+    <script type="text/javascript">
+      // <![CDATA[
+      wooly.newSetIntervalUpdate('{update_url}', wooly.updatePage, 3000);
+      // ]]>
+    </script>
+  </head>
+  <body class="{class}">
+    {content}
+  </body>
+</html>
+
+[UpdatePage.html]
+<?xml version="1.0" encoding="UTF-8"?>
+<widgets>{widgets}</widgets>
+
+[UpdatePage.widget_html]
+<widget id="{widget_id}">{widget}</widget>

Modified: mgmt/trunk/wooly/python/wooly/parameters.py
===================================================================
--- mgmt/trunk/wooly/python/wooly/parameters.py	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/wooly/python/wooly/parameters.py	2009-03-18 15:33:33 UTC (rev 3161)
@@ -59,6 +59,7 @@
 
         self.is_collection = True
 
+    # XXX eliminate
     def set_element_parameter(self, param):
         self.param = param
 

Added: mgmt/trunk/wooly/resources/wooly.css
===================================================================
--- mgmt/trunk/wooly/resources/wooly.css	                        (rev 0)
+++ mgmt/trunk/wooly/resources/wooly.css	2009-03-18 15:33:33 UTC (rev 3161)
@@ -0,0 +1,33 @@
+body {
+  margin: 0;
+  padding: 0;
+  background-color: #fff;
+  font-size: 0.9em;
+  font-family: "DejaVu LGC Sans", "Bitstream Vera Sans", "Lucida Grande",
+               "Trebuchet MS", verdana, helvetica, arial, sans-serif;
+}
+
+h1 {
+  font-size: 1.1em;
+}
+
+h2 {
+  font-size: 1em;
+}
+
+h3 {
+  font-size: 0.9em;
+}
+
+a {
+  text-decoration: none;
+  color: #06c;
+}
+
+a.selected {
+  color: black;
+}
+
+img {
+  border: none;
+}

Modified: mgmt/trunk/wooly/resources/wooly.js
===================================================================
--- mgmt/trunk/wooly/resources/wooly.js	2009-03-17 20:54:29 UTC (rev 3160)
+++ mgmt/trunk/wooly/resources/wooly.js	2009-03-18 15:33:33 UTC (rev 3161)
@@ -26,7 +26,7 @@
 
     function translate(node, parent) {
         //log("node", node.nodeType, node, "parent", parent);
-        
+
         var first = node.firstChild;
         var name = node.nodeName;
 
@@ -129,7 +129,7 @@
 
         for (var i = 0; i < names.length; i++) {
             var elems = elem.getElementsByTagName(names[i]);
-            
+
             if (elems.length) {
                 node = elems[0];
             } else {
@@ -198,54 +198,136 @@
         }
     }
 
+    function updatePage(xml) {
+        var child = xml.documentElement.firstChild;
+
+        while (child) {
+            if (child.nodeType == 1 && child.nodeName == "widget") {
+                var id = child.getAttribute("id");
+                var oldElem = document.getElementById(id);
+
+                if (oldElem) {
+                    var newElem = child.firstChild;
+
+                    if (newElem.nodeType != 1) {
+                        newElem = newElem.nextSibling;
+                    }
+
+                    replaceNode(newElem, oldElem);
+                } else {
+                    wooly.log("Element '" + id + "' not found");
+                }
+            }
+
+            child = child.nextSibling;
+        }
+    }
+
+    var damnyouie = /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent);
+
+    function replaceNode(newNode, oldNode) {
+        var node = copyNode(newNode, true);
+        oldNode.parentNode.replaceChild(node, oldNode);
+
+        if (node.outerHTML) {
+            // Damn you straight to hell, IE!
+            node.outerHTML = node.outerHTML;
+        }
+    }
+
+    function copyNode(node) {
+        switch (node.nodeType) {
+            case 1:
+                return copyElement(node);
+            case 3:
+            case 4:
+                return document.createTextNode(node.nodeValue);
+            default:
+                return null;
+        }
+    }
+
+    function copyElement(node) {
+        var newElem = document.createElement(node.nodeName);
+
+        // XXX consider using hasAttributes here
+        if (node.attributes && node.attributes.length > 0) {
+            var len = node.attributes.length;
+
+            for (var i = 0; i < len; i++) {
+                var attr = node.getAttribute(node.attributes[i].nodeName);
+                newElem.setAttribute(node.attributes[i].nodeName, attr);
+            }
+        }
+
+        var child = node.firstChild;
+
+        while (child) {
+            var newChild = copyNode(child);
+
+            if (newChild) {
+                newElem.appendChild(newChild);
+            }
+
+            child = child.nextSibling;
+        }
+
+        return newElem;
+    }
+
+    function getNewRequest() {
+        var request;
+
+        if (window.XMLHttpRequest) {
+            request = new XMLHttpRequest();
+        } else {
+            if (window.ActiveXObject) {
+                try {
+                    request = new ActiveXObject("Microsoft.XMLHTTP");
+                } catch (e) {
+                    request = new ActiveXObject("Msxml2.XMLHTTP");
+                }
+            }
+        }
+
+        return request;
+    }
+
+
     function Wooly() {
-		this.getNewRequest = function() {
-			var request;
-			if (window.XMLHttpRequest) {
-	        	request = new XMLHttpRequest();
-			}
-			else {
-				if (window.ActiveXObject) {
-					try {			
-		        		request = new ActiveXObject("Microsoft.XMLHTTP");
-					} catch (e) {
-						request = new ActiveXObject("Msxml2.XMLHTTP");
-					}
-				}
-			}
-			return request;
-		}
-		
+        if (window.console) {
+            this.console = window.console;
+        }
+
         this.assert = assert;
         this.log = log;
         this.dir = dir;
-        this.updater_ids = [];
 
-        if (window.console) {
-            this.console = window.console;
-        }
+        this.getNewRequest = getNewRequest
+        this.updatePage = updatePage
 
+        this.updaterIDs = [];
 
-		this.deferredUpdate = function(url, callback, passback) {
+        this.deferredUpdate = function(url, callback, passback) {
             var req = this.getNewRequest();
 
             req.open("get", url, true);
             req.onreadystatechange = update;
             req.send(null);
-			
+
             function update() {
                 try {
                     if (req.readyState == 4 && req.status == 200) {
-                    	data = wooly.doc(req.responseXML);
-			            var obj = data.objectify();
-						callback(obj, passback);
+                        var data = wooly.doc(req.responseXML);
+                        var obj = data.objectify();
+                        callback(obj, passback);
                     }
                 } catch (e) {
                     log(e);
                     throw e;
                 }
             }
-		}
+        }
 
         this.setIntervalUpdate = function(url, callback, interval) {
             var req = this.getNewRequest();
@@ -257,9 +339,9 @@
             }
 
             var id = window.setInterval(fetch, interval);
-            
-            this.updater_ids.push(id);
 
+            this.updaterIDs.push(id);
+
             function update() {
                 try {
                     if (req.readyState == 4 && req.status == 200) {
@@ -277,9 +359,37 @@
             }
         }
 
+        this.newSetIntervalUpdate = function(url, callback, interval) {
+            var req = this.getNewRequest();
+
+            function fetch() {
+                req.open("get", url, true);
+                req.onreadystatechange = update;
+                req.send(null);
+            }
+
+            var id = window.setInterval(fetch, interval);
+
+            this.updaterIDs.push(id);
+
+            function update() {
+                try {
+                    if (req.readyState == 4 && req.status == 200) {
+                        callback(req.responseXML);
+                    }
+                } catch (e) {
+                    log(e);
+                    // XXX might want to retry for a bit before we do
+                    // this
+                    window.clearInterval(id);
+                    throw e;
+                }
+            }
+        }
+
         this.clearUpdates = function() {
-            for (var i = 0; i < this.updater_ids.length; i++) {
-                window.clearInterval(this.updater_ids[i])
+            for (var i = 0; i < this.updaterIDs.length; i++) {
+                window.clearInterval(this.updaterIDs[i])
             }
         }
 
@@ -393,7 +503,7 @@
 
         this.add = function(content) {
             assert(content);
-            
+
             if (typeof content == "string") {
                 // XXX flatten this out
                 this.add(new WoolyText(this.doc, null).set(content));
@@ -495,8 +605,8 @@
         assert(doc);
         assert(doc instanceof WoolyDocument);
         if (node) {
-        	//assert(node instanceof Node);
-        	assert(node.nodeType == 3);
+        //assert(node instanceof Node);
+        assert(node.nodeType == 3);
         }
 
         this.doc = doc;




More information about the rhmessaging-commits mailing list