Moksha container widgets provide configurable containers for loading Moksha applications and widgets. They are used for layout, navigation and dynamic loading of content on your site. The configuration format for specifying components to load into containers make it easy to dynamically store and update configuration information including location and default settings of an application. Containers can load applications asynchronously through JavaScript or pull in a widget during the initial request. Since containers are widgets themselves containers can be nested.
Configuration for each container is done using a restricted python syntax and can be passed to the container as a string or a Python object. Strings are mainly used when reading from a configuration file but can also be used to avoid having to import the configuration wrapper objects.
Here is an example of what a configuration line could look like:
dashboard_layout = [
Category('Test Applications', [
MokshaApp('Hello World 1',
'moksha.helloworld',
{'name': 'J5'}),
App('Hello World 2',
'/apps/moksha.helloworld',
{'name': 'Luke'}),
MokshaWidget('Hello World 3',
'moksha.helloworldwidget',
{'name': 'Anonymous'},
auth=Not(not_anonymous())),
]
)
]
This would be a configuration for the dashboard container discussed bellow. It defines one category, two applications and a widget. How this is laid out in your final view is up to the template and css. The default view is setup to load each component into it’s category div in order. You can then specify CSS to position those categories in your layout.
Lets look at each individual component.
moksha.application
entry point as moksha.helloworld
.
We then send it a dictionary of keys - in this case the key ‘name’.moksha.widget
entry point as
moksha.helloworldwidget
. We also pass in a auth predicate. If the
authorization evaluates to True, in this case if the user is anonymous, the
widget will be embedded in the page. If not then it is removed. Predicates
are defined by the :module:`repoze.what.authorize` module and can be added to
any ConfigWrapper.moksha.api.widgets.containers.TabbedContainer
A tabbed container is a container that places components in a jQuery.ui.tabs javascript widget. Applications are then dynamically loaded when that tab is selected. Widgets placed in a tabbed container are continuously running while the tabbed container is active even if not visible. It is important to not load widgets that have a high resource requirement. Tabbed containers must be subclassed in order to point it to the correct resources.
Here is an example on how to subclass a TabbedContainer:
mainnav.py
from moksha.api.widgets.containers import TabbedContainer
class MainNav(TabbedContainer):
template = 'mako:myapp.templates.mainnav'
config_key = 'myapp.mainnav.apps'
mainnav.mak
<div>
<ul id="${id}">
% for t in tabs:
<li>
% if t.has_key('url'):
<a href="${t['url']}" title="${t['label']} Page">
${t['label']}
</a>
% else
${t['label']}
% endif
</li>
% endfor
</ul>
</div>
<div id="content">
% for t in tabs:
<div id="${t['label']}_Page">
% if t.has_key('widget'):
${t['widget'](t['params'])}
% endif
</div>
% endfor
</div>
development.ini
[DEFAULT]
myapp.mainnav.apps = (MokshaApp('Home', 'myapp.home'),
MokshaApp('2nd Tab', 'myapp.tab2'),
MokshaApp('3rd Tab','myapp.tab3',
auth=not_anonymous()),
MokshaApp('4th Tab', 'myapp.tab4',
auth=Not(not_anonymous())
)
)
It should be noted that the template boilerplate should be handled automatically in the future.
moksha.api.widgets.containers.DashboardContainer
A dashboard container is a container that places components in a jQuery.ui.sortable javascript widget. Applications are dynamically loaded in the order they are placed in the configuration. Dashboard containers must be subclassed in order to point it to the correct resources.
Here is an example on how to subclass a DashboardContainer:
homepage.py
from moksha.api.widgets.containers import DashboardContainer
class HomePageContainer(DashboardContainer):
template = 'mako:myapp.templates.homepagecontainer'
layout = [Category('left-content-column',
[App('Banner', '/static-html/sitebanner.html'),
MokshaApp('Stable Updates','myapp.updates/table',
{"some_json":'{"status":"stable"}'}
),
MokshaApp('Testing Updates','myapp.updates/table',
{"some_json":'{"status":"testing"}'}
),
]),
Category('right-content-column',
MokshaWidget(None, 'myapp.loginwidget',
auth=Not(not_anonymous())
)
)
]
homepagecontainer.mak
<div id="${id}">
<div>
<div id="right-content-column">
${applist_widget(category = 'right-content-column', layout = layout)}
</div>
<div id="left-content-column">
${applist_widget(category = 'left-content-column', layout = layout)}
</div>
</div>
</div>
Notice above that I decided to use the layout calls variable instead of a configuration key. Either form is acceptable for any container.
Moving from a model where you piece everything together on the server to dynamically loading content in the browser means that there are some issues to consider.