Skip to main content

Working with Plugins

Zen Mojo plugins are utility classes containing layout objects that provide access to several popular third-party JavaScript libraries and frameworks. Zen Mojo currently provides plugins for the Twitter Bootstrap library, the Chart.js library, the ChocolateChip-UI framework, the Dojo Toolkit, the Google Maps API, the Highcharts library, the jQuery Mobile framework, and HTML5 standard. You can also extend Zen Mojo by creating your own plugins for other third-party libraries.

This chapter discusses the following topics:

Overview

A Zen Mojo application consists of the following primary components:

  • one or more template classes, which determine what is displayed on your web page

  • a set of plugin classes, which define the layout objects used by the templates

  • the page class, which specifies the plugin classes and other resources available to your template classes

A set of plugins must by specified for each documentView defined in the pageContents XData block of your page class (for details, see “Adding Plugins to the Page Class” later in this chapter).

Each documentView element must specify a single page manager plugin, which will contain one or more helper plugins. Each helper plugin defines a set of layout objects. These elements perform the following functions:

  • A page manager plugin provides the interface between the templates and a set of helper plugins.

    The page manager creates a list of all layout objects defined in the specified list of helper plugins, and resolves any naming conflicts (for example, two helper plugins may define two different button layout objects). Page managers may also provide library-specific utility functions that can be used by all layout objects associated with a given JavaScript library or framework.

  • Helper plugins define layout objects and other library-specific resources used by template classes.

    When you specify a helper plugin in your page class, the layout objects defined in that helper become available to your template classes. A helper plugin may also provide additional resources, such as utility methods for common tasks.

  • Layout objects use library functions to produce HTML strings.

    A template class uses one or more layout objects to determine the appearance of your web page. A typical layout object renders a graphical element, usually by using a corresponding element in the JavaScript library. For example, a button layout object might render itself by calling a button function in the library.

Choosing Plugins for Your Application

Zen Mojo provides plugins for several popular JavaScript libraries and frameworks. When designing your Zen Mojo application, pick the helpers that you will need, and then chose a page manager that supports all of them.

The following helper plugins can be used in any application:

  • Zen Mojo Default helper — provides utility layout objects used by most helper plugins. It can be used by any page manager (not just the Default page manager).

  • HTML5 helper — provides layout objects for most standard HTML5 elements.

  • Bootstrap helper — provides layout objects for many of Twitter Bootstrap’s enhanced versions of HTML5 elements.

  • Chart.js helper — provides layout objects for the lightweight Chart.js library.

  • Highcharts helper — similar to Chart.js, but Highcharts provides a much greater variety of charts.

  • Google Maps helper — provides layout objects that support an online connection to the Google Maps API.

These helper plugins can be used with any page manager.

All other helper plugins require support for a specific JavaScript library or framework, and can only be used by the page manager that provides that support. The following page managers and specialized helpers are available:

  • The Default page manager supports only the previously listed helpers.

  • The ChocolateChip-UI page manager supports a helper containing layout objects for the enhanced ChocolateChip-UI versions of HTML5 elements. This page manager is best for relatively simple mobile applications.

  • The jQuery Mobile page manager supports a helper containing layout objects for the long list jQuery Mobile enhanced HTML5 elements. This page manager may be preferable for complex mobile applications.

  • The Dojo page manager supports three helpers for three different APIs in the Dojo Toolkit. This page manager is best for complex desktop applications.

Adding Plugins to the Page Class

Plugins are added to your application by specifying some or all of the following items in the page class:

  • External JavaScript and CSS files

    Most helper plugins depend on external JavaScript and CSS files. All required files should be located in or under <install-dir>/csp/broker (where <install-dir> is the is directory in which Caché is installed). Lists of installed files are specified as comma-delimited strings in the JSINCLUDES and CSSINCLUDES (or CSS3INCLUDES) parameters. The following example demonstrates how to list the required files for the Bootstrap helper plugin:

    Parameter JSINCLUDES As STRING = "jquery-1.11.3.min.js,bootstrap-3.3.5/js/bootstrap.min.js"
    Parameter CSSINCLUDES As STRING = "bootstrap-3.3.5/css/bootstrap.min.css"
    

    Caché assumes that /csp/broker is the root directory for each of these paths and filenames.

    The order of the JSINCLUDES list determines the order in which the JavaScript libraries will be loaded, from left to right. In this example, the jQuery library must be loaded first because the Bootstrap library depends on it.

  • Plugin page manager and helper classes

    In the pageContents XData block of your page class, you must register one or more plugins for use in each documentView (see “Basic Definition of a Zen Mojo Page” in the book Using Zen Mojo). To do so:

    • Include only one page manager plugin as a child element of <mojo:documentView>.

    • Include one or more helper plugins as child elements of the page manager plugin.

    The following example shows the general structure (with optional indentation for clarity):

      <mojo:documentView id="mainView" ongetlayout = "return zenPage.getContent('layout',key);">
        <mojo:mojoDefaultPageManager>
          <mojo:bootstrap-3.3.x-Helper/>
          <mojo:mojoDefaultHelper/>
        </mojo:mojoDefaultPageManager>
      </mojo:documentView>
    

    The order in which you list helper plugins is important. When two plugins use the same name for a layout object, your application will use the layout object from the plugin listed first. Later instances of layout objects with the same name will be ignored. See “Detecting and Resolving Plugin Conflicts” for details.

  • Required page methods

    Depending on the plugins you choose, your page class may have to implement certain required methods. See “Implementing Required Methods in the Page Class” for details.

For each plugin or set of plugins, this book describes all page class requirements at the beginning of the relevant chapter. See the Bootstrap chapter for the information used in the previous examples.

Detecting and Resolving Plugin Conflicts

It is important to consider the order in which you list the helper plugins, in the case of plugin conflict. A plugin conflict occurs when a single documentView uses multiple helper plugins and those plugins have layout objects with the same name. A plugin conflict is not an error condition, but rather a situation that requires special handling. There is a default behavior and a way to override it.

In the case of a plugin conflict, by default, Zen Mojo uses the layout object rendering logic as given in the helper plugin that is listed first. If you do not want the default behavior, you can modify it.

To override the default handling, do the following:

  • Specify the onresolvepluginconflicts callback attribute of the documentView. Use a value like the following:

      onresolvepluginconflicts="zenPage.onResolvePluginConflicts(zenThis, conflicts);"
    

    In this callback, you can use the variable conflicts, which Zen Mojo provides. This variable is an array that contains the names of layout objects defined by more than one plugin.

  • Implement the method to which your callback attribute refers. In this method, use the setPluginMapping() method of the documentView instance. The following shows a simple example:

      ClientMethod onResolvePluginConflicts(docView, conflicts) [ Language = javascript ]
      {
        for (prop in conflicts) {
            if (conflicts[prop].indexOf('HTML5') > -1) {
                docView.setPluginMapping(prop, 'HTML5');
            }
            else if (conflicts[prop].indexOf('html5') > -1) {
                docView.setPluginMapping(prop, 'html5');
            }
        }
      }
    

    For any given layout object type, your implementation can specify which helper plugin should perform the rendering for that layout object type.

Implementing Required Methods in the Page Class

Depending on the plugins you choose, your application may have to implement the adjustContentSize() method or the onPageShow() callback, as described in the following sections:

Overriding the adjustContentSize() Page Method

An override for the basePage.adjustContentSize() page method must be implemented in your page class if it uses the Default page manager or the Dojo page manager.

The purpose of the adjustContentSize() method is to specify the size and position of each documentView, based on the current width and height of the pageContents pane, which varies depending on the screen size and current rotation. This method is called when the basePage.onlayoutHandler() event is triggered. It has the following signature:

  ClientMethod adjustContentSize(load, width, height) [ Language = javascript ]

Where load indicates if the page is being loaded. This argument is 1 when the page is loaded and is 0 at other times. width and height are the current width and height, respectively, of the pageContents pane, in pixels.

In this method, it is typically necessary to do the following for each documentView on this page:

  • Get a reference to the documentView and call its setSize() method. The following example gets an instance of documentView with id mainView, and uses the width and height arguments received when adjustContentSize() is called from onlayoutHandler():

      var mainView = zen('mainView');
      mainView.setSize(width, height);
    

    where width and height are the desired width and height in pixels.

  • If there is more than one documentView on the page, specify the position of the top, left corner of each documentView. Use the documentView.getEnclosingDiv() instance method to get the <div> that contains the instance, then specify the style.top and style.left properties of the <div>. Specify the values as 'nnnpx' where nnn is an integer. For example:

      var mainDiv = mainView.getEnclosingDiv();
      mainDiv.style.top =  '0px';
      mainDiv.style.left = '0px';
    
    
Example: Implementing adjustContentSize() for a page with two documentView instances

In the following example, there are two documentView instances. The left one is one-fourth of the width of the pageContents area, and the right one uses the rest of the space.

ClientMethod adjustContentSize(load, width, height) [ Language = javascript ]
{
    var leftView = zen('leftView');
    var mainView = zen('mainView');
    var leftWidth = Math.floor(width/4);

    // This method should have an if{} block for each component.

    if (leftView) {
        leftView.setSize(leftWidth-2,height);
        var leftDiv = leftView.getEnclosingDiv();
        leftDiv.style.top = '0px';
    }
    if (mainView) {
        mainView.setSize(width - leftWidth - 2, height);
        var mainDiv = mainView.getEnclosingDiv();
        mainDiv.style.top = '0px';
        mainDiv.style.left = leftWidth + 'px';
    }
}

Implementing the onPageShow() Callback

You can specify the optional onPageShow callback attribute in the page manager element of your pageContents XData block, as demonstrated in the following example:

  <mojo:chui-3.5.2-PageManager onPageShow="zenPage.onPageShow(layoutkey,documentkey);">

This attribute defines the callback method to be invoked after rendering the layout objects for the plugin. For example, you could implement a method that adjusts the display for a layout object provided by a different plugin. Each page manager plugin contains appropriate code to invoke the callback if it has been defined.

Currently, the callback is only required when using the Google Maps plugin, which needs a way to resize the map after rendering the other page items. The following example implements a callback method that triggers a Google Maps resize event:

Example: Implementing onPageShow() for Google Maps

Specify the onPageShow callback attribute of the page manager element. This example uses the jQuery Mobile page manager:

  <mojo:jQM-1.4.5-PageManager onPageShow="zenPage.onPageShow(layoutkey,documentkey);">

In your page class, implement a method similar to the following:

  ClientMethod onPageShow(layoutkey, documentkey) [ Language = javascript ]
  {
    if (layoutkey == 'maps-demo') {
      zen('mainView').getPluginByLayoutObjectType('$map').resizeMap();
    }
}

This example assumes that the application defines the 'maps-demo' layout key, and that the documentView id attribute is 'mainView'. See “Custom Google Maps Helper Plugin Methods” for information on the resizeMap() method.

Using Plugin Resources in a Template Class

Both helper plugins and layout objects sometimes contain methods that provide object-specific utilities, as described in the following sections:

Helper Plugin Methods

Some plugin classes provide special methods that directly invoke utilities defined in the supporting JavaScript library. To use them, get an instance of the plugin object (via documentView methods such as getPluginByLayoutObjectType() or getPluginByName()), and then call the plugin method. The following example gets a Google Maps plugin object and calls its resizeMap() method. The plugin method then uses the current map instance to directly access the Google Maps API and trigger a resize event:

  zen('mainView').getPluginByLayoutObjectType('$map').resizeMap();

For each plugin, information on available plugin methods is listed in the relevant chapter under the heading “<Plugin-name> Helper Plugin Methods”. Some chapters also include a more detailed “Custom <Plugin-name> Helper Plugin Methods” section (for example, the resizemap() function used in this example is described under “Custom Google Maps Helper Plugin Methods” in the Google Maps chapter).

Layout Object Methods

Individual layout objects may also contain special methods. For example, many layout objects have a $refresh method. The following call would refresh the display of the layout object identified by key 'person1':

  zen('mainView').getItemByKey('person1').$refresh();

For each plugin, details on available layout object methods are listed in the relevant chapter under the heading “Custom <Plugin-name> Layout Object Methods”.

FeedbackOpens in a new tab