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" />
<quickFilters>
<quickFilter name="myQuickFilter">
<clause>dc:title IN ('Title 1', 'Title 2')</clause>
<sort column="dc:creator" ascending="true" />
</quickFilter>
</quickFilters>
<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).
quickFilter elements
Since version 8.10, the quickFilter
element enables to refine the results obtained by a search. There can be any number of quickFilter
elements. Each quick filter is composed of a clause
element which enables to extend the query, and additional sort
elements.
The quick filters appears in the interface as buttons where each action on a button enables or disables its associated quick filter.
In the previous example, activating "myQuickFilter" will display the children of the current document with the titles "Title1" or "Title2". The search results will be ordered by creator.
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, 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. This is configurable by contributing the property nuxeo.pageprovider.default-max-page-size
to the Configuration service.
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 by contributing the propertyorg.nuxeo.ecm.platform.query.nxql.defaultNavigationResults
to the Configuration service.PAGE_SIZE
: this is useful when you are interested in a single page or if you don't need a total count.
Note that when using an Elasticsearch page provider, the maxResults
limit is not taken in account because the total number of results is always available.
For performance reason by default Elasticsearch does not allow you to do unlimited deep scrolling on results.
Only the index.max_result_window
results (which defaults to 10000) are accessible. Content view will not allow you to access pages out of this window to prevent errors.
If you change the Elasticsearch configuration you can adapt the Nuxeo limit by contributing the property org.nuxeo.elasticsearch.provider.maxResultWindow
to the Configuration service.
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:isCheckedInVersion = 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 behavior:
statement
makes is possible to declare the select statement to use (as contrary to thepattern
element, thefixedPart
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, theescapeParameters
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(dc:title,dc:description)" parameter="dc:title" operator="FULLTEXT">
<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 value 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.
waitForExecution element
The waitForExecution
element waits for a boolean value, and defaults to false. When set to true, the query will not be executed right away: this is useful when user has to submit filtering criteria first, when search criteria are presented on the side of the page, for instance. When submitting the filtering form, the content view will be marked as executed (it can also be explicitely marked as executed by using the content view API) and search results will be presented.
The waitForExecutionSentence
element can also be used to customize the text presented to the user when the content view is not executed yet. Note that the sentence will be translated if the translateEmptySentence
element is set to true.
Sample declaration:
<contentView name="myContentView">
<waitForExecution>true</waitForExecution>
<waitForExecutionSentence>
label.search.waitForExecution
</waitForExecutionSentence>
</contentView>
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 default 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>
...
<coreQueryPageProvider>
...
<pageSizeOptions>
<option>10</option>
<option>15</option>
<option>20</option>
</pageSizeOptions>
...
</coreQueryPageProvider>
...
</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.
Since version 7.3, the pageSizeOptions
element allows to configure available options for page size selection in the UI. If not filled, values 10, 20, 30, 40 and 50 will be displayed by default, as well as the page provider default pageSize
element value (as well as the current page size, if not already present in this list).
Check out chapter Content Views Display for more display information and customization.
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.
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 that 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.