Layouts

Table of Contents

7.1. Introduction
7.1.1. Layouts
7.1.2. Widgets
7.1.3. Widget types
7.1.4. Modes
7.2. Manage layouts
7.2.1. Layout registration
7.2.2. Layout definition
7.2.3. Widget definition
7.2.4. EL expressions in layouts and widgets
7.3. Document layouts
7.4. Layout display
7.5. Standard widget types
7.5.1. text
7.5.2. int
7.5.3. secret
7.5.4. textarea
7.5.5. datetime
7.5.6. template
7.5.7. file
7.5.8. htmltext
7.5.9. selectOneDirectory
7.5.10. selectManyDirectory
7.5.11. list
7.5.12. checkbox
7.6. Custom templates
7.6.1. Custom layout template
7.6.2. Custom widget template
7.6.3. Builtin templates to handle complex properties
7.7. Custom widget types
7.8. Generic layout usage

Let our artists go wild on imaginative page layouts.

-- Grant Morrison

7.1. Introduction

Layouts are used to generate pages rendering from an xml configuration.

In a document oriented perspective, layouts are mostly used to display a document metadata in different use cases: present a form to set its schemas fields when creating or editing the document, and present these fields values when simply displaying the document. A single layout definition can be used to address these use cases as it will be rendered for a given document and in a given mode.

In this chapter we will see how to define a layout, link it to a document type, and use it in XHTML pages.

7.1.1. Layouts

A layout is a group of widgets that specifies how widgets are assembled and displayed. It manages widget rows and has global control on the rendering of each of its widgets.

7.1.2. Widgets

It's all the same machine, right? The Pentagon, multinational corporations, the police! You do one little job, you build a widget in Saskatoon and the next thing you know it's two miles under the desert, the essential component of a death machine!

-- Holloway, Cube

A widget defines how one or several fields from a schema will be presented on a page. It can be displayed in several modes and holds additional information like for instance the field label. When it takes user entries, it can perform conversion and validation like usual JSF components.

7.1.3. Widget types

A widget definition includes the mention of its type. Widget types make the association between a widget definition and the jsf component tree that will be used to render it in a given mode.

7.1.4. Modes

The layout modes can be anything although some default modes are included in the application: create, edit, view and search.

The widget modes are more restricted and widget types will usually only handle two modes: edit and view. The widget mode is computed from the layout mode following this rule: if the layout is in mode create, edit or search, the widget will be in edit mode. Otherwise the widget will be in view mode.

It is possible to override this behaviour in the widget definition, and state that, for instance, whatever the layout mode, the widget will be in view mode so that it only displays read-only values. The pseudo-mode "hidden" can also be used in a widget definition to exclude this widget from the layout in a given mode.

The pseudo mode "any" is only used in layouts and widgets definitions to set up default values.

7.2. Manage layouts

Custom layouts can be contributed to the web layout service, using its extension point. The layout definition is then available through the service to control how it will be displayed in a given mode.

Some jsf tags have been added to the Nuxeo ECM layout tag library to make then easily available from an xhtml page.

7.2.1. Layout registration

Layouts are registered using a regular extension point on the Nuxeo ECM layout service. Here is a sample contribution.

<?xml version="1.0"?>

<component name="org.nuxeo.ecm.platform.forms.layouts.webapp">

  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="layouts">

    <layout name="heading">
      <templates>
        <template mode="any">/layouts/layout_default_template.xhtml</template>
      </templates>
      <rows>
        <row>
          <widget>title</widget>
        </row>
        <row>
          <widget>description</widget>
        </row>
      </rows>
      <widget name="title" type="text">
        <labels>
          <label mode="any">label.dublincore.title</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field>dc:title</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
      <widget name="description" type="textarea">
        <labels>
          <label mode="any">label.dublincore.description</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field>dc:description</field>
        </fields>
      </widget>
    </layout>

  </extension>

</component>

      

Example 7.1. Sample layout contribution to the layout service.


7.2.2. Layout definition

The above layout definition is used to display the title and the description of a document. Here are its properties:

  • name: string used as an identifier. In the example, the layout name is "heading".

  • templates: list of templates to use for this layout global rendering. In the example, the layout template in any mode is the xhtml file at "/layouts/layout_default_template.xhtml". Please refer to section about custom layout templates for more information.

  • rows: definition about what widgets will have to be displayed on this row. Each row can hold several widgets, and an empty widget tag can be used to control the alignment. The widget has to match a widget name given in this layout definition. In the example, two rows have been defined, the first one will hold the "title" widget, and the second one will hold the "description" widget.

  • widget: a layout definition can hold any number of widget definitions. If the widget is not referenced in the rows definition, it will be ignored. Please refer the widget definition section.

7.2.3. Widget definition

Two widget definitions are presented on the above example. Let's look into the "title" widget and present its properties:

  • name: string used as an identifier in the layout context. In the example, the widget name is "title".

  • type: the widget type that will manage the rendering of this widget. In this example, the widget type is "text". This widget type is a standard widget types, more information about widget types is available here.

  • labels: list of labels to use for this widget in a given mode. If no label is defined in a specific mode, the label defined in the "any" mode will be taken as default. In the example, a single label is defined for any mode to the "label.dublicore.title" message. If no label is defined at all, a default label will be used following the convention: "label.widget.[layoutName].[widgetName]".

  • translated: string representing a boolean value ("true" or "false") and defaulting to "false". When set as translated, the widget labels will be treated as messages and displayed translated. In the example, the "label.dublincore.title" message will be translated at rendering time. Default is true.

  • fields: list of fields that will be managed by this widget. In the example, we handle the field "dc:title" where "dc" is the prefix for the "dublincore" schema. If the schema you would like to use does not have a prefix, use the schema name instead. Note that most of standard widget types only handle one field. Side note: when dealing with an attribute from the document that is not a metadata, you can use the property name as it will be resolved like a value expression of the form #{document.attribute}.

  • properties: list of properties that will apply to the widget in a given mode. Properties listed in the "any" mode will be merged with properties for the specific mode. Depending on the widget type, these properties can be used to control what jsf component will be used and/or what attributes will be set on these components. In standard widget types, only one component is used given the mode, and properties will be set as attributes on the component. For instance, when using the "text" widget type, every property accepted by the "<h:inputText />" tag can be set as properties on "edit" and "create" modes, and every property accepted by the "<h:outputText />" tag can be set as properties. Properties can also be added in a given widget mode.

Additional properties can be set on a widget:

  • helpLabels: list that follows the same pattern as labels, but used to set help labels.

  • widgetModes: list of local modes used to override the local mode (from the layout).

  • subWidgets: list of widget definitions, as the widget list, used to describe sub widgets use to help the configuration of some complex widget types.

Here is a more complex layout contribution that shows the syntax to use for these additional properties:

<?xml version="1.0"?>

<component name="org.nuxeo.ecm.platform.forms.layouts.webapp">

  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="layouts">

    <layout name="complex">
      <templates>
        <template mode="any">/layouts/layout_default_template.xhtml</template>
      </templates>
      <rows>
        <row>
          <widget>identifier</widget>
        </row>
      </rows>
      <widget name="identifier" type="text">
        <labels>
          <label mode="any">label.dublincore.title</label>
        </labels>
        <translated>true</translated>
        <fields>
          <field>uid:uid</field>
        </fields>
        <widgetModes>
          <!-- not shown in create mode -->
          <mode value="create">hidden</mode>
        </widgetModes>
        <properties widgetMode="edit">
          <!-- required in widget mode edit -->
          <property name="required">true</property>
        </properties>
        <properties mode="view">
          <!-- property applying in view mode -->
          <property name="styleClass">cssClass</property>
        </properties>
      </widget>
    </layout>

  </extension>

</component>

      

Example 7.2. Sample complex layout contribution to the layout service.


7.2.4. EL expressions in layouts and widgets

TODO: explain what variables are available in the context

7.3. Document layouts

Layouts can be linked to a document type definition by specifying the layout names:

<layouts mode="any">
  <layout>heading</layout>
  <layout>note</layout>
</layouts>

Layouts are defined in a given mode; layouts in the "any" mode will be merged with layouts defined for specific modes.

7.4. Layout display

Layouts can be displayed thanks to a series a JSF tags that will query the web layout service to get the layout definition and build it for a given mode.

For instance, we can use the documentLayout tag to display the layouts of a document:

<div xmlns="http://www.w3.org/1999/xhtml"
    xmlns:nxl="http://nuxeo.org/nxforms/layout">
  <nxl:documentLayout mode="view" value="#{currentDocument}" />
</div>

We can also display a specific layout for a document, even if it is not specified in the document type definition:

<div xmlns="http://www.w3.org/1999/xhtml"
    xmlns:nxl="http://nuxeo.org/nxforms/layout">
  <nxl:layout name="heading" mode="view" value="#{currentDocument}" />
</div>

Please refer to the tag library documentation available at http://doc.nuxeo.org/5.1/tlddoc/.

7.5. Standard widget types

A series of widget types has been defined for the most generic uses cases.

Please refer to the tag library documentation available at http://doc.nuxeo.org/5.1/tlddoc/ for nuxeo jsf tags.

7.5.1. text

The text widget displays an input text in create or edit mode, with additional message tag for errors, and a regular text output in any other mode. Widgets using this type can provide properties accepted on a <h:inputText /> tag in create or edit mode, and properties accepted on a <h:outputText /> tag in other modes.

7.5.2. int

The int widget displays an input text in create or edit mode, with additional message tag for errors, and a regular text output in any other mode. It uses a number converter. Widgets using this type can provide properties accepted on a <h:inputText /> tag in create or edit mode, and properties accepted on a <h:outputText /> tag in other modes.

7.5.3. secret

The secret widget displays an input secret text in create or edit mode, with additional message tag for errors, and nothing in any other mode. Widgets using this type can provide properties accepted on a <h:inputSecret /> tag in create or edit mode.

7.5.4. textarea

The textarea widget displays a textarea in create or edit mode, with additional message tag for errors, and a regular text output in any other mode. Widgets using this type can provide properties accepted on a <h:inputTextarea /> tag in create or edit mode, and properties accepted on a <h:outputText /> tag in other modes.

7.5.5. datetime

The datetime widget displays a javascript calendar in create or edit mode, with additional message tag for errors, and a regular text output in any other mode. It uses a date time converter. Widgets using this type can provide properties accepted on a <nxu:inputDatetime /> tag in create or edit mode, and properties accepted on a <h:outputText /> tag in other modes. The converter will also be given these properties.

7.5.6. template

The template widget displays a template content whatever the mode. Widgets using this type must provide the path to this template; this template can check the mode to adapt the rendering.

Information about how to write a template is given in the custom widget template section.

7.5.7. file

The file widget displays a file uploader/editor in create or edit mode, with additional message tag for errors, and a link to the file in other modes. Widgets using this type can provide properties accepted on a <nxu:inputFile /> tag in create or edit mode, and properties accepted on a <nxu:outputFile /> tag in other modes.

7.5.8. htmltext

The htmltext widget displays an html text editor in create or edit mode, with additional message tag for errors, and a regular text output in other modes (without escaping the text). Widgets using this type can provide properties accepted on a <nxu:editor /> tag in create or edit mode, and properties accepted on a <nxu:outputText /> tag in other modes.

7.5.9. selectOneDirectory

The selectOneDirectory widget displays a selection of directory entries in create or edit mode, with additional message tag for errors, and the directory entry label in other modes. Widgets using this type can provide properties accepted on a <nxd:selectOneListbox /> tag in create or edit mode, and properties accepted on a <nxd:directoryEntryOutput /> tag in other modes.

7.5.10. selectManyDirectory

The selectManyDirectory widget displays a multi selection of directory entries in create or edit mode, with additional message tag for errors, and the directory entries labels in other modes. Widgets using this type can provide properties accepted on a <nxd:selectManyListbox /> tag in create or edit mode, and properties accepted on a <nxd:directoryEntryOutput /> tag in other modes.

7.5.11. list

The list widget displays an editable list of items in create or edit mode, with additional message tag for errors, and the same list of items in other modes. Items are defined using sub wigdets configuration. This actually a template widget type whose template uses a <nxu:inputList /> tag in edit or create mode, and a table iterating over items in other modes.

7.5.12. checkbox

The checkbox widget displays a checkbox in create, edit and any other mode, with additional message tag for errors. Widgets using this type can provide properties accepted on a <h:selectBooleanCheckbox /> tag in create, edit mode, and other modes.

7.6. Custom templates

Some templating feature have been made available to make it easier to control the layouts and widgets rendering.

7.6.1. Custom layout template

A layout can define an xhtml template to be used in a given mode. Let's take a look at the default template structure.

<f:subview
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:nxl="http://nuxeo.org/nxforms/layout"
  xmlns:nxu="http://nuxeo.org/nxweb/util"
  xmlns:nxd="http://nuxeo.org/nxweb/document">

  <f:subview rendered="#{layout.mode != 'edit' and layout.mode != 'create'}">

    <table class="dataInput">
      <tbody>

        <nxl:layoutRow>
          <tr>
            <nxl:layoutRowWidget>
              <td class="labelColumn">
                <h:outputText value="#{widget.label}" rendered="#{!widget.translated}" />
                <h:outputText value="#{messages[widget.label]}" rendered="#{widget.translated}" />
              </td>
              <td class="fieldColumn">
                <nxl:widget widget="#{widget}" mode="#{widget.mode}" value="#{value}" />
              </td>
            </nxl:layoutRowWidget>
          </tr>
        </nxl:layoutRow>

      </tbody>
    </table>

  </f:subview>

  <f:subview rendered="#{layout.mode == 'edit' or layout.mode == 'create'}">

    <table class="dataInput">
      <tbody>

        <nxl:layoutRow>
          <tr>
            <nxl:layoutRowWidget>
              <td class="labelColumn">
                <h:outputText value="#{widget.label}" rendered="#{!widget.translated}"
                  styleClass="#{nxu:test(widget.required, 'required', '')}" />
                <h:outputText value="#{messages[widget.label]}" rendered="#{widget.translated}"
                  styleClass="#{nxu:test(widget.required, 'required', '')}" />
              </td>
              <td class="fieldColumn">
                <nxl:widget widget="#{widget}" mode="#{widget.mode}" value="#{value}" />
              </td>
            </nxl:layoutRowWidget>
          </tr>
        </nxl:layoutRow>

      </tbody>
    </table>

  </f:subview>

</f:subview>

      

Example 7.3. Default layout template


This template is intended to be unused in any mode, so the layout mode is checked to provide a different rendering in "edit" or "create" modes and other modes.

When this template is included in the page, several variables are made available:

  • layout: the computed layout value ; its mode and number of columns can be checked on it.

  • value or document: the document model (or whatever item used as value).

The layout system integration using facelets features requires that iterations are performed on the layout rows and widgets. The <nxl:layoutRow> and <nxl:layoutRowWidget /> trigger these iterations. Inside the layoutRow tag, two more variables are made available: layoutRow and layoutRowIndex. Inside the layoutRowWidget, two more variables are made available: widget and widgetIndex.

These variables can be used to control the layout rendering. For instance, the default template is the one applying the "required" style on widget labels, and translating these labels if the widget must be translated. It also makes sure widgets on the same rows are presented in the same table row.

7.6.2. Custom widget template

The template widget type makes it possible to set a template to use as an include.

Let's have a look at a sample template used to present contributors to a document.

<f:subview xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
  xmlns:t="http://myfaces.apache.org/tomahawk"
  xmlns:nxdir="http://nuxeo.org/nxdirectory">

  <t:dataList id="#{widget.id}" var="listItem" value="#{field_0}"
    layout="simple" styleClass="standardList">
    <h:graphicImage value="/icons/html.png" />
    <h:commandLink value="#{listItem}" immediate="true"
      action="#{userManagerActions.viewUser}">
      <f:param name="usernameParam" value="#{listItem}" />
    </h:commandLink>
    <br />
  </t:dataList>

</f:subview>
      

Example 7.4. Sample template for a widget


This widget presents the contributors of a document with specific links on each on these user identifier information.

Having a widget type just to perform this kind of rendering would be overkill, so using a widget with type "template" can be useful here.

When this template is included in the page, the widget variable is made available:

Some rules must be followed when writing xhtml to be included in templates:

  • Use the widget id as identifier: the widget id is computed to be unique within the page, so it should be used instead of fixed id attributes so that another widget using the same template will not introduce duplicated ids in the jsf component tree.

  • Use the variable with name following the field_n pattern to reference field values. For instance, binding a jsf component value attribute to #{field_0} means binding it to the first field definition.

7.6.3. Builtin templates to handle complex properties

7.6.3.1. List widget template

The standard widget type "list" is actually a widget of type "template" using a static template path: /widgets/list_widget_template.xhtml. If this default behaviour does not suit your needs, you can simply copy this template, make your changes, and use a widget of type "template" with the new template path.

This template assumes that each element of the list will be displayed using subwidgets definitions.

For instance, to handle a list of String elements, you can use the definition:

<widget name="contributors" type="list">
  <fields>
    <field>dc:contributors</field>
  </fields>
  <subWidgets>
    <widget name="contributor" type="text">
      <fields>
        <field></field>
      </fields>
    </widget>
  </subWidgets>
</widget>

The empty field definition in the subwidget is used to specify that each element of the list is itself the element to display.

To handle a list of complex properties (each entry of the list is a map with keys 'name' and 'email' for instance), you can use the definition:

<widget name="employees" type="list">
  <fields>
    <field>company:employees</field>
  </fields>
  <subWidgets>
    <widget name="name" type="text">
      <fields>
        <field>name</field>
      </fields>
    </widget>
    <widget name="email" type="text">
      <fields>
        <field>email</field>
      </fields>
    </widget>
  </subWidgets>
</widget>

7.6.3.2. Complex widget template

A builtin template has been added to handle complex properties. It is available at /widgets/complex_widget_template.xhtml. It assumes that each element of the complex property will be displated using subwidgets definitions.

To handle a complex property (the value is a map with keys 'name' and 'email' for instance, you can use the definition:

<widget name="manager" type="template">
  <fields>
    <field>company:manager</field>
  </fields>
  <properties mode="any">
    <property name="template">
      /widgets/complex_widget_template.xhtml
    </property>
  </properties>
  <subWidgets>
    <widget name="name" type="text">
      <fields>
        <field>name</field>
      </fields>
    </widget>
    <widget name="email" type="text">
      <fields>
        <field>email</field>
      </fields>
    </widget>
  </subWidgets>
</widget>

7.7. Custom widget types

Custom widget types can be added to the standard list thanks to another extension point on the web layout service.

Here is a sample widget type registration:

<?xml version="1.0"?>

<component name="org.nuxeo.ecm.platform.forms.layout.MyContribution">

  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="widgettypes">

    <widgetType name="customtype">
      <handler-class>
        org.myproject.MyCustomWidgetTypeHandler
      </handler-class>
      <property name="foo">bar</property>
    </widgetType>

  </extension>

</component>

      

Example 7.5. Sample widget type contribution to the layout service.


The custom widget type class must follow the org.nuxeo.ecm.platform.forms.layout.facelets.WidgetTypeHandler interface.

Additional properties can be added to the type registration so that the same class can be reused with a different behaviour given the property value.

The widet type handler is used to generate facelet tag handlers dynamically taking into account the mode, and any other properties that can be found on a widget.

The best thing to do before writing a custom widget type handler is to go see how standard widget type handlers are implemented, as some helper methods can be reused to ease implementation of specific behaviours.

7.8. Generic layout usage

Layouts can be used with other kind of objects than documents.

The field definition has to match a document property for which setters and getters will be available, or the "value" property must be passed explicitely for the binding to happen. Depending on the widget, other kinds of bindings can be done.