Part XII - UI Widgets in OpenText Content Server (incl. WebReports)

In my previous blog post I introduced a cascading stylesheet that covers two common page layouts in OpenText Content Server. In this next post I continue the discussion and introduce some of the widgets included with RHCore for adding interactive page components (or "widgets") to a page.

Let's consider a few examples of widgets in Content Server:

  • a function menu on a node;
  • a breadcrumb trail to display the location of a node;
  • the tabs in tabbed content;
  • a date picker to select a date;
  • a user picker to find and select a user; and
  • a pagination widget to navigate through pages of content.

Some of these components are available in Content Server, but are often difficult to apply outside the context of where they're normally used. Sometimes it's not possible at all.

RHCore provides some common interface widgets, which can be added to a page with just a few lines of code. Let's jump in.

# RHCore Widgets

RHCore provides a collection of widgets that can be added to a page whenever you need them. Widgets are designed to work with few preconditions, which makes them easy to use without having to write code in various locations. In fact, the only precondition to a widget is the initial data and two lines in the header of the template (have a look at Part III if you're not familiar with RHTemplate; these widgets also work with WebLingo and WebReports):

{% include "rhcore/macros.html" %}
{% usemacro load_base true %}

The first line loads the macro library included with RHCore. Macros are a powerful feature of RHTemplate, which are like functions that can be defined and called (with parameters) to insert snippets of HTML. The second line calls the load_base macro, which adds the JavaScript libraries and stylesheets into the page that are required for the widgets to function. Once these are loaded you can call and render a widget without having to write any extra JavaScript, CSS, or OScript.

Widgets come in different flavours. The most common are form field widgets, which are rendered in RHTemplate using the formfield filter with the following syntax:

{{ initialValue|formfield:"<fieldType>":"<fieldName>" }}

With WebReports this can be done with the RHFILTER sub-tag (which is a small enhancement to WebReports to enable RHTemplate filters and other features in WebReports):

[LL_REPTAG_"initialValue" RHFILTER:"formfield":"<fieldType>":"<fieldName>" /]

Let's look at a few examples.

# Date Picker Widget

A date picker widget makes it easy to select a date with a popup calendar. This can be generated with RHTemplate as follows:

{{ "2015-01-01"|formfield:"date":"startDate" }}

Or, with WebReports:

[LL_REPTAG_"2015-01-01" RHFILTER:"formfield":"date":"startDate" /]

This creates a date picker form field that looks like this:

Again, this works without having to write any extra JavaScript or CSS. Behind the scenes the widget:

  • parses of the initial value (e.g., 2015-01-01) into a date (other formats are supported);
  • adds a "Clear" button to clear out the value;
  • displays the chosen date in the format defined in the system configuration; and
  • synchronizes the selected date to a hidden form field named startDate, which can be consumed by Content Server in a POST request (e.g., D/2015/1/1:0:0:0).

Not bad for three lines of code.

Say you later realize you need a date and time picker instead. This can be accommodated by simply changing the field type to datetime:

{{ "2015-01-01"|formfield:"datetime":"startDate" }}

The result:

The simplicity and reusability of this widget has saved me countless hours of time. I find it much more forward thinking than copying and pasting the date picker code each time I need it. And yes, it works with IE.

# User Picker Widget

The standard Content Server user picker is a form field with a user icon. Clicking the icon presents a search page where search criteria can be input to find a user. Once the user is found a select link can be clicked to update the field with the selected user:

This style of "classic" user picker can be rendered with RHCore (say, with "Admin" being the initial value):

{{ "Admin"|formfield:"userclassic":"selectedUser" }}

An alternative widget, which requires fewer mouse clicks, is also available:

{{ "Admin"|formfield:"user":"selectedUser" }}

This renders an "autocomplete" field, where typing part of the user's log-in name, first name, last name, or e-mail address displays a list of matched suggestions from which the user can be selected:

The widget automatically:

  • manages the AJAX request that applies the criteria;
  • synchronizes the ID of the chosen user to a hidden field (named selectedUser); and
  • formats the display names according to the format configured in the admin pages.

A similar widget also exists for groups. Again, not bad for three lines of code.

# Multi Ordered User Picker

I've had requirements where multiple users needed to be selected with a user-defined order. A standard development pattern in Content Server is to have plus and minus buttons that submits the existing values to a request handler, adds or removes the row, stores the state in a cache, and reloads the page. I find this overly complex, and so I created a widget that does it all on the client.

The widget is no more difficult to render than any other form widget (using a JSON array for the initial values; an OScript list is also valid):

{{ ["Admin","jdole"]|formfield:"multiuser":"selectedUsers" }}

This renders as follows, which shows the selected users in blue bubbles (which can be removed by clicking the "x"):

Additional users can be found and selected by typing a criteria in the "Search for user..." input field:

Users can also be ordered with drag and drop:

As before, the widget automatically:

  • manages the AJAX request that applies the criteria; and
  • synchronizes the selected users to a hidden field as a sorted JSON array (e.g., [3433,1000]), which can be submitted and decoded on the server (using Web.FromJSON() or something similar).

Again, not bad for three lines of code.

# Tabs

Tabs are commonly used in applications to group related views. For example, a Content Server document has tabs named General, Audit, Categories, Versions, etc. that all relate to the document. Tabs allow a user to visualize what's available and navigate among the different views.

Tabbed views are simple to create with RHCore. This is easiest to show with an example:

{% tabs %}
    {% tab "Tab 1" %}
        This is the content of tab 1.
    {% endtab %}

    {% tab "Tab 2" %}
        This is the content of tab 2.
    {% endtab %}

    {% tab "Tab 3" %}
        This is the content of tab 3.
    {% endtab %}
{% endtabs %}

This renders as follows:

Only the contents of the active tab is rendered and displayed. The framework manages the URL for each tab, which is just the current URL with a different &tab parameter. For example, clicking on "Tab 2" reloads the page but with &tab=2 in the URL.

A parameter can be passed into the {% tabs %} tag to change the URL parameter name. The individual {% tab %} tags also accept a parameter to control whether a tab should be displayed. For example, say you have a tab that should only display if the current user has system administrator rights:

{% tab "Admin Tab" user.isAdmin %}
    Content that only administrators should see.
{% endtab %}

I'm using this widget in numerous projects with much success, and it has greatly simplified what would otherwise be complicated to implement.

# Wrapping Up

The widgets in this post are only a few examples of what is possible. Other widgets include:

  • standard form fields (input, textarea, checkbox, password, select, etc.);
  • node picker;
  • category/attribute picker;
  • generic multi ordered select;
  • sort headers (see Part III for a discussion on sort headers);
  • function menus;
  • breadcrumb trails;
  • user info link (that pops up the user information); and
  • pagination (see Part V for a discussion on pagination).

I'm always adding new widgets whenever a general use-case presents itself.

The widgets have saved me countless hours of development time and have allowed me to focus on the overall solution without getting bogged down in the intricate details of a small component. I couldn't imagine working without them.

Questions or comments about this blog post or anything else? Might RHCore be something you'd want to use in your projects? Send me an e-mail or leave a comment below.