We show a dynamic function that collects items and allows to link to a detail view of each item.

The result

Click on the headings of the list entries to see their detail views. If you are offline, you might also change some parameters of the function that provides the list.

In the detail view a special formatter is used. It displays the title, the text and the image, if present. Hence, it may happens that the content says "Do something!" - but you simply can't because of the different formatter that is used. Or the article might describe somethings thats not true for its detail view formatter.
 

Demo - Lists and detail pages

Nothing found for query:
fq=parent-folders:"/sites/default/documentation/demos/.content/documentation-demo-article/"&fq=type:documentation-demo-article&rows=5&sort=lastmodified desc
 

Example resources and the interesting spots

In this demo different things are of interest:

  • How to build the list?
  • How to add a detail-page for a type?
  • How to configure the naming scheme for the URLs of detail pages?

We discuss these questions in the following subsections.

2.1 How the list is created

The list, shown in the example is generated by a dynamic function. The function provider looks as follows:

In the dynamic function that uses the provider, the parameters folder, type and count are specified. If offline, click on the function's edit point in the result section.
<%@page buffer="none" session="false" trimDirectiveWhitespaces="true" taglibs="c,cms,fn" %>
<cms:formatter var="con" rdfa="rdfa">
	<div>
		<div class="headline"><h3 ${rdfa.Title}><c:out value="${con.value.Title}" escapeXml="false" /></h3></div>
		<c:set var="folder">
			<c:choose>
			<c:when test="${fn:startsWith(param.folder,'/system') or fn:startsWith(param.folder,'/shared')}">
				${param.folder}
			</c:when>
			<c:otherwise>
				${cms.requestContext.siteRoot}${param.folder}
			</c:otherwise>
			</c:choose>
		</c:set>
		<%-- Define a Solr query --%>
		<c:set var="solrQuery">fq=parent-folders:"${folder}"&fq=type:${param.type}&rows=${param.count}&sort=lastmodified desc</c:set>
		<%-- Define a create path --%>
		<c:set var="createPath">${param.folder}</c:set>
		<%-- Collect the resources --%>
		<cms:contentload collector="byContext" param='${solrQuery}|createPath=${createPath}article_%(number).xml' 
		                 preload="true" >
			<cms:contentinfo var="info" />
			<c:choose>
			<c:when test="${info.resultSize > 0}">
				<cms:contentload editable="true">
					<cms:contentaccess var="content" />
					<div>
						<h4><a href="<cms:link>${content.filename}</cms:link>">${content.value.Title}</a></h4>
						<hr />
					</div>
				</cms:contentload>
			</c:when>
			<c:otherwise>
				Nothing found for query:<br/><em>${solrQuery}</em>
			</c:otherwise>
			</c:choose>
		</cms:contentload>
	</div>
</cms:formatter>

The most interesting part is the <cms:contentload>-tag. It is used twice. Once, in the "outer" use, with preload="true" as attribute and the attributes collector and param. The collector attribute specifies which collector is used and the param attribute configures the collector. In the example, we use the Solr-collector byQuery and configure it with a Solr query and (after the |) with the path and a name scheme that specifies where and under which name new resources are created.

Setting preload to true avoids loading the resources completely. The loaded information suffices to know, e.g., the number of results, as is read via info.resultSize from the info object exposed by <cms:contentinfo var="info" />. If we have at least one result, we start loading the content fully by the "inner" <cms:contentload>. It takes over collector and param from the outer tag and the additional attribute editable="true" enables us to edit, add and delete list entries.

The "inner" <cms:contentload>'s body is looped through for each collected content and via <cms:contentaccess> we get access to the current content in the same way we get access to a content in a formatter. The link to ${content.filename} by default links to the content itself. But, if a detail page for contents of that type is configured, <cms:link> redirects the link to this detail page.

2.2 How the detail page is added

If detail pages for a content type are allowed (what is configured in the module configuration of the module where the resource type is defined), you can add a detail page via the sitemap editor. Therefore, go to the sitemap editor, open the "Add wizard" and choose the tab "Detail pages". Now you can select the detail page for your type and drop it in the sitemap.

In the example, we added the page "Article detail pages" as detail page for the type "documentation-demo-article". The page is marked as such a detail page in the sitemap by stating the type in brackets and using the type's icon for the page entry:

How the URL name is adjusted

While the first part of the URL of the detail view of an article is quite clear: It is the detail pages URL, the last, content-specific part is not that obvious. In the demo, it is generated from the article's Title elements. This behavior is configured in the content type definition of the article. In the <appinfo>-part a mapping from the Title element to urlName is configured:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	elementFormDefault="qualified">

	<xsd:include schemaLocation="opencms://opencms-xmlcontent.xsd" />

	<xsd:element name="DocumentationDemoArticles" type="OpenCmsDocumentationDemoArticles" />

	<xsd:complexType name="OpenCmsDocumentationDemoArticles">
		<xsd:sequence>
			<xsd:element name="DocumentationDemoArticle" type="OpenCmsDocumentationDemoArticle"
				minOccurs="0" maxOccurs="unbounded" />
		</xsd:sequence>
	</xsd:complexType>

	<xsd:complexType name="OpenCmsDocumentationDemoArticle">
		<xsd:sequence>
			<xsd:element name="Title" type="OpenCmsString" />
			<xsd:element name="Text" type="OpenCmsHtml" />
			<xsd:element name="Image" type="OpenCmsVfsImage" minOccurs="0" />
			<xsd:element name="Script" type="OpenCmsString" minOccurs="0" />
		</xsd:sequence>
		<xsd:attribute name="language" type="OpenCmsLocale" use="optional" />
	</xsd:complexType>

	<xsd:annotation>
		<xsd:appinfo>
			<layouts>
				<layout element="Script" widget="TextareaWidget" configuration="10" />
			</layouts>
			<mappings>
				<mapping element="Title" mapto="urlName" />
			</mappings>
		</xsd:appinfo>
	</xsd:annotation>
</xsd:schema>	  

It is possible to map every other element instead of Title. If no element is mapped, the resource-id of the article content would be used for the content-specific URL part.