Table of Contents
The User Interface framework uses different kinds of concepts to make the interface configurable in the same way that the application itself is.
Links and pages that appear on the site can be the result of a "static" template written in the XHTML language, but can also be the result of a configuration change, taken into account thanks to more "generic" XHTML pages.
The following chapters will explain how configuration and templating combine to achieve the UI of the site.
In this chapter, an action will stand for any kind of command that can be triggered via user interface interaction. In other words, it will describe a link and other information that may be used to manage its display (the link label, an icon, security information for instance).
Custom actions can be contributed to the actions service, using its extension point. Their description is then available through this service to control where and how they will be displayed.
An action can be registered using the following example extension:
<extension target="org.nuxeo.ecm.platform.actions.ActionService" point="actions"> <action id="logout" link="#{loginLogoutAction.logout}" label="command.logout"> <category>USER_SERVICES</category> </action> </extension>
Example 7.1. Example of an action registration
The above action will be used to display a "logout" link
on the site. Here are its properties:
id
: string identifying the action. In
the example, the action id is "logout".
label
: the action name that will be
used when displaying the link. In the example, the label is
"command.logout". This label is a message that will be
translated at display.
link
: string representing the command
the action will trigger. This string may represent a different
action given the template that will display the action. In the
example, a JSF command link will be used, so it represents an
action method expression. The seam component called
"loginLogoutAction" holds a method named "logout" that will
perform the logout and return a string for navigation.
category
: a string useful to group
actions that will be rendered in the same area of a page. An
action can define several categories. Here, the only category
defined is "USER_SERVICES". It is designed to group all the
actions that will be displayed on the right top corner of any
page of the site.
Other properties can be used to define an action. They are
listed here but you can have a look at the main actions contributions
file for more examples:
nuxeo-platform-webapp-core/srs/main/resources/OSGI-INF/actions-contrib.xml
.
filter-ids
: id of a filter that will be
used to control the action visibility. An action can have
several filters: it is visible if all its filters grant the
access.
filter
: a filter definition can be done
directly within the action definition. It is a filter like
others and can be referred by other actions.
icon
: the optional icon path for this
action.
confirm
: an optional Javascript
confirmation string that can be triggered when executing the
command.
order
: an optional integer used to sort
actions within the same category. This attribute may be
deprecated in the future.
enabled
: boolean indicating whether the
action is currently active. This can be used to hide existing
actions when customizing the site behavior.
Actions extension point provides merging features: you can change an existing action definition in your custom extension point provided you use the same identifier. Properties holding single values (label, link for instance) will be replaced using the new value. Properties holding multiple values (categories, filters) will be merged with existing values.
Actions in the same category are supposed to be displayed in the same area of a page. Here are listed the main default categories if you want to add an action there:
USER_SERVICES
: used to display actions
in the top right corner of every page. The link attribute should
look like a JSF action command link. See the example
above.
VIEW_ACTION_LIST
: used for tabs
displayed on every document. As each tab is not displayed in a
different page, but just includes a specific template content in
the middle of the page, the link attribute has to be a template
path. For instance:
<action id="TAB_VIEW" link="/incl/tabs/document_view.xhtml" enabled="true" order="0" label="action.view.summary"> <category>VIEW_ACTION_LIST</category> <filter-id>view</filter-id> </action> <action id="TAB_CONTENT" link="/incl/tabs/document_content.xhtml" order="10" enabled="true" label="action.view.content"> <category>VIEW_ACTION_LIST</category> <filter-id>view_content</filter-id> </action>
SUBVIEW_UPPER_LIST
: used to display
actions just below a document tabs listing. As
USER_SERVICES
, these actions will be
displayed using a command link, so the link attribute has to be
an action method expression. For instance:
<action id="newSection" link="#{documentActions.createDocument('Section')}" enabled="true" label="command.create.section" icon="/icons/action_add.gif"> <category>SUBVIEW_UPPER_LIST</category> <filter id="newSection"> <rule grant="true"> <permission>AddChildren</permission> <type>SectionRoot</type> </rule> </filter> </action> <action id="newDocument" link="select_document_type" enabled="true" label="action.new.document" icon="/icons/action_add.gif"> <category>SUBVIEW_UPPER_LIST</category> <filter-id>create</filter-id> </action>
An action visibility can be controlled using filters. An action filter is a set of rules that will apply - or not - given an action and a context.
Filters can be registered using their own extension point, or registered implicitly when defining them inside of an action definition:
<filter id="view_content"> <rule grant="true"> <permission>ReadChildren</permission> <facet>Folderish</facet> </rule> <rule grant="false"> <type>Root</type> </rule> </filter>
Example 7.2. Example of a filter registration
<action id="newSection" link="#{documentActions.createDocument('Section')}" enabled="true" label="command.create.section" icon="/icons/action_add.gif"> <category>SUBVIEW_UPPER_LIST</category> <filter id="newSection"> <rule grant="true"> <permission>AddChildren</permission> <type>SectionRoot</type> </rule> </filter> </action>
Example 7.3. Example of a filter registration inside an action registration
A filter can accept any number of rules. It will grant
access to an action if, among its rules, no denying rule
(grant=false)
is found and at least one granting
rule (grant=true)
is found. A general rule to
remember is that if you would like to add a filter to an action that
already has one or more filters, it has to hold constraining rules: a
granting filter will be ignored if another filter is already too
constraining.
If no rule is set, the filter will grant access by default.
The default filter implementation uses filter rules with the following properties:
grant
: boolean indicating whether this
is a granting rule or a denying rule.
permission
: permission like "Write"
that will be checked on the context for the given user. A rule
can hold several permissions: it applies if user holds at least
one of them.
facet
: facet like "Folderish" that can
be set on the document type
(org.nuxeo.ecm.core.schema.types.Type
) to
describe the document type general behavior. A rule can hold
several facets: it applies if current document in context has at
least one of them.
condition
: EL expression that can be
evaluated against the context. The Seam context is made
available for conditions evaluation. A rule can hold several
conditions: it applies if at least one of the conditions is
verified.
type
: document type to check against
current document in context. A rule can hold several types: it
applies if current document is one of them. The fake 'Server'
type is used to check the server context.
schema
: document schema to check
against current document in context. A rule can hold several
schemas: it applies if current document has one of them.
group
: group like "members" to check
against current user in context. A rule can hold several
groups: it applies if current user is in one of them.
Filters do not support merging, so if you define a filter with an id that is already used in another contribution, only the first contribution will be taken into account.
It is important to understand that an action does *not* define the way it will be rendered: This is left to pages, templates and other components displaying it. Most of the time, actions will be rendered as command links or command buttons.
For instance, actions using the USER_SERVICES
category will be rendered as action links:
<nxu:methodResult name="actions" value="#{webActions.getActionsList('USER_SERVICES')}"> <nxu:dataList layout="simple" var="action" value="#{actions}" rowIndexVar="row" rowCountVar="rowCount"> <h:outputText value=" | " rendered="#{row!=(rowCount-1)}" /> <nxh:commandLink action="#{action.getLink()}"> <t:htmlTag value="br" rendered="#{row==(rowCount-1)}" /> <h:outputText value="#{messages[action.label]}" /> </nxh:commandLink> </nxu:dataList> </nxu:methodResult>
The nxu:methodResult
tag is only used to
retrieve the list of actions declared for the
USER_SERVICES
category. The
nxh:commandLink
is used instead of a simple
h:commandLink
so that it executes commands that
where described as action expression methods.
Another use case is the document tabs: actions using the
VIEW_ACTION_LIST
category will be rendered as
action links too, but actions are managed by a specific seam component
that will hold the information about the selected tab. When clicking
on an action, this selected tab will be changed and the link it points
to will be displayed.
First of all, we have to make the difference between a view in a standard JSF way (navigation case view id, navigation case output) and views in Nuxeo 5 (document type view, creation view)
A standard JSF navigation rule can be defined in the
OSGI-INF/deployment-fragment.xml
files, inside
the faces-config#NAVIGATION
directive.
<extension target="faces-config#NAVIGATION"> <navigation-case> <from-outcome>create_document</from-outcome> <to-view-id>/create_document.xhtml</to-view-id> <redirect /> </navigation-case> <navigation-case> <from-outcome>view_documents</from-outcome> <to-view-id>/view_documents.xhtml</to-view-id> <redirect /> </navigation-case> </extension>
Example 7.4. Example of a navigation rule case definitions
A certain Nuxeo document type, can have defined a default view
(used to view/edit the document) and a create view (used to create the
document). These views are specified in the
OSGI-INF/ecm-types-contrib.xml
file, as in the
following example.
<extension target="org.nuxeo.ecm.platform.types.TypeService" point="types"> <type id="Workspace" coretype="Workspace"> <label>Workspace</label> <icon>/icons/workspace.gif</icon> <icon-expanded>/icons/workspace_open.gif</icon-expanded> <default-view>view_documents</default-view> <create-view>create_workspace</create-view> </type> </extension>
Example 7.5. Example of view definitions for a document type
The default view of a document is rendered as a list of tabs. As
mentioned before, the document tabs are defined as actions in the
OSGI-INF/actions-contrib
file, having as category
VIEW_ACTION_LIST
. A tab can be added to a document
default view as shown in the following example.
<extension target="org.nuxeo.ecm.platform.actions.ActionService" point="actions"> <action id="TAB_EDIT" link="/incl/tabs/document_edit.xhtml" enabled="true" order="20" label="action.view.edit" icon="/icons/file.gif"> <category>VIEW_ACTION_LIST</category> <filter-id>edit</filter-id> <filter-id>mutable_document</filter-id> </action> </extension>
Example 7.6. Example of tab definition for a default view of a document type
There are two services that help building GET URLs to restore a Nuxeo context. The default configuration handle restoring the current document, the view, current tab and current sub tab.
The service handling document views allows registration of codecs. Codecs manage coding of a document view (holding a document reference, repository name as well as key-named string parameters) in to a URL, and decoding of this URL into a document view.
<extension target="org.nuxeo.ecm.platform.url.service.DocumentViewCodecService" point="codecs"> <documentViewCodec name="docid" enabled="true" default="true" prefix="nxdoc" class="org.nuxeo.ecm.platform.url.codec.DocumentIdCodec" /> <documentViewCodec name="docpath" enabled="true" default="false" prefix="nxpath" class="org.nuxeo.ecm.platform.url.codec.DocumentPathCodec" /> </extension>
Example 7.7. Example of a document view codec registration
In this example, the docid codec uses the document uid to
resolve the context. Urls are of the form
http://site/nuxeo/nxdoc/demo/docuid/view. The docpath codec uses the
document path to resolve the context. Urls are of the form
http://site/nuxeo/nxpath/demo/path/to/my/doc@view.
Additional parameters are coded/decoded as usual request parameters.
Note that when building a document view, the url service will require a view id. The other information (document location and parameters) are optional, as long as they're not required for your context to be initialized correctly.
The service handling URLs allows registration of patterns. These patterns help saving the document context and restoring it thanks to information provided by codecs. The URL service will iterate through its patterns, and use the first one that returns an answer (proving decoding was possible).
<extension target="org.nuxeo.ecm.platform.ui.web.rest.URLService" point="urlpatterns"> <urlPattern name="default" enabled="true"> <defaultURLPolicy>true</defaultURLPolicy> <needBaseURL>true</needBaseURL> <needRedirectFilter>true</needRedirectFilter> <needFilterPreprocessing>true</needFilterPreprocessing> <codecName>docid</codecName> <actionBinding>#{restHelper.initContextFromRestRequest}</actionBinding> <documentViewBinding>#{restHelper.documentView}</documentViewBinding> <newDocumentViewBinding>#{restHelper.newDocumentView}</newDocumentViewBinding> <bindings> <binding name="tabId">#{webActions.currentTabId}</binding> <binding name="subTabId">#{webActions.currentSubTabId}</binding> </bindings> </urlPattern> </extension>
Example 7.8. Example of a url pattern registration
In this example, the "default" pattern uses the above
"docid" codec. Its is set as the default URL policy, so that it's used
by default when caller does not specify a pattern to use. It needs the
base URL: the docid codec only handles the second part if the URL. It
needs redirect filter: it will be used to provide the context
information to store. It needs filter preprocessing: it will be used to
provide the context information to restore. It's using the docid
codec.
The action binding method handles restoring of the context in the Seam context. It takes a document view as parameter. It requires special attention: if you're using conversations (as Nuxeo does by default), you need to annotate this method with a "@Begin" tag so that it uses the conversation identifier passed as a parameter if it's still valid, or initiates a new conversation in other cases. The method also needs to make sure it initializes all the seam components it needs (documentManager for instance) if they have not be in intialized yet.
The additional document view bindings are used to pass document view information through requests. The document view binding maps to corresponding getters and setters. The new document view binding is used to redirect to build GET URL in case request is a POST: it won't have the information in the URL so it needs to rebuild it.
Other bindings handle additional request parameters. In this example, they're used to store and restore tab and sub tab information (getters and setters have to be defined accordingly).
The URL patterns used need to be registered on the authentication service so that they're considered as valid urls. Valid urls will be stored in the request, so that if authentication is required, user is redirected to the url after login.
<extension target="org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService" point="startURL"> <startURLPattern> <patterns> <pattern>nxdoc/</pattern> </patterns> </startURLPattern> </extension>
Example 7.9. Example of a start url pattern registration
Just the start of the url is required in this configuration.
Contributions are merged: it is not possible to remove an existing start
pattern.
The URL patterns used also need to be handled by the default nuxeo authentication service so that login mechanism (even for anonymous) applies for them.
<extension target="web#STD-AUTH-FILTER"> <filter-mapping> <filter-name>NuxeoAuthenticationFilter</filter-name> <url-pattern>/nxdoc/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> </extension>
Example 7.10. Example authentication filter configuration
This is a standard filter mapping configuration.
There are some JSF tags and functions helping you to define what kind of GET URL should be displayed on the interface.
<nxd:restDocumentLink document="#{doc}"> <nxh:outputText value="#{nxd:titleOrId(doc)}" /> </nxd:restDocumentLink>
Example 7.11. Example of nxd:restDocumentLink use
In this example, the tag will print a simple link, using the
default pattern, and build the document view using given document model,
using its default view.
Please refer to the tag library documentation available at http://doc.nuxeo.org/5.1/tlddoc/nxd/restDocumentLink.html for additional parameters: it's possible to set the tab, sub tab, and use a specific URL pattern.
Note that you can also use JSF functions to build the GET URL. This is what's done for file links: the function queries the URL policy service to build the URL.
<nxh:outputLink rendered="#{doc.hasSchema('file') and !empty doc.file.content}" value="#{nxd:fileUrl('downloadFile', doc, 'file:content', doc.file.filename)}"> <nxh:graphicImage value="/icons/download.png" style="vertical-align:middle" title="#{doc.file.filename}" /> </nxh:outputLink>
Example 7.12. Example of a jsf function use
public static String fileUrl(String patternName, DocumentModel doc, String blobPropertyName, String filename) { try { DocumentLocation docLoc = new DocumentLocationImpl(doc); Map<String, String> params = new HashMap<String, String>(); params.put(DocumentFileCodec.FILE_PROPERTY_PATH_KEY, blobPropertyName); params.put(DocumentFileCodec.FILENAME_KEY, filename); DocumentView docView = new DocumentViewImpl(docLoc, null, params); // generate url URLPolicyService service = Framework.getService(URLPolicyService.class); if (patternName == null) { patternName = service.getDefaultPatternName(); } return service.getUrlFromDocumentView(patternName, docView, BaseURL.getBaseURL()); } catch (Exception e) { log.error("Could not generate url for document file", e); } return null; }
Example 7.13. fileUrl method code
Similar methods exist for more complex urls, when handling files in list for instance. Please refer to the list at http://doc.nuxeo.org/5.1/tlddoc/nxd/tld-summary.html.
The Document List Manager provides a service to manage lists of Nuxeo documents.
These lists of documents can have properties such as:
a name, defined by name
attribute.
a scope (session or conversation), defined by
<isSession/>
tag - it defines if the memory
storage occurs in the Seam session context or in the Seam
conversation context.
a persistence (SQL directory or not present), defined by
<persistent/>
tag - the service persists
only the list of the document references, not the real documents;
the lists of document references is persisted in a SQL directory,
which is generic and does not need any configuration.
The lists of documents can be invalidated when Seam events are
raised. This is usefull, for example, for resetting
CURRENT_SELECTION
lists when the user change the
current folder or when a new search is performed.
Documents lists can be defined like in the following example
(OSGI-INF/documentslists-contrib.xml
):
<extension target="org.nuxeo.ecm.webapp.documentsLists.DocumentsListsService" point="list"> <documentsList name="CLIPBOARD"> <category>CLIPBOARD</category> <imageURL>/img/clipboard.gif</imageURL> <title>workingList.clipboard</title> <defaultInCategory>false</defaultInCategory> <supportAppends>false</supportAppends> </documentsList> <documentsList name="CURRENT_SELECTION"> <events> <event>folderishDocumentSelectionChanged</event> <event>searchPerformed</event> </events> <isSession>false</isSession> </documentsList> </extension>
Example 7.14. Example of documents lists definition
The File Manager provides a service which exposes a simple API in order to create a Nuxeo document model from a passed blob file. Also, this service exposes as extension point which can be used to define plugins.
When the File Manager service is called, it will detect the mime-type of the passed blob, and will try to find a plugin to hadle the creation of a Nuxeo document model based on the detected mime-type.
Typical usages:
txt/html/xml files - a Note
document is
created.
image files - a Picture
document is created
(if nuxeo-platform-imaging
addon is
deployed).
folder - a Folder
document is created.
other files - a File
document is
created.
Pugins can be defined like in the following example
(OSGI-INF/nxfilemanager-plugins-contrib.xml
):
<extension target="org.nuxeo.ecm.platform.filemanager.service.FileManagerService" point="plugins"> <plugin name="Noteplugin" class="org.nuxeo.ecm.platform.filemanager.service.extension.NotePlugin"> <filter>text/plain</filter> <filter>text/html</filter> <filter>application/xhtml+xml</filter> <filter>application/xml</filter> <filter>text/xml</filter> </plugin> </extension>
Example 7.15. Example of File Manager plugins definition
As a client of the File Manager service can be used the browser plugins (for Firefox and Internet Explorer) which can be be downloaded through the links from the default Nuxeo 5 login page. These plugins enable the user to create Nuxeo documents just by dragging & dropping folders/files to the browser. The plugins use a restlet (HTTP API) to send files/folders to the Nuxeo 5 Platform. The restlets use the File Manager serivce in order to create a Nuxeo document from the passed file.
Please refer to the tag library documentation available at http://doc.nuxeo.org/5.1/tlddoc/.