...
features have been made available to make it easier to control the layouts and widgets rendering. |
| Column |
|---|
| Panel |
|---|
| bgColor | #FFFFFF |
|---|
| title | In this section |
|---|
| |
|
|
Custom layout template
A layout can define an xhtml XHTML template to be used in a given mode. Let's take a look at the default template structure.
| Code Block |
|---|
|
<f:subview
xmlns:c="http://java.sun.com/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:nxl="http://nuxeo.org/nxforms/layout"
xmlns:nxu="http://nuxeo.org/nxweb/util"
id="#{layout.id}"
styleClass="#{layoutProperty_styleClass}">
<c:set var="isEditMode" value="#{nxl:isBoundToEditMode(layout.mode)}" />
<table class="dataInput">
<tbody>
<nxl:layoutRow>
<tr class="#{layoutRow.properties['styleClass']}">
<nxl:layoutRowWidget>
<nxu:set var="fieldColspan"
value="#{nxu:test(layoutRow.size==1, 3*layout.columns-2, 1) + nxu:test(widget.handlingLabels, 1, 0)}">
<c:if test="#{not widget.handlingLabels}">
<td class="labelColumn">
<ui:include src="/widgets/incl/widget_label_template.xhtml" />
</td>
</c:if>
<td class="fieldColumn" colspan="#{fieldColspan}">
<nxl:widget widget="#{widget}" value="#{value}" />
</td>
</nxu:set>
</nxl:layoutRowWidget>
</tr>
</nxl:layoutRow>
</tbody>
</table>
<script>
jQuery(document).ready(function() {
jQuery(".widgetHelpLabel").tooltip({relative: true, position: 'bottom center'});
});
</script>
</f:subview>
|
...
This layout intends to render columns within a table: each line will be filled thanks to a layout configuration. It is only used in view mode. Let's take a look at the default listing template structure.
| Code Block |
|---|
|
<f:subview
xmlns:c="http://java.sun.com/jstl/core"
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"
xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
id="#{layout.id}">
<c:if test="false">
Layout template applying to an item instance of PageSelections<DocumentModel> named "documents"
Other needed parameters are:
- provider: instance of a PageProvider<DocumentModel> to handle sort
- layoutListingStatus: iteration status, used to print table header
matching widget label.
</c:if>
<nxu:set var="hasSeveralSorts"
value="#{provider.getSortInfos().size() > 1}"
cache="true">
<c:if test="#{showListingHeader and layout.properties.showListingHeader}">
<thead>
<tr>
<nxl:layoutColumn>
<th>
<c:choose>
<c:when test="#{layoutColumn.properties.isListingSelectionBox}">
<h:selectBooleanCheckbox id="#{layoutColumn.widgets[0].name}_header"
title="#{messages['tooltip.content.select.all']}"
value="#{documents.selected}">
<a4j:support event="onclick"
action="#{documentListingActions.processSelectPage(contentView.name, contentView.selectionListName, documents.selected)}"
onclick="javascript:handleAllCheckBoxes('#{contentView.name}', this.checked)"
reRender="ajax_selection_buttons" />
</h:selectBooleanCheckbox>
</c:when>
<c:when test="#{layoutColumn.properties.isListingSelectionBoxWithCurrentDocument}">
<h:selectBooleanCheckbox id="#{layoutColumn.widgets[0].name}_header"
title="#{messages['tooltip.content.select.all']}"
value="#{documents.selected}">
<a4j:support event="onclick"
onclick="javascript:handleAllCheckBoxes('#{contentView.name}', this.checked)"
action="#{documentListingActions.checkCurrentDocAndProcessSelectPage(contentView.name, contentView.selectionListName, documents.selected, currentDocument.ref)}"
reRender="ajax_selection_buttons" />
</h:selectBooleanCheckbox>
</c:when>
<c:when test="#{layoutColumn.properties.useFirstWidgetLabelAsColumnHeader}">
<c:choose>
<c:when test="#{provider.sortable and !empty layoutColumn.properties.sortPropertyName}">
<nxu:set var="ascIndex"
value="#{provider.getSortInfoIndex(layoutColumn.properties.sortPropertyName, true)}"
cache="true">
<nxu:set var="descIndex"
value="#{provider.getSortInfoIndex(layoutColumn.properties.sortPropertyName, false)}"
cache="true">
<h:commandLink immediate="true"
action="#{provider.setSortInfo(layoutColumn.properties.sortPropertyName, nxu:test(ascIndex != -1, false, true), true)}"
id="#{layoutColumn.widgets[0].name}_header_sort">
<h:outputText value="#{layoutColumn.widgets[0].label}"
rendered="#{!layoutColumn.widgets[0].translated}" />
<h:outputText value="#{messages[layoutColumn.widgets[0].label]}"
rendered="#{layoutColumn.widgets[0].translated}" />
</h:commandLink>
<f:verbatim>&nbsp;</f:verbatim>
<c:if test="#{ascIndex != -1}">
<h:commandLink immediate="true"
action="#{provider.setSortInfo(layoutColumn.properties.sortPropertyName, false, false)}"
id="#{layoutColumn.widgets[0].name}_header_sort_desc">
<h:graphicImage value="/icons/sort_selected_down.png" />
<c:if test="#{hasSeveralSorts}">
#{ascIndex + 1}
</c:if>
</h:commandLink>
</c:if>
<c:if test="#{descIndex != -1}">
<h:commandLink immediate="true"
action="#{provider.setSortInfo(layoutColumn.properties.sortPropertyName, true, false)}"
id="#{layoutColumn.widgets[0].name}_header_sort_asc">
<h:graphicImage value="/icons/sort_selected_up.png" />
<c:if test="#{hasSeveralSorts}">
#{descIndex + 1}
</c:if>
</h:commandLink>
</c:if>
<c:if test="#{ascIndex == -1 and descIndex == -1}">
<h:commandLink immediate="true"
action="#{provider.addSortInfo(layoutColumn.properties.sortPropertyName, true)}"
id="#{layoutColumn.widgets[0].name}_header_sort_add">
<h:graphicImage value="/icons/sort_down.png" />
</h:commandLink>
</c:if>
</nxu:set>
</nxu:set>
</c:when>
<c:otherwise>
<h:outputText value="#{layoutColumn.widgets[0].label}"
rendered="#{!layoutColumn.widgets[0].translated}" />
<h:outputText value="#{messages[layoutColumn.widgets[0].label]}"
rendered="#{layoutColumn.widgets[0].translated}" />
</c:otherwise>
</c:choose>
</c:when>
</c:choose>
</th>
</nxl:layoutColumn>
<c:if test="#{provider.sortable}">
<th>
<h:graphicImage value="/icons/lightbulb.png"
onmouseover="tooltip.show('#{messages['contentview.sort.help']}', 200, 'topleft');"
onmouseout="tooltip.hide();" />
</th>
</c:if>
</tr>
</thead>
</c:if>
</nxu:set>
<c:set var="trStyleClass" value="#{nxu:test(layoutListingStatus.index%2 ==0, 'dataRowEven', 'dataRowOdd')}" />
<tr class="#{nxu:test(layout.properties.showRowEvenOddClass, trStyleClass, '')}">
<nxl:layoutColumn>
<td class="#{layoutColumn.properties.columnStyleClass}">
<nxl:layoutColumnWidget>
<nxl:widget widget="#{widget}" value="#{value}" />
<c:if test="#{layoutColumn.size > 1 and layoutColumn.size > widgetIndex + 1 and widgetIndex > 0}">
<br />
</c:if>
</nxl:layoutColumnWidget>
</td>
</nxl:layoutColumn>
<c:if test="#{provider.sortable}">
<td class="iconColumn">
</td>
</c:if>
</tr>
</f:subview>
|
...
Since version 5.6, it uses a "grid" rendering allowing fine-grained control over the place used by widgets. It combines the following layout template with the use of the standard "container" widget type. The container widgets pile up any number of widgets displaying information about the document metadata, its state, relations, publications, etc...
| Code Block |
|---|
|
<f:subview
xmlns:c="http://java.sun.com/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:nxl="http://nuxeo.org/nxforms/layout"
id="#{layout.id}">
<c:if test="false">
Handles grid layouts, using style classes defined by row properties.
</c:if>
<div class="gridContainer">
<nxl:layoutRow>
<div class="gridRow">
<nxl:layoutRowWidget>
<c:set var="gridStyleClassProp" value="nxl_gridStyleClass_#{widgetIndex}" />
<div class="gridBox #{layoutRow.properties[gridStyleClassProp]}">
<nxl:widget widget="#{widget}" value="#{value}" />
</div>
</nxl:layoutRowWidget>
</div>
</nxl:layoutRow>
</div>
</f:subview>
|
When using this layout template, the layout definition will use properties defined on rows to allow more or less place to the widgets. Here is the default summary definition:
| Code Block |
|---|
|
<layout name="grid_summary_layout">
<templates>
<template mode="any">
/layouts/layout_grid_template.xhtml
</template>
</templates>
<rows>
<row>
<properties mode="any">
<property name="nxl_gridStyleClass_0">gridStyle7</property>
<property name="nxl_gridStyleClass_1">gridStyle5</property>
</properties>
<widget>summary_left_panel</widget>
<widget>summary_right_panel</widget>
</row>
</rows>
</layout>
|
...
Let's have a look at a sample template used to present contributors to a document.
| Code Block |
|---|
|
<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:nxu="http://nuxeo.org/nxweb/util"
xmlns:nxdir="http://nuxeo.org/nxdirectory"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:nxp="http://nuxeo.org/nxweb/pdf"
id="#{widget.id}">
<div>
<c:forEach var="username" items="#{field}" varStatus="status">
<c:if test="#{!status.first}">#{status.last ? andLabel : ', '}</c:if>
<h:outputText value="#{nxu:userFullName(username)}"
title="#{username}" onmouseover="tooltip.show(username, 500);"
onmouseout="tooltip.hide();"/>
</c:forEach>
</div>
</f:subview>
|
...
Some helper methods make it easier to check the widget mode, here is the complete current definition of the contributors widget type in Nuxeo.
| Code Block |
|---|
|
<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:nxu="http://nuxeo.org/nxweb/util"
xmlns:nxdir="http://nuxeo.org/nxdirectory"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:nxp="http://nuxeo.org/nxweb/pdf"
id="#{widget.id}">
<c:set var="andLabel" value=" #{messages['label.and']} " scope="page" />
<c:if test="#{nxl:isLikePlainMode(widget.mode)}"><nxu:inputList
value="#{field}" model="contributorsModel"><h:outputText
value="#{nxu:userFullName(contributorsModel.rowData)}" /><h:outputText
rendered="#{contributorsModel.rowIndex != contributorsModel.rowCount -1}"
value="#{nxu:test(contributorsModel.rowIndex == contributorsModel.rowCount -2, andLabel, ', ')}" /></nxu:inputList></c:if>
<c:if test="#{widget.mode == 'pdf'}">
<nxp:html>
<c:forEach var="username" items="#{field}" varStatus="status">
<c:if test="#{!status.first}">#{status.last ? andLabel : ', '}</c:if>
<h:outputText value="#{nxu:userFullName(username)}" />
</c:forEach>
</nxp:html>
</c:if>
<c:if test="#{nxl:isLikeViewMode(widget.mode)}">
<div>
<c:forEach var="username" items="#{field}" varStatus="status">
<c:if test="#{!status.first}">#{status.last ? andLabel : ', '}</c:if>
<h:outputText value="#{nxu:userFullName(username)}"
title="#{username}" onmouseover="tooltip.show(username, 500);"
onmouseout="tooltip.hide();"/>
</c:forEach>
</div>
</c:if>
</f:subview>
|
...
Some rules must be followed when writing xhtml XHTML to be included in templates:
...
For instance, to handle a list of String elements, you can use the definition:
| Code Block |
|---|
|
<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.
With nuxeo Nuxeo version <= 5.3.0, 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:
| Code Block |
|---|
|
<widget name="employees" type="list">
<fields>
<field>company:employees</field>
</fields>
<subWidgets>
<widget name="employee" type="template">
<labels>
<label mode="any"></label>
</labels>
<fields>
<field></field>
</fields>
<properties mode="any">
<property name="template">
/widgets/complex_widget_template.xhtml
</property>
</properties>
<!-- subwidgets for complex -->
<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>
</subWidgets>
</widget>
|
With nuxeo Nuxeo version > 5.3.0, 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:
| Code Block |
|---|
|
<widget name="employees" type="list">
<fields>
<field>company:employees</field>
</fields>
<subWidgets>
<widget name="employee" type="template">
<labels>
<label mode="any"></label>
</labels>
<properties mode="any">
<property name="template">
/widgets/complex_list_item_widget_template.xhtml
</property>
</properties>
<!-- subwidgets for complex -->
<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>
</subWidgets>
</widget>
|
...
To handle a complex property (the value is a map with keys 'name' and 'email' for instance, you can use the definition:
| Code Block |
|---|
|
<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>
|
...
A builtin template has been added to handle sublists: the original "list" widget is equivalent to a widget of type "template" using the file /widgets/list_widget_template.xhtml. To handle the sublist, this template needs to be changed. The file list_subwidget_template.xhtml is available for it since nuxeo Nuxeo version 5.2 GA.
To handle a sublist property, you can use take example on this definition:
| Code Block |
|---|
|
<widget name="employees" type="list">
<fields>
<field>company:employees</field>
</fields>
<subWidgets>
<widget name="employee" type="template">
<labels>
<label mode="any"></label>
</labels>
<properties mode="any">
<property name="template">
/widgets/complex_list_item_widget_template.xhtml
</property>
</properties>
<!-- subwidgets for complex -->
<subWidgets>
<widget name="phoneNumbers" type="template">
<fields>
<field>phoneNumbers</field>
</fields>
<properties mode="any">
<property name="template">
/widgets/list_subwidget_template.xhtml
</property>
</properties>
<subWidgets>
<widget name="phoneNumber" type="text">
<label mode="any"></label>
<fields>
<field></field>
</fields>
</widget>
</subWidgets>
</widget>
</subWidgets>
</widget>
</subWidgets>
</widget>
|
| Content by Label |
|---|
| spaces | @self |
|---|
| title | Related topics |
|---|
| showLabels | false |
|---|
| labels | summary-layout |
|---|
| showSpace | false |
|---|
| type | page |
|---|
|