moksha/api/widgets/__init__.py | 1
moksha/api/widgets/containers/dashboardcontainer.py | 2
moksha/api/widgets/containers/tabbedcontainer.py | 14 +
moksha/api/widgets/containers/templates/layout_applist.mak | 4
moksha/api/widgets/containers/templates/tabbedcontainer_panes.mak | 7
moksha/api/widgets/containers/templates/tabbedcontainer_tabs.mak | 9
moksha/api/widgets/placeholder.py | 11 +
moksha/lib/helpers.py | 103 +++++++---
moksha/middleware/middleware.py | 5
setup.py | 2
10 files changed, 124 insertions(+), 34 deletions(-)
New commits:
commit 474f4570361b47ff61d22dcba70c0f840f614e26
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Wed Feb 4 16:05:00 2009 -0500
add placeholders and fix up containers to be more consitant and easier to use
* added the TabbedContainerPanes and TabbedContainerTabs widgets to abstract
out displaying apps inside of containers. Now if the internal config
format changes a bit apps won't break if they use the standard display
widgets
* fixed a few bugs with displaying widgets that had parameters
diff --git a/moksha/api/widgets/__init__.py b/moksha/api/widgets/__init__.py
index 38b79ba..6449275 100644
--- a/moksha/api/widgets/__init__.py
+++ b/moksha/api/widgets/__init__.py
@@ -1,4 +1,5 @@
from live import LiveWidget
from util import *
from grid import Grid
+from placeholder import Placeholder
diff --git a/moksha/api/widgets/containers/dashboardcontainer.py b/moksha/api/widgets/containers/dashboardcontainer.py
index 41732bf..6892d6f 100644
--- a/moksha/api/widgets/containers/dashboardcontainer.py
+++ b/moksha/api/widgets/containers/dashboardcontainer.py
@@ -7,7 +7,7 @@ from tg import config
class AppListWidget(Widget):
template = 'mako:moksha.api.widgets.containers.templates.layout_applist'
- properties = ['layout', 'category']
+ properties = ['category']
def update_params(self, d):
super(AppListWidget, self).update_params(d)
diff --git a/moksha/api/widgets/containers/tabbedcontainer.py b/moksha/api/widgets/containers/tabbedcontainer.py
index 1111084..00e5898 100644
--- a/moksha/api/widgets/containers/tabbedcontainer.py
+++ b/moksha/api/widgets/containers/tabbedcontainer.py
@@ -1,10 +1,20 @@
from tw.jquery.ui_tabs import JQueryUITabs
+from tw.api import Widget
from pylons import config, request
from repoze.what import predicates
from moksha.lib.helpers import eval_app_config, ConfigWrapper
import urllib
+class TabbedContainerTabs(Widget):
+ template = 'mako:moksha.api.widgets.containers.templates.tabbedcontainer_tabs'
+
+class TabbedContainerPanes(Widget):
+ template = 'mako:moksha.api.widgets.containers.templates.tabbedcontainer_panes'
+
+tabwidget = TabbedContainerTabs('tabs')
+panewidget = TabbedContainerPanes('panes')
+
"""
:Name: TabbedContainer
:Type: Container
@@ -49,3 +59,7 @@ class TabbedContainer(JQueryUITabs):
# not allowed to run with the current session's authorization level
tabs = ConfigWrapper.process_wrappers(tabs)
d['tabs'] = tabs
+ d['tabwidget'] = tabwidget
+ d['panewidget'] = panewidget
+ d['root_id'] = d['id']
+
diff --git a/moksha/api/widgets/containers/templates/layout_applist.mak b/moksha/api/widgets/containers/templates/layout_applist.mak
index 0fa4464..af2021a 100644
--- a/moksha/api/widgets/containers/templates/layout_applist.mak
+++ b/moksha/api/widgets/containers/templates/layout_applist.mak
@@ -6,11 +6,11 @@
% endif
<dd id="${app['id']}">
% if app.has_key('widget'):
- ${app['widget'](app['params'])}
+ ${app['widget'](**app['params'])}
% endif
</dd>
- % if app.has_key('url'):
+ % if not app.has_key('widget'):
<script type="text/javascript">
$("#${app['id']}").load("${app['url']}");
</script>
diff --git a/moksha/api/widgets/containers/templates/tabbedcontainer_panes.mak b/moksha/api/widgets/containers/templates/tabbedcontainer_panes.mak
new file mode 100644
index 0000000..5bc58b7
--- /dev/null
+++ b/moksha/api/widgets/containers/templates/tabbedcontainer_panes.mak
@@ -0,0 +1,7 @@
+% for t in tabs:
+ <div id="${t['content_id']}">
+ % if t.has_key('widget'):
+ ${t['widget'](**t['params'])}
+ % endif
+ </div>
+% endfor
\ No newline at end of file
diff --git a/moksha/api/widgets/containers/templates/tabbedcontainer_tabs.mak b/moksha/api/widgets/containers/templates/tabbedcontainer_tabs.mak
new file mode 100644
index 0000000..6bcaab3
--- /dev/null
+++ b/moksha/api/widgets/containers/templates/tabbedcontainer_tabs.mak
@@ -0,0 +1,9 @@
+<ul id="${root_id}">
+ % for t in tabs:
+ <li>
+ <a href="${t['url']}" title="${t['content_id']}">
+ ${t['label']}
+ </a>
+ </li>
+ % endfor
+</ul>
diff --git a/moksha/api/widgets/placeholder.py b/moksha/api/widgets/placeholder.py
new file mode 100644
index 0000000..656580e
--- /dev/null
+++ b/moksha/api/widgets/placeholder.py
@@ -0,0 +1,11 @@
+from tw.api import Widget
+
+class Placeholder(Widget):
+ engine_name = 'mako'
+ template = """
+<div class='placeholder'>
+ Moksha application <strong>${appname}</strong> is not registered yet. This is a placeholder
+ for testing purposes. When the app is registered it will appear in the
+ layout once the server is restarted.
+</div>
+"""
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py
index 7d9982b..e08b732 100644
--- a/moksha/lib/helpers.py
+++ b/moksha/lib/helpers.py
@@ -117,25 +117,34 @@ class App(ConfigWrapper):
:Example:
hello_app = App('Hello World App',
'/appz/moksha.helloworld',
- {'greeter_name': 'J5'},
- not_anonymous())
+ params={'greeter_name': 'J5'},
+ auth=not_anonymous())
"""
- def __init__(self, label="", url="", req_params=None, auth=None):
+ def __init__(self, label="", url="", content_id="",
+ params=None, auth=None):
"""
:label: The title the application should use when rendering
in a container. Leave this blank if you do not wish the
application to be visibly labeled when rendered
:url: the url to load this application from
- :req_params: A dict of request parameters to send to the application
- when loading it from a url
+ :content_id: the id to use for url navigation and associating the
+ content with a control such as tabs needing to know
+ which div to add the content to when selected. If
+ this is not set we scrub the label of illegal characters
+ lower case it and use that as the content_id
+ :params: A dict of request parameters to send to the application
+ when loading it from a url
:auth: A list of predicates which are evaluate before the wrapper
is sent to the container. If it evaluates to False it does not
get sent.
"""
self.label = label
self.url = url
- self.req_params = req_params or {}
+ self.params = params or {}
self.auth = auth or []
+ self.content_id = content_id
+ if self.label and not self.content_id:
+ self.content_id = scrub_filter.sub('_', self.label.lower())
def process(self):
"""Check the predicates and construct the dict
@@ -146,12 +155,13 @@ class App(ConfigWrapper):
return None
query_str = ""
- if self.req_params:
- query_str = "?" + urllib.urlencode(self.req_params)
+ if self.params:
+ query_str = "?" + urllib.urlencode(self.params)
id = uuid.uuid4()
- return {'label': self.label, 'url': self.url + query_str, 'id': id}
+ return {'label': self.label, 'url': self.url + query_str, 'id': id,
+ 'content_id': self.content_id}
class MokshaApp(App):
"""A configuration wrapper class that displays a Moksa application
@@ -163,26 +173,44 @@ class MokshaApp(App):
:Example:
hello_app = App('Hello World Moksha App',
'moksha.helloworld',
- {'greeter_name': 'J5'},
- not_anonymous())
+ params={'greeter_name': 'J5'},
+ auth=not_anonymous())
"""
-
- def __init__(self, label="", moksha_app="", req_params=None, auth=None):
+ def __init__(self, label="", moksha_app="", content_id="",
+ params=None, auth=None):
"""
:label: The title the application should use when rendering
in a container. Leave this blank if you do not wish the
application to be visibly labeled when rendered
:moksha_app: the name of the entry point registered under the
moksha.application section
- :req_params: A dict of request parameters to send to the application
- when loading it
+ :content_id: the id to use for url navigation and associating the
+ content with a control such as tabs needing to know
+ which div to add the content to when selected. If
+ this is not set we scrub the label of illegal characters
+ lower case it and use that as the content_id
+ :params: A dict of request parameters to send to the application
+ when loading it
:auth: A list of predicates which are evaluate before the wrapper
is sent to the container. If it evaluates to False it does not
get sent.
"""
# FIXME figure out how to pull auth info from an app
- super(MokshaApp, self).__init__(label, '/appz/' + moksha_app, req_params, auth)
+ self.app = moksha_app
+ super(MokshaApp, self).__init__(label,
+ '/appz/' + moksha_app,
+ content_id,
+ params, auth)
+
+ def process(self):
+ # We return a placeholder if the app is not registered
+ if not moksha._apps.has_key(self.app):
+ return MokshaWidget(self.label, 'placeholder',
+ self.content_id,
+ {'appname':self.app}, self.auth).process()
+
+ return super(MokshaApp, self).process()
class Widget(ConfigWrapper):
"""A configuration wrapper class that displays a ToscaWidget. Use this
@@ -196,16 +224,22 @@ class Widget(ConfigWrapper):
hello_widget = Widget('Hello World Widget',
HelloWidget(),
- {'greeter_name': 'J5'},
- not_anonymous())
+ params={'greeter_name': 'J5'},
+ auth=not_anonymous())
"""
- def __init__(self, label="", widget="", params=None, auth=None):
+ def __init__(self, label="", widget=None, content_id="",
+ params=None, auth=None):
"""
:label: The title the widget should use when rendering
in a container. Leave this blank if you do not wish the
widget to be visibly labeled when rendered
:widget: the ToscaWidget to be rendered
+ :content_id: the id to use for url navigation and associating the
+ content with a control such as tabs needing to know
+ which div to add the content to when selected. If
+ this is not set we scrub the label of illegal characters
+ lower case it and use that as the content_id
:params: A dict of parameters to send to the widgets update_params
method when rendering it
:auth: A list of predicates which are evaluate before the wrapper
@@ -217,13 +251,18 @@ class Widget(ConfigWrapper):
self.params = params or {}
self.auth = auth or []
+ self.content_id = content_id
+ if self.label and not content_id:
+ self.content_id = scrub_filter.sub('_', self.label.lower())
+
def process(self):
if not check_predicates(self.auth):
return None
id = uuid.uuid4()
-
- return {'label': self.label, 'widget': self.widget , 'params':self.params, 'id': id}
+ url = '#' + self.content_id
+ return {'label': self.label, 'url': url,'widget': self.widget ,
+ 'params':self.params, 'id': id, 'content_id': self.content_id}
class MokshaWidget(Widget):
"""A configuration wrapper class that displays a ToscaWidget registered
@@ -232,25 +271,33 @@ class MokshaWidget(Widget):
:Example:
hello_moksha_widget = Widget('Hello Moksha Widget',
'moksha.hello',
- {'greeter_name': 'J5'},
- not_anonymous())
+ params={'greeter_name': 'J5'},
+ auth=not_anonymous())
"""
- def __init__(self, label="", name="", params=None, auth=None):
+ def __init__(self, label="", moksha_widget="", content_id="",
+ params=None, auth=None):
"""
:label: The title the widget should use when rendering
in a container. Leave this blank if you do not wish the
widget to be visibly labeled when rendered
- :name: the name of the entry point registered under the
- moksha.widget section
+ :content_id: the id to use for url navigation and associating the
+ content with a control such as tabs needing to know
+ which div to add the content to when selected. If
+ this is not set we scrub the label of illegal characters
+ lower case it and use that as the content_id
+ :moksha_widget: the name of the entry point registered under the
+ moksha.widget section
:params: A dict of parameters to send to the widgets update_params
method when rendering it
:auth: A list of predicates which are evaluate before the wrapper
is sent to the container. If it evaluates to False it does not
get sent.
"""
- widget = moksha._widgets[name]['widget']
- super(MokshaWidget, self).__init__(label=label, widget=widget, params=params, auth=auth)
+ widget = moksha._widgets[moksha_widget]['widget']
+ super(MokshaWidget, self).__init__(label=label, widget=widget,
+ content_id=content_id, params=params,
+ auth=auth)
# setup the dictionary of acceptable callables when eval'ing predicates from
diff --git a/moksha/middleware/middleware.py b/moksha/middleware/middleware.py
index 701f7d5..aee95e0 100644
--- a/moksha/middleware/middleware.py
+++ b/moksha/middleware/middleware.py
@@ -70,8 +70,7 @@ class MokshaMiddleware(object):
self.feed_cache = Cache(self.feed_storage)
def __call__(self, environ, start_response):
- environ['paste.registry'].register(moksha.apps, self.apps)
-
+ # environ['paste.registry'].register(moksha.apps, self.apps)
# environ['paste.registry'].register(moksha._widgets, self.widgets)
environ['paste.registry'].register(moksha.feed_cache, self.feed_cache)
environ['paste.registry'].register(moksha.menus, self.menus)
@@ -148,6 +147,8 @@ class MokshaMiddleware(object):
except ImportError:
pass
+ moksha._apps = self.apps
+
def load_widgets(self):
log.info('Loading moksha widgets')
for widget_entry in pkg_resources.iter_entry_points('moksha.widget'):
diff --git a/setup.py b/setup.py
index 2f17bc3..6ae206c 100644
--- a/setup.py
+++ b/setup.py
@@ -64,7 +64,7 @@ setup(
#livegraph = moksha.examples.livegraph:LiveGraphWidget
#grid = moksha.api.widgets:Grid
ptd = moksha.widgets.misc.ptd:ProcessedTowerDefense
-
+ placeholder = moksha.api.widgets:Placeholder
[moksha.global]
# The pipeline for our live widgets