Web UI Framework

Content Views

Updated: October 16, 2020

Content Views can be configured using Studio, check out the Content Views documentation.

Definition

 

A content view is a notion to define all the elements needed to get a list of items and perform their rendering. The most obvious use case is the listing of a folderish document content, where we would like to be able to perform several actions.

  • Defining the NXQL query that will be used to retrieve the documents, filtering some of them (documents in the trash for instance).
  • Passing on contextual parameters to the query (the current container identifier).
  • Defining a filtering form to refine the query.
  • Defining what columns will be used for the rendering of the list, and how to display their content.
  • Handling selection of documents, and actions available when selecting them (copy, paste, delete...).
  • Handling sorting and pagination.
  • Handling caching, and refresh of this cache when a document is created, deleted, modified, etc.

The Nuxeo Content View framework makes it possible to define such an object, by registering content views to the service. Here is a sample contribution, that will display the children of the current document:

<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">

  <contentView name="document_content">

    <coreQueryPageProvider>
      <property name="coreSession">#{documentManager}</property>
      <pattern>
        SELECT * FROM Document WHERE ecm:parentId = ?
        AND ecm:isVersion = 0
        AND ecm:mixinType != 'HiddenInNavigation'
        AND ecm:currentLifeCycleState != 'deleted'
      </pattern>
      <parameter>#{currentDocument.id}</parameter>
      <sort column="dc:title" ascending="true" />
      <pageSize>20</pageSize>
    </coreQueryPageProvider>

    <cacheKey>#{currentDocument.id}</cacheKey>
    <cacheSize>10</cacheSize>
    <refresh>
      <event>documentChanged</event>
      <event>documentChildrenChanged</event>
    </refresh>

    <resultLayouts>
      <layout name="document_listing_ajax" title="document_listing"
        translateTitle="true" iconPath="/icons/document_listing_icon.png"
        showCSVExport="true" showPDFExport="true" showSyndicationLinks="true" />
      <layout name="document_listing_ajax_compact_2_columns"
        title="document_listing_compact_2_columns"
        translateTitle="true"
        iconPath="/icons/document_listing_compact_2_columns_icon.png" />
      <layout name="document_listing_ajax_icon_2_columns"
        title="document_listing_icon_2_columns"
        translateTitle="true"
        iconPath="/icons/document_listing_icon_2_columns_icon.png" />
    </resultLayouts>

    <selectionList>CURRENT_SELECTION</selectionList>
    <actions category="CURRENT_SELECTION_LIST" />

  </contentView>

</extension>

The Content View Query

coreQueryPageProvider element

The coreQueryPageProvider element makes it possible to define what query will be performed. Here it is a query on a core session, using a pattern with one parameter.

parameter and property elements

The coreQueryPageProvider element accepts any number of property elements, defining needed context variables for the page provider to perform its work. The coreSession property is mandatory for a core query to be processed and is bound to the core session proxy named documentManager available in a default Nuxeo application.

It also accepts any number of parameter elements, where order of definition matters: this EL expression will be resolved when performing the query, replacing the '?' characters it holds.

The main difference between properties and parameters is that properties will not be recomputed when refreshing the provider, whereas parameters will be. Properties will only be recomputed when resetting the provider.

sort elements

The sort element defines the default sort, that can be changed later through the interface. There can be any number of sort elements. The sortInfosBinding element can also be defined: it can resolve an EL expression in case the sort infos are held by a third party instance (document, Seam component...) and will be used instead of the default sort information if not null or empty. The EL expression can either resolve to a list of org.nuxeo.ecm.core.api.SortInfo instances, or a list of map items using keys sortColumn (with a String value) and sortAscending (with a boolean value).

pageSize elements

The pageSize element defines the default page size, it can also be changed later. The pageSizeBinding element can also be defined: it can resolve an EL expression in case the page size is held by a third party instance (document, Seam component...), and will be used instead of the default page size if not null.

The optional maxPageSize element can be placed at the same level than pageSize. It makes it possible to define the maximum page size so that the content view does not overload the server when retrieving a large number of items. When not set, since 5.9.6, the default value "1000" will be used: even when asking for all the results with a page size with value "0" (when exporting the content view in CSV format for instance), only 1000 items will be returned. Since 5.6 (and some previous hotfixed versions, see NXP-9052) this is configurable globally using the runtime property nuxeo.pageprovider.default-max-page-size.

maxResults elements

To set this limit you need to add a maxResults parameter to coreQueryPageProvider, either using an integer value or one of the following keywords:

  • DEFAULT_NAVIGATION_RESULTS: Used by most of the navigation page provider, the default is 200 and it can be overridden using Java options:

      JAVA_OPTS=$JAVA_OPTS -Dorg.nuxeo.ecm.platform.query.nxql.defaultNavigationResults=1000
    
    

    or you can directly add this line in nuxeo.conf:

     org.nuxeo.ecm.platform.query.nxql.defaultNavigationResults=1000
    
    
  • PAGE_SIZE: this is useful when you are interested in a single page or if you don't need a total count.

whereClause element

This kind of core query can also perform a more complex form of query, using a document model to store query parameters. Using a document model makes it easy to:

  • use a layout to display the form that will define query parameters;
  • save this document in the repository, so that the same query can be replayed when viewing this document.

Here is an example of such a registration:

<extension target="org.nuxeo.ecm.platform.ui.web.ContentViewService"
  point="contentViews">

  <contentView name="document_content">

    <coreQueryPageProvider>
      <property name="coreSession">#{documentManager}</property>
      <property name="maxResults">DEFAULT_NAVIGATION_RESULTS</property>
      <whereClause docType="AdvancedSearch">

        <predicate parameter="dc:title" operator="FULLTEXT">
          <field schema="advanced_search" name="title" />
        </predicate>

        <predicate parameter="dc:created" operator="BETWEEN">
          <field schema="advanced_search" name="created_min" />
          <field schema="advanced_search" name="created_max" />
        </predicate>

        <predicate parameter="dc:modified" operator="BETWEEN">
          <field schema="advanced_search" name="modified_min" />
          <field schema="advanced_search" name="modified_max" />
        </predicate>

        <predicate parameter="dc:language" operator="LIKE">
          <field schema="advanced_search" name="language" />
        </predicate>

        <predicate parameter="ecm:currentLifeCycleState" operator="IN">
          <field schema="advanced_search" name="currentLifeCycleStates" />
        </predicate>

        <fixedPart>
          ecm:parentId = ? AND ecm:isVersion = 0 AND ecm:mixinType !=
          'HiddenInNavigation' AND ecm:currentLifeCycleState != 'deleted'
        </fixedPart>

      </whereClause>
      <parameter>#{currentDocument.id}</parameter>
      <sort column="dc:title" ascending="true" />
      <pageSize>20</pageSize>
    </coreQueryPageProvider>

    <searchLayout name="document_content_search"
      filterDisplayType="quick" />
    <showFilterForm>true</showFilterForm>

    ...

</extension>

The above definition holds a whereClause element, stating the search document type and predicates explaining how the document model properties will be translated into a NXQL query. It can also state a fixedPart element that will added as to the query string. This fixed part can also take parameters using the '?' character and parameter elements. It can also accept "named parameters", e.g. parameters prefixed by a comma, that can also match the search document model properties (for instance: SELECT * FROM Document WHERE [dc:title](http://dctitle) = :[searchdoc:title](http://searchdoctitle) ).

The fixedPart element also accepts attributes to better control its behaviour:

  • statement (available since 5.9.2) makes is possible to declare the select statement to use (as contrary to the pattern element, the fixedPart element is not supposed to hold the select statement). This optional parameter default to "Select * from document" for default core page providers.
  • escapeParameters is a boolean value that allows to avoid escaping parameters when building the fixed part (defaults to true).
  • quoteParameters is a boolean value that allows to avoid adding quotes around the parameter (defaults to true). This is useful when parameters actually hold a complete predicate, for instance (and in this case, the escapeParameters element must also be set to true.
 
Note that when using an Elasticsearch page provider you can use NXQL hints inside predicates like this:
 
< predicate hint = "ES: INDEX(<a>dc:title,dc:description</a>)" parameter = "[dc:title](http://dctitle)" operator = "FULLTEXT" >
&nbsp;&nbsp; < field schema = "advanced_search" name = "fulltext_all" />
</ predicate >

Attributes escapeParameters and quoteParameters are also accepted on the pattern element.

It might be useful to add the ContentViewDisplay facet (this facet includes the content_view_display schema, using the cvd prefix) to the definition of the AdvandedSearch document type, when configuring one of the elements described below: pageSizeBinding, sortInfosBinding, resultColumns or resultLayout.

searchDocumentType element

The searchDocumentType element is an alternative way to define the search document type to use on the whereClause element. It's been made available to make it possible to define such a search document model, even if no whereClause is defined. This can be useful when defining aggregates without any other filtering, for instance.

Sample usage:

<contentView name="myContentView">
  <coreQueryPageProvider>
    <property name="coreSession">#{documentManager}</property>
    <searchDocumentType>AdvancedSearch</searchDocumentType>
[...]
  </coreQueryPageProvider>
</contentView>

 

searchLayout element

The searchLayout element defines what layouts needs to be used when rendering the search document model: it will be in charge of displaying the search form. This element accepts a filterDisplayType attribute: when set to "quick", it will display a form showing only the first row of the layout, visible directly above the content view results. The whole filter form is then displayed in a popup. Otherwise, the default rendering is used, and the filter form is visible in a foldable box.

The showFilterForm element makes it possible to show this form above the content view results.

The Content View Result Layouts

The result layouts control the display of resulting documents. It states different kinds of rendering so that it's possible to switch between them. They also accept a title and an icon, useful for rendering.

The layout configuration is standard and has to follow listing layouts configuration standards. The layout template, as well as widgets displaying selection checkboxes, need to perform an Ajax selection of documents, and re-render the action buttons region.

Listing layouts with a name that ends with 2_columns will be displayed on two columns by default. The layout name will be used as a message key for the selector label.

The Content View Selection List

The selectionList element will be used to fill the document list with given name.

Selection is done through Ajax, so that selection is not lost when not performing any action thanks to this selection.

The Content View Selection Actions

The actions element can be repeated any number of times: it states the actions category to use to display buttons applying to this table ("copy", "paste", "delete",...). Each actions element will generate a new row of buttons.

These actions will be displayed under the table in default templates, and will be re-rendered when selecting an item of the table so that they are enabled or disabled. This is performed using adequate filters, performing checks on selected items.

Note that these actions usually hard-code their usage of a given selection list (whether when filtering the action visibility, whether when performing the action on the list of documents).

Additional Configuration

searchDocument

The searchDocument variable can be used in EL expressions to bind the page size, the sort information and the result columns to the search document properties.

Sample usage:

<contentView name="myContentView">
  <coreQueryPageProvider>
    <property name="coreSession">#{documentManager}</property>
    <whereClause docType="AdvancedSearch">
      <fixedPart>
        ecm:currentLifeCycleState != 'deleted'
      </fixedPart>
      <predicate parameter="dc:title" operator="FULLTEXT">
        <field schema="dublincore" name="title" />
      </predicate>
      <pageSizeBinding>#{searchDocument.cvd.pageSize}</pageSizeBinding>
      <sortInfosBinding>#{searchDocument.cvd.sortInfos}</sortInfosBinding>
    </whereClause>
  </coreQueryPageProvider>
  [...]
</contentView>

The searchDocument element can be filled on a content view using an EL expression: it will be used as the search document model. Otherwise, a bare document will be generated from the document type.

Sample usage, showing how to add a clause to the search depending on title set on the current document (will display non deleted document with the same title):

<contentView name="sampleContentViewWithCustomSearchDocument">
  <searchDocument>#{currentDocument}</searchDocument>
  <coreQueryPageProvider>
    <property name="coreSession">#{documentManager}</property>
    <whereClause docType="AdvancedSearch">
      <fixedPart>
        ecm:currentLifeCycleState != 'deleted'
      </fixedPart>
      <predicate parameter="dc:title" operator="FULLTEXT">
        <field schema="dublincore" name="title" />
      </predicate>
    </whereClause>
  </coreQueryPageProvider>
</contentView>

resultColumns element

The resultColumns element can be filled on a content view using an EL expression: it will be used to resolve the list of selected columns for the current result layout. If several result layouts are defined, they should be configured so that their rows are always selected in case the selected column names do not match theirs.

Sample usage, showing how to reuse selected columns set on the search document model already defined for filtering:

<contentView name="myContentView">
  [...]
  <resultColumns>
    #{searchDocument.cvd.selectedLayoutColumns}
  </resultColumns>
</contentView>

resultLayout element

The resultLayout element can be filled on a content view using an EL expression: it will be used to resolve the current result layout.

Sample usage, showing how to reuse the selected result layout set on the search document model already defined for filtering:

<contentView name="myContentView">
  [...]
  <resultLayout>
    #{searchDocument.cvd.resultLayoutName}
  </resultLayout>
</contentView>
Additional rendering information

Additional rendering information can also be set, to be used by templates when rendering the content view:

<contentView name="CURRENT_DOCUMENT_CHILDREN">
  <title>label.current.document.children</title>
  <translateTitle>true</translateTitle>
  <iconPath>/icons/document_listing_icon.png</iconPath>
  <emptySentence>label.content.empty.search</emptySentence>
  <translateEmptySentence>true</translateEmptySentence>
  <translateEmptySentence>true</translateEmptySentence>
  <showPageSizeSelector>true</showPageSizeSelector>
  <showRefreshCommand>true</showRefreshCommand>

...
</contentView>

The element showTitle can be used to define a title for the content view, without displaying it on the default rendering. It can also be used when exporting the content view in CSV format, for instance.

The elements emptySentence and translateEmptySentence are used to display the message stating that there are no elements in the content view.

The elements showPageSizeSelector and showRefreshCommand are used to control the display of the page size selector, and of the "refresh current page" button. They both default to true.

Caching

The cacheKey element, if filled, will make it possible to keep content views in cache in the current conversation. It accepts EL expressions, but a static cache key can be used to cache only one instance.

The cacheSize element is useful to use a queue of cached instances. In the example, 10 instances of content views with a different cache key will be kept in cache. When the 11th entry, with a new cache key, is generated, the first content view put in the cache will be removed, and will need to be re-generated again. This cache configuration will make it possible to navigate to 10 different folderish document pages, and keep the current page, the current sort information, and current result layout.

When caching only one instance, setting the cacheSize element to more than "1" is useless. Caching only one instance can be useful when several features need to retrieve information from the same content view.

If a cache key is given, but no cache size is set, "5" will be used by default. Using "0" means no caching at all (and the cache key will be ignored).

Caching is done by a Seam component named contentViewActions . Although the cache key, cache size and events configurations handle the most common use cases, it is sometimes useful to call this bean methods directly when forcing a refresh.

The refresh and reset elements configurations make it possible to refresh/reset this content view when receiving the listed Seam event names. Only documentChanged and documentChildrenChanged are handled by default, but it is possible to react to new events by adding a method with an observer on this event on a custom Seam component, and call the method contentViewActions.refreshOnSeamEvent(String seamEventName) or contentViewActions.resetPageProviderOnSeamEvent(String seamEventName).

Refresh will keep current settings, and will force the query to be done again. Reset will delete content views completely from the cache, and force complete re-generation of the content view, its provider, and the search document model if set.

cache size "0" behaviour

Before 5.7.1, selection actions were misbehaving when using a cache of size "0", so content views with selections actions needed a cache size of at least "1". Since 5.7.1 (and 5.6-HF02), when using value "0", the content view is cached anyhow, but its page provider is refreshed every time it is rendered.

As this behavior is costly, using refresh events can be enough most of the time. But it is not possible to trigger a refresh for other users when using Seam events, so this configuration makes it possible to make sure the content view is up to date when other users may have an impact on its content.

Document Content Views

It is possible to define content views on a document type. This makes it easier to define folderish documents views.

Here is the default configuration of content views for Nuxeo folderish documents:

<type id="Folder">
  <label>Folder</label>
  ...
  <contentViews category="content">
    <contentView>document_content</contentView>
  </contentViews>
  <contentViews category="trash_content">
    <contentView showInExportView="false">document_trash_content</contentView>
  </contentViews>
</type>

The document_content content view will be displayed on this folder default view, and the document_trash_content content view will be displayed on the Trash tab.

The category attribute is filled from XHTML templates to render all content views defined in a given category.

The showInExportView attribute is used to check whether this content view should be displayed in the document export view (and PDF export).

If several content views are filled in the same category, both will be displayed on the same page.