Moksha Dashboard Container Widgets

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 Format

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.

  • Category ‘Test Applications’ - This tells the container that you want to group a number of applications under the ‘Test Application’ title which in essence creates a div with class ‘test_applications’. You may also want to specify css_class instead of relying on the label.
  • MokshaApp ‘Hello World 1’: here we dynamically load the moksha application installed on the moksha.application entry point as moksha.helloworld. We then send it a dictionary of keys - in this case the key ‘name’.
  • App ‘Hello World 2’: This is the same as the above but instead of giving the application name we give it the url the application is mounted on. We also send in different configuration data. The App object allows for non moksha web apps and static content to be placed in a container.
  • MokshaWidget ‘Hello World 3’: Again this is the same as above but we pass in a widget installed on the 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.

Tabbed Container

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.

Dashboard Container

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.

Issues

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.

  • Id’s may clash. It is suggested that when using jQuery or any other javascript dom tool to generate a uuid and do all of your selections relative to that id. It is also suggested you namespace your id’s and only use classes to style.
  • Javascript may load more than once. If all you uses is widgets you are fine as ToscaWidgets will take care of duplicate resource requests. However a powerful concept in moksha is the ability to load applications asynchronously so that the user does not have to wait for the server to finish processing a page before any data is streamed to them. It is suggested you make heavy use of global resources in order to aleviate the issue. At some point we may introduce a way for the browser to filter out already loaded javascript and other resources.