Part I: Portal Theme Developer's Guide
Chapter 1: Portal Theme Basics
Portal Theme development is best done by Web developers. Specifically, the skills you should be at least familiar with include HTML, CSS, Javascript, and in some cases, XSLT.
1.1: What is a Portal Theme?
Titania Delivery comes with a default portal theme, meant to be used either as an out-of-the-box solution to delivering and presenting your content or as a starting point for customizing a different look and feel. Every aspect of a Portal Theme is customizable. A new portal theme could also be created from scratch by deleting every file in a default theme, adding brand new versions of the required pages, and extending the theme by adding new custom pages.
If you are familiar with the Model-View-Controller pattern, you'll recognize that Portal Themes represent the 'View' aspect, with Titania Delivery providing the models and controllers.
1.2: Portal Theme Directory Structure
All Portal Themes must have the following three top-level folders:
-
/pages
- The pages directory contains the HTML templates used to draw the application pages required for all Portals to function. Titania Delivery templates are written using the Freemarker template language, which will be discussed later. -
/static
- The static directory contains website assets, such as images and CSS stylesheets, that are referenced from your page templates. -
/xsl
- The xsl directory contains the XSLT transforms that can convert XML content into HTML for display in the portal.
Offline packagers must be defined in the following directory:
-
/packagers
- Specific packagers will be defined in subdirectories named after the packager (e.g. "webhelp"). Other subdirectories may be included to contain common templates and resources for all packagers.
In addition, Portal Themes should include a config.xml
file at the root
level. This file will contain parameters that allow for easy customization of a portal's
appearance without actually modifying the theme.
Chapter 2: Page Templates
/pages
directory contains the templates that generate the HTML of a
Portal.2.1: What Is Freemarker?
Freemarker is a text templating engine. It provides looping and branching constructs as well a library of powerful functions (built-ins), directives, and expressions that allow for creating reusable templates which generate HTML or any other textual content. Freemarker pages are defined by templates and data-models. Data-models are the data provided to templates. Titania Delivery provides each template with a data-model, and the template designer can use that model to render and display appropriate information. Freemarker files have a .ftl file extension.
2.2: Common Template Variables
Within a Freemarker template, these properties can be accessed with
${propertyName}
. Many properties have fields (and sometimes those fields
have fields themselves). These can be accessed with dot syntax. For example,
${propertyName.fieldName}
.
Common Properties
The following properties are present on every page:
-
portal
- A complex object containing the properties of the portal itself. See PortalIdentity.
-
hasSecurity
- A boolean property indicating whether the portal is configured for security.
-
isAuthenticated
- A boolean property indicating whether the current user has logged in.
-
user
- A complex object containing the properties of the authenticated user. See PortalUser.
-
currentUrl
- The absolute URL of the current page, excluding any fragment identifier.
-
request
- The
HttpServletRequest
object for the current request. -
RequestParameters
- A hash of the URL parameters passed to the request.
-
userData
- A UserDataStorage object that can be used to store and retrieve persistent data for the current user or session.
-
siteData
- A SiteDataStorage object that can be used to store and retrieve global data shared by all users.
-
buildString
- A string containing Titania Delivery versioning information.
-
online
andoffline
- Boolean variables indicating whether the script is executing in an 'online' (normal) mode or as part of an offline packager. These variables can be used to easily conditionalize modules that contain logic for both online and offline page generation. See Offline Packagers for details.
-
t
- The namespace for the layout template directives.
Commenting-Related Properties
The following properties are also present on every page, but pertain specifically to commenting-related features.
-
cmScriptLocation
- A string specifying the URL of the Titania Annotator Javascript library.
-
moderators
- An array of the ids of the users configured as comment moderators.
2.3: Portal Theme Pages
Most of the following pages are located in the root of the /pages
directory, with the exception of the pages contained in the /errors
directory. There are no requirements regarding the content of the following files;
any one of
them could be left blank without causing problems as long as they are not linked to.
When
rendered, these pages' data-models are supplemented with data structures specifically
designed
for the purpose connoted by the file's name.
Portal Theme Page URLs
Template File | URL Pattern(s) | Description |
---|---|---|
/pages/portal-home.ftl
|
/portalPath/
|
Portal landing page. |
/pages/searchResults.ftl
|
/portalPath/search
|
Search results page. |
/pages/viewer.ftl
|
/portalPath/viewer/* ,
/portalPath/content/*
|
Viewer page for XML content in the context of other documents. For example, a DITA topic in the context of a DITA map, or a chunked section of a non-DITA XML document. |
/pages/mapViewer.ftl (deprecated) |
/portalPath/viewer/* ,
/portalPath/content/*
|
Viewer page for top-level embeddable content, such as XML, Markdown, and HTML
fragments (no root <html> element.
Note: This page is
deprecated, and should simply <#include>
viwer.ftl . This template may be removed in a future
release. |
/pages/login.ftl
|
/portalPath/login
|
Login page for LDAP-based authentication. |
/pages/assemblyViewer.ftl
|
/portalPath/assembly/assemblyKey/
|
ToC view page of an assembly. |
/pages/assemblyTopicViewer.ftl
|
/portalPath/assembly/assemblyKey/topicId
|
Viewer page for an entry in an assembly. |
/pages/assemblyPreview.ftl
|
N/A | Template used to render the preview view of a topic in the assembly editor. |
/pages/custom/*.ftl
|
/portalPath/pages/*
|
Custom pages. |
/pages/error.ftl
|
N/A | Page used to present HTTP errors (404, 500, etc.). |
2.3.1: Portal Landing Page
/pages/portal-home.ftl
template in the
portal theme. The base URL of any portal is the URL path
/portalUrlPath/
. When navigating to a Portal URL,
this page will be rendered.Page Variables
This page has access to all of the common variables.
2.3.2: Search Results Page
/pages/searchResults.ftl
template in
the portal theme. The search results page is meant to show the results of a query,
and is bound
to the URL path /portalUrlPath/search
.This page is populated with search results from the following query parameters:
-
escape
- Either
true
orfalse
. Specifies whether special query characters in theterm
should be escaped when executing the query. The default isfalse
. See Search Syntax for details of reserved search characters. -
facet
- A metadata field to use as a search facet. If not specified, the search facets configured for the portal are used. See the Titania Delivery Administrative Guide for details on configuring a portal's default search facets. This parameter may be specified multiple times to specify multiple metadata fields to use as facets.
-
filter
- A secondary search query to use to filter the available documents that should be
included in the results. The same results could be achieved by adding additional
criteria to the
term
, but there are performance benefits to using a separatefilter
parameter, especially when the same filter may be reused for multiple searches. -
groupBy
- The property for grouping results. Default is
itemKey
. -
groupSize
- The maximum number of contextualized DITA topics to include in result groupings. The
default is
5
. -
highlightSize
- The maximum number of characters to include in text snippets containing matching text.
The default is
300
. -
maxFacetValues
- The maximum number of facet values to include in the search results. The default is
10
. -
n
- The number of search results to return per page. If not specified, the default is
10
. -
page
- The zero-based index of the page to view. The default is
0
. -
portalContent
- Portals can generate files using the
siteData
interface. This parameter specifies if and how content in that project should be included in the search. The valid values are:-
exclude
- Portal-generated content is excluded. This is the default.
-
include
- Portal-generated content is included, along with other content available through the portal.
-
only
- Only portal-generated content will be included in the results.
-
-
sortBy
- The property name or names by which to sort the results. (All metadata values are
indexed as keywords, and must be named with '_md' suffix: for example,
sortBy=title_md
.) Multiple names may be specified, separated by spaces or commas (URL-encoded as necessary). MultiplesortBy
parameters may be included, but since the order of parameter processing is not guaranteed to be consistent, it is advisable to use only onesortBy
parameter if correspondingsortDirection
s are specified.Note: Sort keys given in thesortBy
parameter will be used before the default "relevance" (as determined by the search engine) is applied. So the top items in the result list might not be the "most relevant" based on the search term. -
sortDirection
- Specify the sort directions corresponding to each sortBy field. If
the list of sort directions is empty or shorter than the list of
sortBy
fields, the default order isASC
. Values may be eitherASC
orDESC
(case-insensitive) to specify the sort direction as ascending or descending. MultiplesortDirection
parameters may be included, but since the order of parameter processing is not guaranteed to be consistent, it is advisable to use only onesortDirection
parameter (with multiple values, if necessary). -
startAfter
- For programmatic use only, this should be an object value from the SearchResultsPage
startNextAfter
property. -
term
- The search query.
Additionally, any number of metadata filters can be supplied, each in the format:
f.[metadataName]_md
. All parameters are optional but if a
term
parameter is not supplied the search results will be empty.
For example, assume the search page is requested with the following URL query string:
?term=Titania&n=5&page=1&f.format_md=dita
. The page would be
populated with data containing up to five search results of the second page (remember
that
the page
param is zero-indexed) of results that match the search term
Titania
that have format
metadata with a value of
dita
.
- Search results for the word "Titania"
- Up to five results
- Starting with the sixth result, because we requested the second page (because the
page
parameter is zero-indexed).
Data Model
In addition to the common properties, this page has access to the following:
-
filterParams
- A string containing the URL parameters for the metadata filters being applied to the
search. This is a convenience property that could be constructed manually from the
filters
data structure. This property can be used to easily construct URLs in paginated search result lists. -
filters
-
A hash. The keys of the hash are the metadata names being used to filter results. Each keyed entry is an array of the values for that metadata name specified by the user for filtering.
For example, if a user filters on a metadata named "foo" using values "abc" and "xyz", the
${filters}
hash would look like this:{ foo: ['abc', 'xyz'] }
-
result
- A SearchResultsPage containing the set of results to display, grouped by context, represented by SearchResultGroup objects.
-
sortBy
- Sequence or null. If
sortBy
names were given, this will be a sequence of the givensortBy
field names. -
sortDirection
- Sequence or null. If
sortDirection
parameter was given, this will be the sequence of values specified. -
term
- The search term entered by the user.
2.3.3: Embeddable Content Viewer Pages
/pages/viewer.ftl
and
/pages/mapViewer.ftl
(deprecated) templates in the portal theme. Content
that can be embedded in a portal's overall look, such as XML content, Markdown, and
some HTML
files, are rendered through this template. Other file types are served directly, without
a
template.If the document is a contextualized DITA topic - that is, a topic that is part of
a
map - it will be rendered using viewer.ftl
. All other file types will
be rendered using mapViewer.ftl
.
mapViewer.ftl
is deprecated. It is
strongly recommended that all viewer page logic be placed in
viewer.ftl
, and that mapViewer.ftl
simply be an
inclusion of viewer.ftl
. The Freemarker code can determine whether the
document is a contextualized topic using the hasContext
variable. The
mapViewer.ftl
template may be removed in a future release. Tip: In addition to the URL format returned by the viewerUrl
tag, you can use
metadata to construct the web URL to the viewer pages using query parameters. By accessing
/portalUrlPath/viewer?<md_name>=<md_value>
.
You can specify as many metadata parameters as you want. If more than one file matches
the
metadata query, the system will pick one at random.
So, for example, if you wanted to access a DITA topic with <resourceId
id="12345"/>
, you could use
/myportal/viewer?resourceid=12345
.
Variables
In addition to the common properties, this page has access to the following:
-
itemUrl
- The ContentLocator for the file being displayed. In the case of a DITA topic under a map, this will be the locator for the topic. In the case of a synthetic topic generated from a heading-only node in a DITA map, this will be the locator of the map. In the case of a chunked division in a non-DITA document, this will be the locator for the top-level document.
-
contextRefId
- Only present when viewing a piece of content in the context of another, such as a DITA topic or XML division chunk. In the case of a DITA topic within a map, this will be the ID of the topicref element referencing the topic. In the case of a chunked division, this will be the ID of the element defining the chunk.
-
virtual
- A boolean attribute describing whether the content being viewed is a virtual chunk, meaning that the content was generated as part of content processing, and was not based on a file in a project. This will be false for DITA maps and topics, and for top-level non-DITA documents. It will be true for chunked divisions in non-DITA documents and for topics generated from title-only <topicref> elements in DITA maps.
-
title
- The title of the document being shown. In the case of contextualized content such as a DITA topic in a map or a chunked division, this will be the title of the topic or chunk. In the case of monolithic XML documents or root-level DITA maps, this will be the title of the document itself. In the case of chunked divisions, this is the only way to get the title of the chunk, as all other document properties listed here will be associated with the top-level document.
-
itemData
- An ItemDataAccess data structure with access to the properties of
the document identified by
itemUrl
. -
properties
- A hash containing the file's properties. A convenience synonym for
itemData.propertyMap
. -
metadata
- A hash of all of the properties for the file being viewed, including project and context
metadata, if any.
Note: This is not a synonym for
itemData.properties
, which only contains only the metadata for the item itself. -
contexts
- An array of ContentRelationship data structures that represent the various contexts in which this file is present. Only those contexts visible to the portal (as determined by metadata rules) will be included.
-
hasContext
- A boolean value denoting whether the object being viewed is contextualized under a DITA map.
-
contextHarpUrl
- The ContentLocator of the context (usually a DITA map) for the content
being viewed. Optional, and will never be present in
mapViewer.ftl
. -
contextMetadata
- The hash of properties for the context (generally a DITA map) of the file being viewed.
Optional, and will never be present in
mapViewer.ftl
. -
debug
- The boolean value represented by the optional
debug
URL parameter. Can be used to trigger special debugging behavior. Always present, defaults tofalse
. -
ignoreCache
- The boolean value represented by the optional
ignoreCache
URL parameter, and can be used in conjunction with theignoreCache
attribute on the <@td.content> tag to bypass server-side caching mechanisms. Always present, defaults tofalse
. -
UUID
- A generated UUID that can be used to identify individual page views for analytics recording purposes.
Note: In most cases, the document being viewed is a file in a project. However, in some cases, these pages will be used to view content for which there is no corresponding document in a project. These include
- Synthetic DITA topics defined by a title-only <topicref> element.
- A chunked division from a non-DITA document.
In such cases, the metadata properties will be describing the top-level document/DITA map instead of the chunk being viewed. The one exception to this is title, which will always be the title of the chunk being viewed, regardless of whether or not it is virtual.
2.3.4: Login Page
/pages/login.ftl
template in the portal
theme. This page is used when a portal uses an LDAP authentication scheme, to gather
the
username
and password
for the user.This page is only required for portals secured using LDAP. If a user is not logged
in or their
session has recently expired and they attempt to visit any page within the Portal,
they will be
forwarded to this page if the Portal does not support anonymous browsing. Attempting
to access
the login page in a Portal without security will redirect to
portal-home.ftl
. In order to log in, a client must send a successful
POST
containing valid username
and password
parameters to the URL below. If their information matches the credentials stored in
the server
connected to by the LDAP configuration set up on the admin application then they will
be
forwarded to the portal. If the request was unsuccessful for any reason, the user
will be
redirected to login.ftl
and there will be an error message added to the
model.
The most basic login.ftl
should contain the following contents:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> </head> <body> <#if errorMessage??> ${errorMessage?html} </#if> <form action="login" method="post"> <label for="username">User Name</label> <input type="text" name="username" placeholder="User Name"> <label for="password">Password</label> <input type="password" name="password" placeholder="Password"> <button type="submit">Submit</button> </form> </body> </html>
Page Variables
In addition to the common variables, this page has access to the following:
-
errorMessage
- A string with the error message produced by the previous login attempt.
2.3.5: Assembly Viewer Pages
/pages/assemblyViewer.ftl
and
/pages/assemblyTopicViewer.ftl
templates in the portal theme and are used
to display assemblies and their contents.These pages can only be accessed in Portals that have security and that have the Assembly feature.
href
attribute.Page Variables
In addition to the common variables, these pages have access to the following:
-
assembly
- The Assembly object.
-
assemblyTopicRef
- The ID for the document in the assembly being viewed. Applies only for
assemblyTopicViewer.ftl
. -
ignoreCache
- The boolean value represented by the optional
ignoreCache
URL parameter, and can be used in conjunction with theignoreCache
attribute on the <@td.content> tag to bypass server-side caching mechanisms. Always present, defaults tofalse
. -
UUID
- A generated UUID that can be used to identify individual page views for analytics recording purposes.
2.3.6: Assembly Preview Template
/pages/assemblyPreview.ftl
template in
the portal theme. It is used to display topics in the Assembly Editor.It is not intended to be used anywhere else. This page can only be accessed in a Portal
that
has security and that has the Assembly feature. To test it, log in to a secured portal
and
create a new assembly. Do a search for any content and click it to view a preview.
The window
to the right shows the result of assemblyPreview.ftl
.
2.3.7: Error Pages
When an HTTP response in the 400 or 500 range is sent, the application will use
/pages/errors/{code}.ftl
, if it exists, and
/pages/error.ftl
if it does not. For example, when sending a 404
response, /pages/errors/404.ftl
will be used if it exists, and the
fallback /pages/error.ftl
. (The default portal theme's 404 and 500 error
pages simply <#include ../error.ftl/>
.)
Page Variables
Unlike most pages, error pages do not include the common variables. Error pages are limited to the following data:
-
portal
- A complex object containing the properties of the portal itself. See PortalIdentity.
-
request
- The
HttpServletRequest
object for the current request. -
errorCode
- An integer with the HTTP error code.
-
stackTrace
- If applicable, the Java exception stack trace that caused the error page.
2.3.8: Custom Pages
/pages/custom
folder contains
full-page templates that can be used to extend the functionality of a Portal by adding
new
pages.Custom pages can be linked to via <a href=<@harp.pageUrl
page="path/to/custom/page.ftl" />>Link Text</a>
. The path must be
relative to the /pages/custom/
directory.
Page Variables
In addition to the common variables, all custom pages have access to the following:
-
multiValueParams
- A hash of the URL request parameters, with all values for each parameter in a string array.
-
params
- A hash of the URL request parameters, holding a single value for each parameter. (Do not use for multi-value parameters.)
-
requestBody
- An HttpEntityContent object representing the HTTP request body (if any).
-
UUID
- A generated UUID that can be used to identify individual page views for analytics recording purposes.
Specifying Content Type via File Extension
By default, the Content-Type
header for custom pages is
text/html
. However, if the base name of the file has an extension with a
known file type, the system will automatically select the appropriate value for the
Content-Type
header. For example, the custom page template
/pages/custom/example.css.ftl
would be served with a
Content-Type
header of text/css
.
Here are some common file extensions and the resulting content type.
Content-Type
header will be
text/html
.
Extension
|
Content Type |
---|---|
*.css.ftl
|
text/css
|
*.js.ftl
|
application/javascript
|
*.xml.ftl
|
application/xml
|
*.dita.ftl and *.ditamap.ftl
|
application/dita+xml
|
*.txt.ftl
|
text/plain
|
*.csv.ftl
|
text/csv
|
HTTP Headers for Custom Pages
By default, Titania Delivery serves custom pages with a minimum of HTTP headers, and
a
Content-Type header determined as described above. You can customize
the HTTP headers sent for a given custom page by specifying those headers in metadata
with
keys beginning with _td.header.
. For example, specifying
_td.header.Content-Type=application/xml
on a page's metadata will cause
it to be served as an XML document.
Example Usage
A new custom page can be created with the following steps:
-
Create a file named
test.ftl
somewhere on your computer. Paste in the following code:<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8" /> <title>Hello, Titania!</title> </head> <body> <h1>Hello, Titania!</h1> <p>Welcome to the ${portal.name?html} portal</p> </body> </html>
- In your Portal Theme, select the
pages/custom/
directory - Click the Upload tab then click "Select a file..." to upload your
file or drag your file to the location specified. You should now be able to see, and
edit,
test.ftl
from within the browser. -
In
portal-home.ftl
, add the following in the first line after<div class="container">
<a href=<@harp.pageUrl page="test.ftl" />>Test Page</a>
- Navigate to the Portal homepage and click the link to be taken to the new custom page.
One common use of custom pages is to render non-DITA content such as Microsoft Office,
PDF,
or graphic files. Using the above steps, create a new custom template called
pngViewer.ftl
. Paste in the following code:
<#assign td=JspTaglibs['http://www.titaniasoftware.com/harp/taglib']> <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8" /> <title>${portal.displayName?html}</title> </head> <body> <#if params['projectKey']?? && params['itemKey']??> <@td.fileProperties var="itemData" projectKey="${params['projectKey']}" itemKey="${params['itemKey']}"/> </#if> <#if itemData??> <h1>${itemData.properties.specifiedDetails.title?html}</h1> <img src="<@td.viewerUrl item=itemData.item/>"/> <#else> <h1>No such file.</h1> <a href="javascript:history.back()">Go back.</a> </#if> </body> </html>
Then, set the contents of searchResults.ftl
to:
<#assign td=JspTaglibs['http://www.titaniasoftware.com/harp/taglib']> <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8" /> <title>${portal.displayName?html}</title> </head> <body> <h1> Search Results: ${term?html} </h1> <#if result.content?size == 0> <h2>No Results</h2> <#else> <ul> <#list result.content as group> <#assign filename> ${group.firstResult.filename?lower_case?trim} </#assign> <#assign extension> ${filename?substring(filename?last_index_of('.') + 1)} </#assign> <#assign url> <#if extension?trim == "png"> <@td.pageUrl page="graphic.ftl"> <@td.urlParam name="projectKey" value="${group.firstResult.projectKey}" /> <@td.urlParam name="itemKey" value="${group.firstResult.itemKey}" /> </@td.pageUrl> <#else> <@td.viewerUrl searchResult=group.firstResult /> </#if> </#assign> <li><a href="${url}">${group.firstResult.title?html}</a></li> </#list> </ul> </#if> </body> </html>
Ensure that there is at least one file available to the Portal that has a
.png
extension. Then, navigate to the URL path
/portalUrlPath/search?term=<filename>
where filename
is the name of one of the png files in your project. That
file should come up as a search result and clicking on the link should redirect to
the page
generated by pngViewer.ftl
. Any files returned by the search that do
not have a .png
extension will link to the regular viewer pages.
2.4: Storing Data
The userData object manages data associated with the currently authenticated portal user. If no user is currently logged in, stored data is associated with, and expires with, the current user session. The siteData object manages data associated with the portal itself, and is not associated with any particular user.
These objects are available on every page, and provide simple methods for storing
and
retrieving virtually any data structure in a persistent way. For example, you can
store a
value using put(key, value)
on one page, and on another page, retrieve the
value with get(key)
.
The siteData object provides additional methods for storing and searching arbitrary data structures in user-defined search indexes. It also provides methods to add, retrieve, and delete files in a project that is associated with the portal.
For a full description of how userData and
siteData
work, see UserDataStorage and SiteDataStorage. This functionality can also be leveraged using client-side
Javascript; see UserData and SiteData in Javascript.
Here is a more complex example:
<!-- The view will be of the 'current' state; next view will show new state. --> <#assign counter = userData.get('counter')!0/> ${userData.put('counter', counter + 1)} <p>Counter value: ${counter}</p> <!-- Store the 5 most recent counters --> <#assign counterList = userData.getList('counterList')![]/> <p>Counter list: ${counterList?join(', ')?html}</p> ${userData.push('counterList', counter, 5)} <!-- You can also store complex objects and arrays --> ${userData.put('object', {"a": 5, "b": "foo"})} ${userData.put('array', [1, 2, 3, 4, 5])} ${userData.push('complexData', {"I": "am", "a": {"nested": "structure"}});
The built-in theme's Recently Viewed Documents, Recent Searches, and Favorites features are implemented using userData.
2.5: Modifiable Lists and Maps
There are cases in a portal theme page or offline packager where it can be beneficial to build up temporary caches of information to be reused or aggregated elsewhere in the page/package. For instance, a package script may want to cache the URLs of various pages as they are built. Unfortunately, Freemarker hashes and sequences are ill-suited to this sort of task.
Sequences and hashes in Freemarker can be created programmatically.
<#assign arr = []/> <#assign hash = {}/>
They can also be updated.
<#assign arr = arr + [newElement]/> <#assign hash = hash + {key: value}/>
However, the Freemarker documentation discourages open-ended concatenation, stating:
and
In fact, in some unusual circumstances with huge collections, exceptions can be thrown when attempting to read from a concatenated hash or sequence.
Titania Delivery provides a set of Freemarker directives or functions that enable the creation and modification of mutable collections that do not suffer from the limitations of sequences and hashes.
newSet
and newList
The newSet
and newList
directives and functions can be
used to instantiate mutable lists of values. The only difference between the two collection
types are:
- Values in sets are unique; attempts to add the same value multiple times will not modify the list.
- Values in lists can be removed by their index via the
removeIndex
directive, which is not available on sets.
Instantiation
Instances of sets and lists are instantiated using the newSet
or
newList
objects. These objects can be invoked as either directives or
functions.
<#-- As a directive --> <@newSet var="mySet"/> <@newList var="myList"/> <#-- As a function --> <#assign mySet = newSet()/> <#assign myList = newList()/>
Once instantiated, the variable can be used as a prefix for the various directives and properties of the collection.
Parameters
-
var
orassign
- The global variable name to assign the new object. This parameter cannot be passed
to the functional
form.
<@newSet var="mySet"/> <@newSet assign="mySet"/> <#-- Identical to: --> <#assign mySet = newSet()/>
-
local
- The local variable name to assign the new object. The current processing context
must be within a
<#function>
or<#macro>
. This parameter cannot be passed to the functional form.<@newList local="myList"/> <#-- Identical to: --> <#local myList = newList()/>
-
from
- Optional. A Freemarker sequence that will be the starting values for the object.
Passed as the first argument to the functional
form.
<@newSet var="mySet" from=['a', 'b', 'c']/> <#assign mySet = newSet(['a', 'b', 'c'])/>
Directives
Sets provide sub-directives that can be used to modify the contents of the set.
-
add
- Used to add values to the set using the
value
parameter.<@mySet.add value="someValue"/>
-
clear
- Removes all values from the
collection.
<@myList.clear/>
-
removeValue
- Removes a value from the collection using the
value
parameter.<@mySet.removeValue value="someValue"/>
-
removeIndex
(lists only) - Removes a value from a list using the
index
parameter.Important: This directive is not present on sets, and attempts to invoke it on sets will cause errors.<@myList.removeIndex index=4/>
Properties
Sets and lists have the following properties.
-
size
- The number of elements in the collection.
${mySet.size}
-
asSequence
- The collection as a native Freemarker sequence. This is the primary mechanism by
which the data in the collection should be read.
Note: There is no meaningful processing or memory overhead when using this property. It is a reference to the underlying storage for the object, it is not a copy.
${myList.asSequence[0]} ${mySet.asSequence?join('<br>')} <#if myList.asSequence?seq_contains('someValue')> <#-- Conditional code here --> </#if>
-
json
- The set as a JSON
string.
<pre>${mySet.json?html}</pre>
newMap
The newMap
directive and function can be used to instantiate mutable hash
maps. Keys in mutable hashes must be strings.
Instantiation
<#-- As a directive --> <@newMap var="myMap"/> <#-- As a function --> <#assign myMap = newMap()/>
Parameters
-
var
orassign
- The global variable name to assign the new object. This parameter cannot be passed
to the functional
form.
<@newMap var="myMap"/> <@newMap assign="myMap"/>
-
local
- The local variable name to assign the new object. The current processing context
must be within a
<#function>
or<#macro>
. This parameter cannot be passed to the functional form.<@newMap local="myMap"/>
-
from
- Optional. A Freemarker hash that will be the starting entries for the map. Passed
as
the first argument to the functional
form.
<@newMap var="myMap" from={"index": 5, "title": "Some Title"}/> <#assign myMap = newMap({"index": 5, "title": "Some Title"})/>
Directives
Maps provide sub-directives that can be used to modify the contents of the map.
-
put
- Used to add entries to the map using the
key
andvalue
attributes. Thekey
must be a string. Thevalue
can be anything.<@myMap.put key="someKey" value="someValue"/>
-
clear
- Removes all entries from the map.
<@myMap.clear/>
-
remove
- Removes an entry from the set using the
key
parameter.<@myMap.remove key="someKey"/>
Properties
Maps have the following properties.
-
size
- The number of elements in the map.
${myMap.size}
-
keys
- The keys in the map as a Freemarker
sequence.
<#if myMap.keys?seq_contains('foo')> <#-- Conditional code here --> </#if>
-
asHash
- The map as a native Freemarker hash. This is the primary mechanism by which the data
in the map should be read.
Note: There is no significant processing or memory overhead when using this property. It is a reference to the underlying storage for the object, it is not a copy.
${myMap.asHash['someKey']!'No entry for someKey'} <#if myMap.asHash?keys?seq_contains('someKey')> <#-- Conditional code here --> </#if>
-
json
- The map as a JSON
string.
<pre>${myMap.json?html}</pre>
2.6: Portal Theme JavaScript Utility Library
harp-sdk.js
adds the HARPPortal
object to the global
scope. This object has the following interface:
interface HARPPortal { // Returns the Titania Delivery Version String getVersion(); // Returns the Titania Delivery build identifier String getBuildId(); // Returns the url to the given path String getPortalUrl(String path); /** * Returns the url to the Titania Delivery endpoint * that handles data transfer of assemblies, * comments, and helpful votes. Valid values are * 'assemblies', 'comments', and 'feedback'. */ String getPortalRpcUrl(String path); // AJAX interface to userData. UserDataStorage userData; // AJAX interface to siteData SiteDataStorage siteData; /** * Deletes the assembly indicated by assemblyKey * redirectTo is an optional parameter that takes a * path relative to the Portal root that the user will * be redirected to. */ void deleteAssembly(assemblyKey, redirectTo); }
These functions can be called anywhere JavaScript is legal on a page. For instance:
<script>alert(HARPPortal.getPortalUrl("search"));</script>
Add this library to any page by putting the following code snippet into the
<head>
of the page:
<#assign c=JspTaglibs['http://java.sun.com/jsp/jstl/core']/> <script type="text/javascript" src="<@c.url value="/resources/scripts/harp-sdk.js"/>"></script>
UserData and SiteData in Javascript
The HARPPortal object has userData and siteData properties that can be used to manage persistent data without reloading the whole page. The interfaces to these objects is the same as the DataStorage and SiteData Freemarker objects, with the exception that all methods return jQuery Promises instead of values.
HARPPortal.userData.put('foo', 'bar').then(function() { console.log('Stored foo'); return HARPPortal.userData.get('foo'); }).then(function(s) { console.log('Got foo: ' + s); return HARPPortal.userData.delete('foo'); }).then(function() { console.log('Deleted foo'); return HARPPortal.userData.push('testList', 1); }).then(function() { console.log('Pushed 1'); return HARPPortal.userData.push('testList', {foo: 'bar'}); }).then(function() { console.log('Pushed object.'); return HARPPortal.userData.getList('testList'); }).then(function(arr) { console.log('Got test list.'); console.log(arr); return HARPPortal.userData.delete('testList'); }).then(function() { console.log('testList deleted'); }).fail(function(e) { alert('Failed'); console.log(e); });
2.7: Portal Features
The following features are available to Portals:
- Anonymous Browsing (
anonymousAccess
) - Document-Level Comments (
docLevelComments
) - Element-Level Comments (
elLevelComments
) - Custom Assemblies (
customAssemblies
) - "Was This Helpful" Widgets (
helpfulVote
)
The status of these features can be checked for using the PortalIdentity
object's enabledFeatures
array or hasFeature
method. Before
exposing functionality to a Portal, the Portal Theme should always first check to
ensure that
it is enabled. For instance:
<#if portal.hasFeature('helpfulVote')> <#-- markup exposing functionality here --> </#if>
2.8: Translation Support
The Titania Default portal theme contains a pages/i18n
folder. This
folder contains utility templates to be imported into other pages for purposes of
translating
the User Interface into different languages. Specifically, the
pages/i18n/strings.ftl
template exposes a getString()
function that takes an English string as a parameter, and returns a translated string
in the
user's current language if one is available. In addition, the User Interface exposes
the
ability for the user to change the current interface language from among the available
languages.
To use a translated string in a page, simply load it through the getString()
function, e.g.
${getString('English String')?html}
Adding Strings
The language files in the pages/i18n
folder are named for specific
locale codes. These files contain simple Freemarker hashes of the English string mapped
to
the translation of that string.
<#assign strings = { "Learn about Titania": "En savoir plus sur Titania", "Learn about Titania Delivery": "En savoir plus sur Titania Delivery", "Powered by Titania Delivery": "Optimisé par Titania Delivery", "Links": "Liens" }/> <#-- lots more, but this is an example -->
To add strings for a particular language, add them to this file.
To add new languages
- Create the new translation file, named for the locale code of the language, and load
it
into the
pages/i18n
folder. - Update
strings.ftl
to import the new file, and add it to itsstringlib
collection.
Parameterized Strings
The getString()
function supports parameterized strings using
$1
. $2
, etc. for the parameters. For example, from the
French translation file:
"Page $1 of $2": "Page $1 sur $2"
When requesting this string, you pass an array of parameter values to the
getString()
function, e.g.
${getString('Page $1 of $2', ['1', '10'])?html} <#-- Translates to "Page 1 sur 10" -->
Assuming the translation includes the parameter tokens, they will be replaced with
the
specified values. You can escape dollar signs with a backslash (\), e.g.
getString("\$2 dollars")
.
Determining the User's Language
The strings.ftl
template uses the following algorithm to determine the
appropriate language for the user.
- If there is a
td.lang
browser cookie, its value is used. The default portal theme includes a menu in the header allowing the user to manipulate this cookie. - Otherwise, if the request specified a
Content-Language
header, that value is used. Most browsers send this header specifying the default language of the user's system. - Otherwise the language is assumed to be English ("en").
Debugging Translations
The getString()
function will look for a URL parameter specifying
debugLang=true
. If it is present, then the strings it returns will be
marked.
- If a string for the given input was found, the result will be wrapped in
{s}
and{/s}
. - If a string was not found, it will be wrapped in
{MISSING_STRING}
and{/MISSING_STRING}
.
This will allow you to easily identify strings that are correctly translated, strings
that
are missing from translation files, and strings that are not being rendered through
getString()
(because they will not be marked at all).
Translating Generated Text in XSLT Transforms
All of the default theme's XSLT stylesheets take a defaultLang
parameter
used to control the rendering language, and have a function similar to the Freemarker
getString()
function for loading translations. See Localizing Generated Text for full details.
2.9: Freemarker Extensions
2.9.1: Layout Templates
A layout template is a Freemarker template that includes <@t.region> declarations for portions of the template that can be populated by client templates. A region may comprise any portion of the document, from a word or phrase to a large, complex document fragment. Regions are uniquely identified by name. If the same region is mentioned more than once in a layout template, the same content will be rendered everywhere the region is included.
A region declaration may include default content. This is a shorthand for adding content
to
the region in a client template using <@t.content> directives.
Alternatively, the default content may also be used simply for documentation or instructions
for users. When the default content is never meant to be rendered, the attribute,
@renderDefault should be set to false
.
Note these features of the following layout template:
- The region named "title" is included twice, once in the <head> and once in the <body> of the document.
- The regions named "pageHeader", "pageFooter", and "body" have default content, but only the content of "pageFooter" will be rendered, due to the attribute setting for @renderDefault.
- As with all Freemarker templates, the html markup will be emitted as-is. The <@t.region> elements will be replaced with the content supplied by client templates.
- Although this simple example does not use any other Freemarker directives or variables, in practice a layout template may include any valid Freemarker constructs.
page_layout.ftl
<html> <head> <title><@t.region name="title"/></title> <@t.region name="head"/> </head> <body> <@t.region name="pageHeader" renderDefault=false> PAGE HEADER GOES HERE </@t.region> <hr> <h1><@t.region name="title"/></h1> <@t.region name="body" renderDefault=false> BODY CONTENT GOES HERE </@t.region> <hr> <@t.region name="pageFooter" renderDefault=true> Powered by layout templates! </@t.region> </body> </html>
Layout templates are invoked using the <@t.page> custom directive or the <@t.section> directive. Typically, a Freemarker template containing only a <@t.page> directive will be the root template for producing a portal page, as in the following example. Freemarker directives and other content may occur inside or outside the <@t.page> directive; however, within <@t.page>, any content not within a <@t.content>, <@t.prepend>, or <t.append> directive will be discarded.
A simplified description of <@t.page> processing is:
- The contents of the <@t.page> directive are processed.
- Freemarker directives and bare content are processed per normal Freemarker processing. However, any rendered output is discarded.
- <@t.content> and related directives are captured and stored for later rendering.
- The layout template is processed as a Freemarker template, replacing
<@t.region> elements with the content specified by the client
template.
Note: If the layout template is (or contains) <@t.page> or <@t.section> directives, the process is recursive. This is explained in more detail below under "Layering Layout Templates."
Directives
Layout templates are implemented using the following directives:
- <@t.region>
- This directive declares a region to be populated in a layout template by client
templates. Attributes:
- @name
- Required. The name of the region.
- @renderDefault
- Optional; default is
true
. Specifies whether the contents of the directive should be rendered if not replaced by a <@t.content> directive in the referencing page.
- <@t.region.*>
- As a shortcut, regions can be declared with their names as part of the directive name,
e.g.
<@t.region.body/>
instead of<@t.region name="body"/>
. - <@t.page>
- Surrounds content whose overall structure is defined by a layout template. Attributes:
- @layout
- Required. A relative path to the layout template to use for the contents defined within this page. (The @master attribute may also be used, though this is deprecated.)
- <@t.section>
- Surrounds content whose overall structure is defined by a layout template. Attributes:
- @layout
- Required. A relative path to the layout template to use for the contents defined within this fragment. (The @master attribute may also be used, though this is deprecated.)
- <@t.content>
- This directive is used within <@t.page> and
<@t.section> to define content to populate the regions declared
by the referenced layout template. If used outside the context of
<@t.page> or <@t.section>, causes an
error. Attributes:
- @region
- Required. The name of the region to be populated.
- @action
- Optional. The allowable values are
"replace"
,"prepend"
, or"append"
. The default is"replace"
. If there are multiple <@t.content> directives for the same region with an action of"replace"
, only the first will be executed. Multiple"append"
actions will be inserted in the order in which they are declared; multiple"prepend"
actions will be applied in reverse order. - defer
- Optional boolean attribute. If true, render this content when the matching <@t.region> directive is processed. If false, render the contents immediately when the <@t.content> directive is evaluated. This could affect what variables and macros are in scope when the contents of the directive are evaluated.
- <@t.prepend> and <@t.append>
- These directives are synonyms for <@t.content>, but with the
@region attribute set automatically. For
example:
<@t.append region="header"> More header! </@t.append>
The above is the same as:<@t.content region="header" action="append"> More header! </@t.content>
- <@t.content.*>, <@t.prepend.*>, and <@t.append.*>
- These directives are synonyms for their base versions, with the
@region attribute included in the directive name instead of as an
attribute. For
example:
<@t.append.header> More header! </@t.append.header> <@t.content.body> This is body content </@t.content.body>
This is synonymous with:<@t.content action="append" region="header"> More header! </@t.content> <@t.content region="body"> This is body content </@t.content>
Example Page with a Layout Template
page.ftl
Considering the following page, which contains some content to be rendered using the overall layout specified in another file:
<@t.page layout="relative/path/to/page_layout.ftl"> <@t.content region="title">Page Title</@t.content> <@t.content region="head"> <link rel="stylesheet" href="style.css"> </@t.content> <@t.content region="pageHeader"> Overriding page header. </@t.content> <#-- Uses the simplified, collapse model --> <@t.content.body> <h2>Page Contents</h2> <p>This is where the body goes.</p> </@t.content.body> <@t.content region="pageFooter" action="prepend"> Extra, PREPENDED footer for this page. </@t.content> <#-- Uses the simplified, collapse model --> <@t.append.pageFooter> Extra, APPENDED footer for this page. </@t.append.pageFooter> </@t.page>
Layouts for Page Sections
Layout templates may also be used for document fragments. Syntactically these fragment layout templates are the same as a page layout template, but will have a top-level element representing some type of HTML division element. Like page layout templates, they will contain <@t.region> directives to place and name regions of replaceable content.
section_layout.ftl
<div> <h1><@t.region name="section-title"/></h1> <@t.region name="section-contents"/> </div>
page_with_sections.ftl
<html> <head> <title>Sections with Common Layout</title> </head> <body> <@t.section layout="relative/path/to/section_layout.ftl"> <@t.content region="section-title"> <#-- generate first section title --> </@t.content> <@t.content region="section-contents"> <#-- generate first section contents --> </@t.content/> </@t.section> <@t.section layout="relative/path/to/section_layout.ftl"> <@t.content region="section-title"> <#-- generate 2nd section title --> </@t.content> <@t.content region="section-contents"> <#-- generate 2nd section contents --> </@t.content/> </@t.section> </body> </html>
Layering Layout Templates
A <@t.page> can reference a @layout which, itself, specifies a <@t.page> directive. Intermediate <@t.page> templates may declare their own <@t.region> directives. Such pages can reference any of the regions at any level of the referenced pages, including the regions in the ultimate layout template.
If a given region is replaced at multiple levels, the first replacing <@t.content> for that region from the outermost page will be used. Prepending and appending content will be applied from all levels, with the outermost page contents coming first for prepending and last for appending.
outerPage.ftl
<@t.page layout="innerPage.ftl"> <@t.content region="innerPageContent"> Content from outerPage. </@t.content> <@t.content region="layoutFooter"> Footer from outerPage. </@t.content> </@t.page>
innerPage.ftl
<@t.page layout="layout.ftl"> <@t.content region="layoutContent"> Content from innerPage. <@t.region name="innerPageContent"/> </@t.content> <@t.content region="layoutFooter"> This will be overwritten by outerPage.ftl </@t.content> </@t.page>
layout.ftl
<@t.region name="layoutContent"/> <@t.region name="layoutFooter"/>
Output
Content from innerPage. Content from outerPage. Footer from outerPage.
The layout template directives are available in version 4.1 and later.
2.9.2: Utility Functions
-
toJSON(object)
- Takes the given object and attempts to serialize it as a JSON string. Useful when building JSON API endpoints as part of your portal theme.
-
urldecode(str)
- Unescapes URL-encoded characters in the given string. Useful when loading data from browser cookies that were stored with URL encoding.
2.9.3: Server-Side Javascript in Freemarker Templates
Freemarker is robust enough to almost function as a fully-fledged programming language. However, it does have some limitations in this regard, and there are times when it would be useful for certain logic-intensive or computational processing.
The following directives will invoke Javascript while processing a template. These directives will be available to both online and packager templates.
- <@js>
-
This directive will allow users to execute javascript at the current location in the template. The javascript code can use
page.var(name)
to get the value of a Freemarker variable from the page, and usepage.assign(name, value)
and/orpage.local(name, value)
to mimic the behavior of the Freemarker <#assign> and <#local> directives. Calling theprint()
function will write the given value to the current location in the template. In addition, thetd.load()
function can be used to source an external script from somewhere in the theme.Functions and variables declared in one <@js> directive will be available to all <@js> directives and <@jsFunction> definitions declared later in the package. In Javascript terms, they share the same global scope.
For example, the following would calculate the base name of a document's filename, assign it to the Freemarker variable 'baseName', and write it to the output.
<@js> var doc = page.var('doc'); var name = doc.label; var ndx = name.lastIndexOf('.'); if (ndx !== -1) { name = name.substring(0, index); } page.assign('baseName', name); print(name); </@js>
The
js
andjsFunction
directives are implemented using the Nashorn script engine, which includes some javascript extensions for integration with Java. See the Nashorn Java Scripting Programmer's Guide. Our implementation does not permit instantiation of arbitrary java classes.One particular problem for script authors will be handling Freemarker sequences in javascript. The directive implementation handles conversion of top-level sequence variables into javascript as true javascript arrays. It also will convert javascript arrays to Freemarker sequences when assigned using
page.assign()
orpage.local()
functions. However, Freemarker sequences in subvariables (hash values) appear in javascript as generic list objects. As such, they do not provide all the usual javascript array functions, such assort()
,join()
, etc. In order to call these functions on a sequence obtained from a hash value, use the Nashorn extension function,Java.from()
to cast the sequence to a javascript array. The following example shows the different ways Freemarker sequences can be used in javascript.<@js> // 'docs' will be a true javascript array, automatically converted from // a Freemarker sequence by the page.var() function. var docs = page.var('documents'); // Sort the docs by title. doc.metadata.title is a sequence (List in javascript), // which can use the subscript operator, like an array. No need to cast to array. docs.sort(function(a,b) { return a.metadata.title[0] < b.metadata.title[0] ? -1 : a.metadata.title[0] > b.metadata.title[0] ? 1 : 0; }); for (var i in docs) { var doc = docs[i]; // doc.keywords is a sequence that comes into javascript as a List. // We can get the length of the sequence. if (doc.keywords.length > 0) { // But must cast to javascript array to get full array behavior. // WARNING: doc.keywords.join(' ') will cause script exception. var kwords = Java.from(doc.keywords).join(' '); // Now 'kwords' is a string containing space-separated values of doc.keywords } } </@js>
- <@jsFunction>
-
This is similar to the built-in Freemarker directive <#function>, except that the body of the function is implemented in Javascript instead of Freemarker. It has two attributes, @name (the name of the function) and, optionally, @parameters, the comma-separated list of parameter names.
Here is a function that computes the base name of a document passed in as a parameter.
<@jsFunction name="getBaseName" parameters="doc"> var name = doc.label; var ndx = name.lastIndexOf('.'); return ndx === -1 ? name : name.substring(0, ndx); </@jsFunction> <#-- Called using normal FreeMarker function call semantics. --> ${getBaseName(doc)?html}
For additional details, see the discussion of script engine implementation under <@js>, above.
2.9.4: Debugging Freemarker
Use <#attempt>
/<#recover>
Wrapping a section of your template in <#attempt>
allows you to handle
errors that occur yourself, instead of having the page fail to render entirely. The
error
will be encapsulated in the built-in .error
variable.
<#attempt> <#-- Risky code here --> <#recover> <#-- Error handling here; the error is in the .error variable --> <pre>${.error?html}</pre> </#attempt>
Set the ?ftldebug
URL parameter
When you add the ?ftldebug
parameter to a Titania Delivery portal URL,
HTML comments will be inserted around all template <#include>
directives. In addition, boundaries around content laid out using the special Layout Templates directives will also be marked. This can significanly help in
identifying where the Feemarker code that generated a part of the page is managed.
<!-- START TEMPLATE "/pages/viewer.ftl" --> <!-- START TEMPLATE "/pages/masters/mainLaout.ftl" --> <!DOCTYPE html> <html> <head> <!-- START REGION "htmlHead" from "/pages/viewer.ftl" --> <title>Topic Title</title> <!-- END REGION "htmlHead" from "/pages/viewer.ftl" --> </head> <body> <!-- START REGION "body" from "/pages/viewer.ftl" --> <!-- START TEMPLATE "/pages/masters/modules/layout.ftl" --> Navbar Content Here <!-- END TEMPLATE "/pages/masters/modules/layout.ftl" --> Contents of the page here. <!-- END REGION "body" from "/pages/viewer.ftl" --> </body> </html> <!-- END TEMPLATE "/pages/masters/mainLayout.ftl" --> <!-- END TEMPLATE "/pages/viewer.ftl" -->
2.10: Template Variable Types
Key Content Access Concepts
Files in Titania Delivery are referred to as Project Items, since they exist within projects. In order to identify content for display, you need the following identifying information:
- The Project Key.
- Either the Item Key (database identifier of the file) or the folder path within the project.
- For DITA topics in the context of a map, the item key of the referencing map, called the Context Key.
- If a DITA topic is referenced multiple times from the same map, you will also need the resolved ID of the reference to the topic, called the Reference Identifier or refId.
For everything other than DITA topics, the Project Key and Item Key are sufficient to identify the content, and can be encapsulated in an ItemIdentifier . The more robust form for identifying content is the ContentLocator object, which contains the project key, item key, and context identification.
Project Items have properties and metadata associated with them. This information is often accessed using ItemDataAccess objects provided to the page. You can also get one from any page using <@td.fileProperties> .
Key Search Concepts
Rather than return Project Items, the search engine returns special SearchResultDocument objects, containing the identifying properties of the project item, as well as some details and metadata. Most searches return these objects grouped using SearchResultGroup objects, which group contextualized topics by their Context Key (uncontextualized DITA topics and non-topic content will also be contained in groups, but those groups will have only one member). Finally, the search engine provides pagination of groups using SearchResultGroup objects.
Key Assembly Concepts
A custom Assembly object is its own data structure, identified by its key. Items within an assembly are identified by the assembly key and the generated reference ID for that entry.
2.10.1: Assembly
Represents an assembly. Assemblies come in two flavors:
- Created in the admin application, belonging to a project.
- Created by a Portal application, belonging to the portal.
<@td.assemblies>
tag.
Properties
2.10.2: ContentLocator
Properties
-
ItemIdentifier contextItemId
- The encapsulated Project and item keys of this document's context document, if applicable.
2.10.3: ContentRelationship
Properties
-
ItemIdentifier source
- The identifier for the source of the relationship.
-
ItemIdentifier target
- The identifier for the target of the relationship. May be null if the
referenced file does not exist, in which case the location of the missing
object is identified by
targetPathInProject
. -
RelationshipType type
- The relationship type. The possible values are
PARENT_CHILD
,LINK
, orGRAPHIC
.
2.10.4: Contextualization
Properties
-
ItemIdentifier childKey
- The identifier for the uncontextualized object.
-
boolean virtualTopic
- Whether the topic is a virtual topic without a single source representation, such as a virtual topic generated from a title-only topicref, or a chunked section of a monolithic source.
-
MetadataEntry[] metadataEntries
- The metadata entries set on this document. It does not contain the metadata inherited from parent maps or the containing project.
2.10.5: FacetCount
2.10.6: FacetField
Properties
-
FacetCount[] values
- The list of values for the facet, and their counts.
2.10.7: FragmentMetadata
2.10.8: HttpEntityContent
Represents an HTTP request or response entity.
The contents of the entity can be accessed using the body
property. If expecting JSON-encoded content, HTML, or XML content, a parsed
representation of the content can be accessed using the json
,
html
, or xml
properties. If there are errors parsing the
content, they are available in the parseError
property.
Introduced in version 4.2.
Properties
-
Document xml
- The
body
as a parsed XML DOM structure. If parsing fails, this property will benull
and any exceptions can be read from theparseError
property. The DOM structure can be interrogated using normal Freemarker XML handling; see the Freemarker documentation ( https://freemarker.apache.org/docs/xgui.html for details. -
Object json
- The
body
as a parsed JSON object. This can also be done manually in Freemarker usingresponse.body?eval
; this property is provided as a convenience. If the parsing of the JSON fails, this property will benull
and any exceptions can be read from theparseError
property. -
Document html
- The
body
as a DOM structure generated by the Jsoup Java library ( https://jsoup.org/ ). If the parsing of the body fails, this property will be null and any exceptions can be read from theparseError
property. -
String base64
- The raw entity encoded as base64 string. This can be used to handle binary data, for example to store a file that includes binary data.
2.10.9: HTTPResponse
Represents the data returned by the <td.httpRequest> tag.
The contents of the response body can be accessed using the body
property. If expecting JSON-encoded content, HTML, or XML content, a parsed
representation of the content can be accessed using the json
,
html
, or xml
properties. If there are errors parsing the
content, they are available in the parseError
property. For example:
<@td.httpRequest url="https://example.com/data.json" var="response"/> <#if response.status == 200> <#if response.contentType?contains('/json')> <#assign responseStruct = response.json!''/> <#elseif response.contentType?contains('/html')> <#assign responseStruct = response.html!''/> <#elseif response.contentType?contains('/xml')> <#assign responseStruct = response.xml!''/> </#if> <#if response.parseError??> <b>ERROR: ${response.parseError.message?html}</b> <pre>${response.body?html}</pre> </#if> </#if>
All headers are available in the headers
property. The keys for the
header names are represented in all lower-case, as well as in whatever case
was presented in the actual response.
Introduced in version 4.2.
Properties
-
Document xml
- The
body
as a parsed XML DOM structure. If parsing fails, this property will benull
and any exceptions can be read from theparseError
property. The DOM structure can be interrogated using normal Freemarker XML handling; see the Freemarker documentation ( https://freemarker.apache.org/docs/xgui.html for details. -
Object json
- The
body
as a parsed JSON object. This can also be done manually in Freemarker usingresponse.body?eval
; this property is provided as a convenience. If the parsing of the JSON fails, this property will benull
and any exceptions can be read from theparseError
property. -
Document html
- The
body
as a DOM structure generated by the Jsoup Java library ( https://jsoup.org/ ). If the parsing of the body fails, this property will be null and any exceptions can be read from theparseError
property. -
String base64
- The raw entity encoded as base64 string. This can be used to handle binary data, for example to store a file that includes binary data.
Methods
2.10.10: ItemDataAccess
Properties
-
ItemIdentifier itemIdentifier
- The ItemIdentifier for the item.
-
ItemProperties properties
- Properties and metadata for the item.
-
ProjectInfo projectInfo
- Information about the project containing the item.
-
ContentRelationship[] outgoingRelationships
- The outgoing relationships, such as links and graphics, from this object.
-
ContentRelationship[] incomingRelationships
- The incoming relationships, such as links and graphics, to this object.
-
ProjectMetadata projectMetadata
- The metadata collection on the project containing the item.
2.10.11: ItemIdentifier
2.10.12: ItemProperties
Properties
-
ItemIdentifier item
- The encapsulated Project key and Item key for this item.
-
SpecifiedItemDetails specifiedDetails
- The details that can be on this item in the admin application, such as name and description. Only available if this is a non-parsable binary file.
-
Map embeddedMetadata
- The embedded metadata from the file. This will be present for PDF, Microsoft Office, several graphics formats, and a number of other file types.
-
String effectiveUrlPath
- The URL path by which this document can be directly addressed as a standalone document.
-
Map propertyMap
-
A hash of properties set on this document. Keys common to all files are:
-
key
- The key of the document -
name
- The name of the document -
projectKey
- The key of the Project containing this document -
size
- The size of the document, in bytes -
contentType
- The MIME Type of the document -
path
- The path to this document within the Project -
createDate
- The date the document was created in Titania Delivery -
lastModified
- The date the document was last modified in Titania Delivery
Keys set on image files only are:
-
img_width
- The width of the image, in pixels -
img_height
- The height of the image, in pixels
Keys set on XML files only are:
-
xml_isWellFormed
-
xml_hasDTD
-
xml_hasSchema
-
xml_hasDoctype
-
xml_doctypeExists
-
xml_isValid
-
xml_elementCount
-
xml_elementIds
-
xml_primarySchema
-
xml_publicId
-
xml_systemId
-
xml_schemas
-
xml_rootElement
-
xml_rootNamespace
-
xml_doctypeFile
-
xml_doctypeProject
-
xml_doctypeName
-
xml_title
-
dita_navtitle
-
xml_validationError
-
xml_isDita
-
dita_isTopic
-
dita_isMap
-
dita_isDitabase
-
dita_domains
-
-
MetadataEntry[] metadataEntries
- The metadata entries set on this document. It does not contain the metadata inherited from parent maps or the containing project.
-
FragmentMetadata[] allFragmentMetadata
- Get all fragment metadata as a list.
2.10.13: ItemRepresentationType
2.10.14: MetadataEntry
2.10.15: MetadataFilter
metadataFilters
array in PortalIdentity
.
Properties
2.10.16: OfflinePackage
Introduced in version 4.1.
Properties
-
OfflinePackageDocumentInfo[] documents
- The documents that were included in the package.
-
boolean signContents
- Whether to generate SHA-512/RSA signatures for each file in the package,
as well as the package itself. The default is
false
. Introduced in version 4.2. -
String signaturePathPrefix
- If signing package contents, this specifies the path prefix to apply for signature files. this can be used to place signature files in their own folder in the archive. The default is no prefix. Introduced in version 4.2.
-
String signaturePathSuffix
- If signing package contents, this specifies the suffix to add to signature files. The default is ".signature". Introduced in version 4.2.
-
String signatureAlgorithm
- The signing algorithm to use for both the package itself and individual
files within the package, if signContents is enabled. The value must
match those available in Java; see
https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Signature
.
The default is
"SHA512withRSA"
. Introduced in version 4.2. -
String statusMessage
- The current status message for the package. The package script can update this message as it builds the package in real-time, so this message should reflect the current state of the packaging process.
-
String signature
- The hexadecimal-encoded SHA-512/RSA checksum for the zip itself. Introduced in version 4.2.
2.10.17: OfflinePackageDocumentInfo
Introduced in version 4.1.
Properties
-
boolean rootDoc
- Whether or not this document was explicitly requested for inclusion in the package, and not included by virtue of being part of another explicit document. For example, when packaging a specific DITA map, the map itself will be marked as explicitly requested, while its topics will not (assuming the package requested the inclusion of contextualized children).
2.10.18: PortalIdentity
$ portal
and
includes data about the Portal itself.
Properties
-
MetadataFilter[] metadataFilters
- The Metadata Filters set on this Portal.
-
PortalSearchFacet[] searchFacets
- The search facets set on this Portal.
-
String[] enabledFeatures
- The features enabled for this portal. Possible values are:
- anonymousAccess
- docLevelComments
- elLevelComments
- customAssemblies
- helpfulVote
-
PortalRobotsTxtBehavior robotsTxtBehavior
- The behavior of this portal in robots.txt. One of NONE, DISALLOW, or ALLOW.
Methods
2.10.19: PortalSearchFacet
searchFacets
array in
PortalIdentity
, which is available on every page in the Portal.
Properties
2.10.20: PortalUser
This object is only available to the Portal if the Portal has security (
hasSecurity
) enabled and the current user is logged in (
isAuthenticated
). If those two conditions fail, this object will be
null and any attempt to reference it will result in a Freemarker error. This
can be using the following code:
<#if hasSecurity && isAuthenticated> <#-- Can now safely reference ${user} --> </#if>
or:
<#if user??> <#-- Can now safely reference ${user} --> </#if>
Properties
-
String id
- A persistent, obfuscated character string based on login name, which identifies the current user.
-
String userName
- The username of the user, as specified by the server pointed to in this Portal's security configuration.
-
Map properties
- The user properties pulled from the authentication service. For SAML-secured and OpenID-secured portals, this will contain whatever attributes were included in the authentication response message sent by the Identity Provider. For LDAP-secured portals, this will contain the properties listed in the LDAP connection configuration. NOTE: This collection allows for multi-valued properties, so values are arrays, not single values. Properties with single values will be lists of size 1.
Methods
2.10.21: ProjectInfo
2.10.22: ProjectItem
2.10.23: ProjectMetadata
2.10.24: SearchResultDocument
results
array of SearchResultGroup
and of the array
returned by the <@td.search>
tag.
Properties
-
String itemKey
- This document's item Key, unique to the project. In some cases, may be of the form key:elementId for chunked content.
-
String contextKey
- The key of this document's context document, or
xxnullxx
if it is a stand-alone document. -
String contextRefId
- If this document is present in its parent context more than once, the
contextRefId
identifies which version the current document represents. -
boolean contextualized
-
true
if this document is present in a parent context document. Equal tocontextKey != xxnullxx
. -
String highlight
- If this document was returned as part of a search query, this field will contain the text contents surrounding the most-relevant "hit" in the document.
-
Map metadata
- A hash representing the metadata on this document. The keys are metadata names as assigned in the TD admin application or present in the source document. The value is an array of strings representing the values of that metadata. If a key is present it is guaranteed that there will be at least one element in the values array.
-
boolean virtual
- Describes whether this search result represents a physical file in a Titania Delivery project, or a virtual, generated document. Examples of virtual documents include topics generated for DITA <topicref> elements that specify a title but no @href or @keyref, or a chunked section of a non-DITA document.
2.10.25: SearchResultGroup
This object is the data type of the content
array of groups. It
represents a "group" of search results.
Search results are generally grouped by their DITA map context. That is, a DITA topic used in multiple DITA map contexts will have its matching search results grouped together. No other documents are grouped in this way.
nContexts
will always be >= 1 and equal to results?size
.
firstResult
will be the same SearchResultDocument
as
results[0]
.
Properties
-
SearchResultDocument firstResult
- convenience variable for
results[0]
. -
String groupingValue
- The value of the grouping field specified by the query for all of the documents in this group. For example, grouped search results are grouped by the "itemKey" property by default, so this value will be the itemKey of all of the results in this group. When grouping by another field, this will be the value for that field on all of the documents in this group. Introduced in version 4.2.1.
-
SearchResultDocument[] results
- The search results grouped by topic. If the topic was returned by a
search result, then each context in which it exists will be present in
the array. If the document is stand-alone, (that is, it is not referenced
by any parent document) then there will be only one entry in the array.
results?size
will always be equal tonContexts
.
2.10.26: SearchResultsPage
<@td.search>
tag, the paged items will be
SearchResultDocument
objects. When grouped, e.g. on the
searchResults.ftl
or from the <@td.groupSearch>
tag,
the contents will be SearchResultGroup
objects.
Properties
-
FacetField[] facetFields
- The list of facet counts for the search.
-
int numberOfElements
- The number of elements on the current page. Will be less than or equal to
size
. -
long totalElements
- The total number of elements (groups or documents) returnable by the current search.
-
String groupedBy
- The property by which the results are grouped when applicable, such as
the default search page or the results of the
td.groupSearch
directive. The default grouping field is "itemKey", meaning that DITA topics with multiple DITA map contexts will be grouped together. This value will be null for ungrouped searches. Introduced in version 4.2.1. -
Object[] startNextAfter
- Markers that can be used in a subsequent request to get the next page of results. Avoids performance and/or hard limits on the full size of all pages in the search engine.
-
T[] content
- The contents of the current page. This will either be
SearchResultGroup
or SearchResultDocument
objects,
depending on the way the query was performed.
- When the search is performed using the standard portal search page,
and rendered with
searchResults.ftl
, this will be a list of SearchResultGroup . - When performed using the
<@td.groupSearch>
tag, the results will also be of type SearchResultGroup . - When performed using
<@td.search>
, the results will be lists of SearchResultDocument .
- When the search is performed using the standard portal search page,
and rendered with
2.10.27: SiteDataStorage
An extension of UserDataStorage that is shared by all users of a portal, including anonymous users. This object exposes a number of special methods for storing data and documents in a searchable way.
Portals have an associated content project that can store documents and metadata generated by the portal. Also, each portal can have one or more searchable indexes containing arbitrary data. (Additional portal data storage capabilities for nonindexed values, counters, and lists are described under "DataStorage".)
When a portal is created, a project is automatically created and associated
with the portal as the portal content project. This project may contain
portal-generated content, and functions like any other content project. The
siteData
object provides methods for accessing portal
content items.
Indexed data can be stored and searched under user-defined index names. Each
index should hold similarly structured records. Methods for storing and
retrieving indexed data are provided in Freemarker and javascript using the
siteData
object. The administration interface also provides
access to view and download portal indexed data. IMPORTANT: The total
number of user-defined indices on the platform cannot exceed 100 at any time
(across all portals). Theme developers and platform administrators should
ensure that no more than 100 indices exist at any time.
Introduced in version 4.2.
Methods
-
Iterable searchIndexed( String index, String query, int [] paging)
- Searches the given index using the given search. Since each index can have its own record type, all indexed searches are ordered by the built-in Elasticsearch field, "_doc".
-
int deleteIndexed( String index, String query)
- Deletes records from the given index that match the given query.
-
int deleteIndexed( String index, String query, boolean waitRefresh)
-
Deletes records from the given index that match the given query. Passing
false
for thewaitRefresh
method will cause the method to return before the deletion has been fully processed. The default istrue
-
void putIndexed( String index, Object value)
- Stores a data structure in such a way that its properties can be queried using normal search syntax. The index functions as a namespace for the stored data. As a best practice, radically different data structures should be stored in different indexes.
-
boolean putIndexed( String index, Object value, boolean waitRefresh)
-
Stores a data structure in such a way that its properties can be queried
using normal search syntax. The index functions as a namespace for the
stored data. As a best practice, radically different data structures
should be stored in different indexes. Passing
false
for thewaitRefresh
method will cause the method to return before the insertion has been fully processed. The default istrue
-
void putFile( String location, String mimeType, CharSequence contents, Map metadata)
- Creates or updates a file in the portal's project. If the file already exists, its contents will be overwritten and its metadata replaced with the given hash.
-
String getFile( String location, String representation)
- Retrieve the contents of the file at the given path as a string.
-
String getFileDownloadURL( String location, String representation)
- Gets an HTTP URL at which the given file can be downloaded directly, optional with a processed representation.
-
String getFileUploadURL( String location, boolean folderMode, String itemName)
- Get a URL to add or replace a file via POST. Any existing file at the location will be overwritten.
-
boolean setFileMetadata( String location, Map metadata)
-
Sets the metadata on the given file. The existing non-intrinsic metadata
entries for the file will be replaced with those supplied. Use
updateFileMetadata(String,Map)
for adding additional metadata to a file. -
boolean updateFileMetadata( String location, Map metadata)
- Updates the metadata on the given file. The existing non-intrinsic metadata entries for the file will be updated and merged with those supplied.
-
String getProcessingPhase( String location)
- Gets the current processing phase of the item at the specified location.
-
ProjectItem[] getProjectRoots()
- List the portal project root contents.
-
ProjectItem[] getFolderContents( String location)
- List the specified folder contents.
-
void put( String dataKey, Object data)
- Stores data with a key. If the data is a string, it is stored as-is. Otherwise, it is converted to JSON and then stored.
-
Object get( String dataKey)
- Retrieves the data with the given key. Objects are encoded as JSON for storage, so the resulting object will be whatever type was stored, unless it's an object, in which case it will be represented as a map hierarchy.
-
void push( String listKey, Object value, int cap)
- Pushes a new value onto the list with the given key.
-
void pushUnique( String listKey, Object value, int cap)
- Pushes a new value onto the list with the given key. If it already exists in the list, it is removed and moved to the top.
-
boolean existsInList( String listKey, Object value)
- Determines whether the given value exists in the list with the given key.
-
void removeFromList( String listKey, Object value)
- Removes the given value from the list with the given key.
-
void incrementCounter( String key, long by)
- Increments the counter with the given key by the given amount (which may be negative). If no such counter exists, it will be created and set to the given increment value.
2.10.28: SpecifiedItemDetails
Properties
2.10.29: UserDataStorage
Portals can store data on the server for later retrieval. If the user is authenticated, the stored data is persisted between sessions. Otherwise, it expires when the client session expires.
There are three types of nonindexed persistent data: values, counters, and lists. Each is associated with a key. A key may have all three types of values.
Values
Values are stored via put(String, Object)
and retrieved via
get(String)
. Values can be anything that can be serialized
as JSON, including strings, numbers, booleans, lists, and data structures.
Data values are serialized as JSON when stored in the database, and
de-serialized when retrieved. If a value is a complex non-map object when it
is stored, it will be retrieved as a map.
Lists
Lists are essentially managed arrays that can be added to or removed from
without needing to retrieve the full data structure. You create/add to lists
via push(String, Object, int)
or pushUnique(String,
Object, int)
. The full list can be retrieved via
getList(String)
. Elements can be removed via
removeFromList(String, Object)
. You can check whether a
value exists in a list via existsInList(key)
. Like values,
list entries can be anything that can be serialized as JSON.
Counters
Counters are whole number values that can be easily incremented and
decremented with the atomic operation incrementCounter(String,
long)
. They can also be retrieved and stored via
getCounter()
and setCounter()
.
Important: The three values are treated independently. If you set a
value via setCounter()
, it must be retrieved by
getCounter()
; it will not be retrieved by
get()
. Similarly, lists stored with put()
cannot be modified via push()
. However, if a given key has
more than one type of value - a list and a counter, for instance - calling
delete()
on that key will delete all the associated data.
Categories
A category is implicitly defined by keys beginning with a certain prefix and a period. For example, deleteCategory('foo') would delete any entry with a key beginning with 'foo.' ('foo.a', 'foo.b', etc.). It would not delete 'foo'. There are a number of methods that allow the interaction with whole groups of entries by their category. This allows the development of features that involve an interaction of multiple keys such that they can be deleted.
Introduced in version 4.0.
Methods
-
void put( String dataKey, Object data)
- Stores data with a key. If the data is a string, it is stored as-is. Otherwise, it is converted to JSON and then stored.
-
Object get( String dataKey)
- Retrieves the data with the given key. Objects are encoded as JSON for storage, so the resulting object will be whatever type was stored, unless it's an object, in which case it will be represented as a map hierarchy.
-
void push( String listKey, Object value, int cap)
- Pushes a new value onto the list with the given key.
-
void pushUnique( String listKey, Object value, int cap)
- Pushes a new value onto the list with the given key. If it already exists in the list, it is removed and moved to the top.
-
boolean existsInList( String listKey, Object value)
- Determines whether the given value exists in the list with the given key.
-
void removeFromList( String listKey, Object value)
- Removes the given value from the list with the given key.
-
void incrementCounter( String key, long by)
- Increments the counter with the given key by the given amount (which may be negative). If no such counter exists, it will be created and set to the given increment value.
2.11: The Titania Tag Library
The tag library can be included on any page via <#assign
td=JspTaglibs['http://www.titaniasoftware.com/harp/taglib']/>
. The
td
identifier can be replaced with any valid name. This directive must be
included on every top-level template file that uses the tag library, and is not supplied
to
pages by the infrastructure. Once included on the page, custom tags can be accessed
with
<@td.tagName atts... />
.
2.11.1: <@td.assemblies>
This tag contains the following attributes:
-
limit
- The maximum number of results per page. Must be a positive
integer n where 0 < n <= 2147483647. This does not limit the total
number of search results, which may be limited by other settings.
- Required: false
- Type: int
- Default: 10
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
sortBy
- The property or properties to sort by,
separated by whitespace or comma.
- Required: false
- Type: String
- Default: none
-
sortDirection
- A list of sort directions ('ASC' or 'DESC'),
corresponding in order to the list of 'sortBy' fields.
If the list is empty or shorter than the 'sortBy' list,
the default of 'ASC' will be used for the missing directions.
- Required: false
- Type: String
- Default: ASC
-
startAfter
- Alternative pagination mode. The startNextAfter token from a
previous page.
- Required: false
- Type: Object
- Default: null
-
startPage
- The page number to return. Must be an integer 0 <= n
<= 10000. Note that ithe preferred pagination method is to use
the startAfter attribute.
- Required: false
- Type: int
- Default: 0
-
var
- The name of the variable used to access the result.
- Required: true
- Type: String
- Default: none
Example Usage:
It is advised to check for the presence of the Assemblies Feature and ensure that a PortalUser is logged in before using this tag. Failing to do so will result in errors.
<#if portal.enabledFeatures?seq_contains['customAssemblies'] && user??> <@td.assemblies var="assemblies" /> . . . <#if assemblies?size > 0> <#list assemblies as assembly> <a href=<@td.assemblyViewerUrl assembly=assembly/>${assembly.name?html}</a> </#list> </#if> </#if>
2.11.2: <@td.assemblyEditorUrl>
This tag contains the following attributes:
-
assembly
- The Assembly object to open in the editor. If not
specified, the
editor will be opened with a new empty
assembly.
- Required: false
- Type: Assembly
- Default: none
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Example Usage:
It is advised to check for the presence of the Assemblies Feature and ensure that a PortalUser is logged in before using this tag. Failing to do so will result in errors.
<#if portal.enabledFeatures?seq_contains['customAssemblies'] && user??> <@td.assemblies var="assemblies" /> . . . <#if assemblies?size > 0> <#list assemblies as assembly> <a href=<@td.assemblyEditorUrl assembly=assembly target="_blank"/>Edit ${assembly.name?html}</a> </#list> </#if> </#if>
2.11.3: <@td.assemblyViewerUrl>
This tag contains the following attributes:
-
assembly
- The Assembly object.
- Required: true
- Type: Assembly
- Default: none
-
refId
- The ID of the node in the Assembly to display.
If
omitted,
the URL of the Assembly itself is returned.
- Required: false
- Type: String
- Default: The root node of the Assembly
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Example Usage:
It is advised to check for the presence of the Assemblies Feature and ensure that a PortalUser is logged in before using this tag. Failing to do so will result in errors.
<#if portal.enabledFeatures?seq_contains['customAssemblies'] && user??> <@td.assemblies var="assemblies" /> . . . <#if assemblies?size > 0> <#list assemblies as assembly> <a href=<@td.assemblyViewerUrl assembly=assembly/>${assembly.name?html}</a> </#list> </#if> </#if>
2.11.4: <@td.content>
This tag contains the following attributes:
-
addPageviewImage
- Whether to automatically insert an HTML <img> tag
after the rendered
content that will request a 1x1-pixel,
invisible image causing the server to record
a view of this
content. This will force a pageview to be recorded, even if the
rendered
page is served from a browser or other cache.
- Required: false
- Type: Boolean
- Default: false
- Since: 4.2
-
assembly
- An Assembly whose content to render. One of
this,
'url',
or 'searchTerm' must be specified, and they
are evaluated
in that
order.
- Required: false
- Type: Assembly
- Default: None
-
assemblyTopicRef
- If an assembly is specified, this is the ID of
the
topic within
that assembly to render. If an assembly
is specified
without this
attribute,
the assembly map
itself is rendered. this
is specified without an
assembly,
it is ignored.
- Required: false
- Type: String
- Default: None
-
contextKey
- The context key. Overridden by contextUrl
and/or
contextUrlString and/or the context key specified
in
url/urlString, in
that order.
- Required: false
- Type: String
- Default: none
-
contextUrl
- The ContentLocator of the context from which to load the
data. Used to
configure hyperlinks and image references
in the
resulting content.
- Required: false
- Type: ContentLocator
- Default: none
-
contextUrlString
- The ContentLocator of the context from which to load the
data. Used to
configure hyperlinks and image references
in the
resulting content.
- Required: false
- Type: String
- Default: none
-
expandReferences
- Whether to expand references to child documents. This
is used to render all topics in a DITA Map-based publication on
a
single page.
- Required: false
- Type: boolean
- Default: false
-
ignoreCache
- Whether to go to the database, ignoring caches.
Note
that
this will flush the requested data from the
cache and
re-cache the newly
loaded version. Default is
false.
- Required: false
- Type: boolean
- Default: none
-
itemKey
- The item key. Overridden by url and/or
urlString.
- Required: false
- Type: String
- Default: none
-
linkContext
- This attribute is deprecated and can be ignored.
- Required: false
- Type: Boolean
- Default: none
-
pipeline
- Post-transform content processing can be accomplished
with
built-in content processing pipelines. Currently the only
supported pipeline
is
"filterchain:/harp/portal/markFilteredTopics.xml", which can
mark or remove
links to topics not available in the portal, and
requires
pipelineParameters
"portal" (PortalIdentity),
"contextKey" (ItemIdentifier), and
"removeFilteredEntries",
a
boolean controlling whether to remove or simply mark links to
filtered content.
- Required: false
- Type: String
- Default: None
-
projectKey
- The Project key. Overridden by url and/or
urlString.
- Required: false
- Type: String
- Default: none
-
recordPageview
- Whether to record a pageview for the given content in
the reporting system. This should only be true when viewing
content
in a custom portal page. The built-in content viewing
pages all
record the pageview before the response is rendered.
But when
rendering content on a custom portal page, this should
be specified
as true to ensure that the content view is recorded.
- Required: false
- Type: boolean
- Default: false
-
searchTerm
- A search term whose first result will be the
SearchResultDocument rendered by this tag.
Overrides url and
contextUrl attributes. Required if url attribute not
provided.
Can be combined with metadata specified in
metadataFilterTags.
- Required: false
- Type: String
- Default: none
-
timeout
- The amount of time, in ms, after which the transform
may be
cancelled. The default value is generally 60000 (60
seconds), though this
can vary depending on the application's
configuration. Set to 0 to
disable
timeouts, but do this with
care; infinitely-running transforms can severely
degrade
application performance site-wide.
- Required: false
- Type: long
- Default: 60000
- Since: 4.2
-
url
- The ContentLocator object describing the content to
retrieve. Required if searchTerm attribute is not
provided.
- Required: false
- Type: ContentLocator
- Default: none
-
urlString
- The ContentLocator object describing the content to
retrieve. Required if searchTerm attribute is not
provided.
- Required: false
- Type: String
- Default: none
-
xsl
- Relative path to an XSLT file, relative to the
WEB-INF directory of the web application, to apply to
the
content. Parameters to the XSLT can be passed using
nested
xslParam
tags.
- Required: false
- Type: String
- Default: none
Rendering a DITA Map as One Page
The expandReferences
attribute can be used when referencing DITA maps to
insert an XML document containing all of the topics in the publication, instead of
the
flattened DITA map markup. The XML structure for this document is similar, but not
quite the
same, as the structure used by the DITA Open Toolkit when rendering PDF output.
- The root element is the map's root element.
- The first child of the root element is
<opentopic:map xmlns:opentopic="http://www.idiominc.com/opentopic">
.- This structure contains the original, unexpanded map structure, including the map title element.
- On each topicref, the ID of the corresponding topic element is in the
puckdita:cxt-topicId
attribute (xmlns:puckdita="http://www.titaniasoftware.com/namespace/puck-saxfilter-dita"
). - The metadata, including navtitle, for each topicref will have been resolved.
- After the
<opentopic:map>
element, all of the topics referenced by the map flow, nested as specified by the map. Navtitle-only topicrefs are rendered as topics with the appropriate title. Theid
attribute maps to thepuckdita:cxt-topicId
attribute for its topicref in the<opentopic:map>
section. - The
@href
attribute on allscope="local" format="dita"
links and cross-references will have already been converted into IDREF-style links (e.g.href="#targetId"
) that will resolve in the flattened document. - Related links, including those generated from reltables and the map structure, will
be
included in the topics. To avoid displaying them they must be excluded by the stylesheet.
You can differentiate authored links from generated links using the
puckdita:linkSource
attribute. If the attribute is not present, then the link was manually authored. Otherwise:-
"structure"
- The link is derived from the map structure.
-
"reltable"
- The link was generated from a reltable.
-
Viewing an XML Document as Transformed HTML
<@td.content url=itemUrl xsl="/topic/topic.xsl"> <@td.xslParam name="GENERATE-TASK-LABELS" value=true/> <@td.xslParam name="TASK-LABEL-TAG" value="h4"/> </@td.content>
This tag will render the content identified by the
ContentLocator
object
itemUrl
using the XSLT
transformation in the portal theme at
/xsl/topic/topic.xsl
. It will
pass two parameters to the XSLT,
GENERATE-TASK-LABELS=true
and
TASK-LABEL-TAG=h4
.
Viewing a Contextualized Topic
<@td.content url=itemUrl contextUrl=contextUrl xsl="/topic/topic.xsl"/>
This loads the topic identified by the
ContentLocator
itemUrl
, as referenced by the DITA map identified by
contextUrl
.
Rendering Content Based on Search
<@td.content searchTerm="serialno:12345" xsl="/topic/topic.xsl"/>
This will render the first document matching the given search.
Rendering an Assembly
<@td.content assembly=assemblyObj xsl="/map/map.xsl"/>
This will render the Assembly object give by
assemblyObj
.
Rendering an Assembly Entry
<@td.content assembly=assemblyObj assemblyTopicRef=refId xsl="/topic/topic.xsl"/>
This will render a topic within Assembly object give by
assemblyObj
and refId
, the identifier of the topic
within the assembly.
Rendering All Topics in a DITA Map
<@td.content url="itemUrl" xsl="/map/monolith.xsl" expandReferences=true/>
This will use a version of the specified DITA map (or assembly) that is similar to, but not the same as, the monolithic XML structure used by the DITA Open Toolkit for PDFs.
Monolithic DITA Map XML Structure
Here is an example of what a DITA map rendered with expandReferences=true
might look like.
<map xmlns:puckdita="http://www.titaniasoftware.com/namespace/puck-saxfilter-dita" xmlns:opentopic="http://www.idiominc.com/opentopic"> <opentopic:map> <title>Map Title</title> <topicref puckdita:cxt-topicId="topic1"> <topicmeta> <navtitle>Topic One</navtitle> </topicmeta> <topicref puckdita:cxt-topicId="topic2"> <topicmeta> <navtitle>Topic Two</navtitle> </topicmeta> </topicref> </topicref> <topicref puckdita:cxt-topicId="topic3"> <topicmeta> <navtitle>Topic Three</navtitle> </topicmeta> </topicref> </opentopic:map> <topic id="topic1"> <title>Topic One</title> <!-- ... --> <topic id="topic2"> <title>Topic Two</title> <body> <p><xref href="#topic3">Topic 3</xref></p> </body> </topic> </topic> <topic id="topic3"> <title>Topic Three</title> <!-- ... --> </topic> </map>
2.11.5: <@td.fileProperties>
This tag contains the following attributes:
-
harpUrl
- The ContentLocator. If specified, projectKey and
itemKey are
ignored.
- Required: false
- Type: ContentLocator
- Default: none
-
harpUrlString
- The ContentLocator as a string. If specified,
projectKey and
itemKey are ignored.
- Required: false
- Type: String
- Default: none
-
itemKey
- The item key
- Required: false
- Type: String
- Default: none
-
projectKey
- The Project key
- Required: false
- Type: String
- Default: none
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
searchResult
- The SearchResultDocument object. If specified,
projectKey,
portalKey,
and harpUrl are ignored.
- Required: false
- Type: SearchResultDocument
- Default: none
-
var
- The name of the variable used to access the result.
- Required: true
- Type: String
- Default: none
Example Usage:
<#if params['projectKey']?? && params['itemKey']??> <@td.fileProperties var="itemData" projectKey="${params['projectKey']}" itemKey="${params['itemKey']}"/> </#if> <#if itemData??> <h1>${itemData.properties.specifiedDetails.title?html}</h1> <#else> <h1>No such file.</h1> </#if>
2.11.6: <@td.groupSearch>
This tag contains the following attributes:
-
cacheKey
- Unique identifier for this tag. If specified and cacheSecs
is positive, this will serve as the cache key. Otherwise the relevant
attributes will be used and all tags with the same attribute values will
share the cache.
- Required: false
- Type: String
- Default: none
-
cacheSecs
- The number of seconds to cache the results. All calls to
this tag with the same attributes will receive the cached value for
the specified length of time unless the cacheKey attribute is specified, in
which case only tags with the same ID will be affected by the caching.
Specify 0 or a negative number to disable caching.
- Required: false
- Type: int
- Default: 0
-
createdBefore
- A Date value specifying the last creation date for the
search. Only files created since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
createdSince
- A Date value specifying the earliest creation date for the
search. Only files created since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
createdSinceDays
- Only return results created in the preceding number of
days specified by this attribute.
- Required: false
- Type: int
- Default: none
-
escape
- Whether to escape characters in the query so that it
operates as a true full-text search rather than a more formal search
engine query. When set to 'true', colons, parentheses, and other
special characters used to structure queries will be escaped and
treated as plain text. If false, the query will be treated as a formal
search engine query, and syntax errors will cause failures. The
default is false.
- Required: false
- Type: String
- Default: false
- Since: 4.2
-
facets
- A space separated list of search facets. Facets do not affect search results.
- Required: false
- Type: Object
- Default: null
- Since: 4.2
-
filter
- A search query to be used as a search filter. The search filter is applied as a secondary
search on primary search results.
- Required: false
- Type: String
- Default: null
- Since: 4.2
-
groupBy
- The property to group results by. This can either be
a base property of
SearchResultDocument or a metadata field. If a
metadata field, the name should end in
"_md". For instance, to
group by "product" metadata, specify
"product_md". The default
value is "itemKey", meaning that different uses of the same DITA
topic in
different
DITA maps will be grouped together.
- Required: false
- Type: String
- Default: "itemKey"
- Since: 4.2.1
-
highlightSize
- The total number of characters before and after
the
given search term in a result. Note that if the
search term is
"*" then the highlight size will be 0.
Must be an integer n 0
<= n <= 2147483647.
- Required: false
- Type: int
- Default: 300
-
limit
- The maximum number of results per page. Must be a positive
integer n where 0 < n <= 2147483647. This does not limit the total
number of search results, which may be limited by other settings.
- Required: false
- Type: int
- Default: 10
-
maxFacetValues
- The maximum number of facet values to return when
executing the search. The resulting facets will be listed from
most-hits to least-hits. Note that this can have a significant
impact on search performance.
- Required: false
- Type: int
- Default: 10
-
metadataFields
- Space-separated list of metadata fields to return with
each search result. If the list is empty, all default metadata fields will
be returned. Otherwise, only the listed fields will be returned. An asterisk
("*") may be used in any term as a wildcard. Use just "*" to
return all metadata fields (both default and custom).
- Required: false
- Type: String
- Default: null
-
modifiedBefore
- A Date value specifying the last modified date for the
search. Only files modified since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
modifiedSince
- A Date value specifying the earliest modified date for the
search. Only files modified since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
modifiedSinceDays
- Only return results modified in the preceding number of
days specified by this attribute.
- Required: false
- Type: int
- Default: none
-
portalContent
- Whether and how to include portal content in search.
Valid values are "exclude", "include",
and "only".
- Required: false
- Type: String
- Default: exclude
- Since: 4.2
-
query
- The search query. Must not be the empty string
("").
- Required: false
- Type: String
- Default: *
-
resultsPerGroup
- The maximum number of "contexts" to return per group.
- Required: false
- Type: int
- Default: 5
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
sortBy
- The property or properties to sort by,
separated by whitespace or comma.
- Required: false
- Type: String
- Default: none
-
sortDirection
- A list of sort directions ('ASC' or 'DESC'),
corresponding in order to the list of 'sortBy' fields.
If the list is empty or shorter than the 'sortBy' list,
the default of 'ASC' will be used for the missing directions.
- Required: false
- Type: String
- Default: ASC
-
startAfter
- Alternative pagination mode. The startNextAfter token from a
previous page.
- Required: false
- Type: Object
- Default: null
-
startPage
- The page number to return. Must be an integer 0 <= n
<= 10000. Note that ithe preferred pagination method is to use
the startAfter attribute.
- Required: false
- Type: int
- Default: 0
-
var
- The name of the variable used to access the result.
- Required: true
- Type: String
- Default: none
Example usage:
When content is written in DITA, search results are "grouped" by topic, with each individual search result within that group representing the topic as it appears in a given context. To facilitate this, the Group Search tag differs from the Search tag in the following ways.
- It takes one additional optional attribute,
resultsPerGroup
that specifies the maximum number of "contexts" to return per group. - The data placed into
@var
is an instance of SearchResultsPage instead of a list of SearchResultDocuments.
The body of this tag can contain any number of <@td.metadataFilter> tags.
<@td.groupSearch var="results" query="Titania" /> <ul> <#list results.content as group> <li>${group.firstResult.title?html}</li> <ul> <#list group.results as result> <li><a href=<@td.viewerUrl searchResult=result />>${result.contextName}</a></li> </#list> </ul> </#list> </ul>
result.content.results
which will be identical to
result.content.firstResult
. Additionally, Portal Theme developers may
want to create custom viewer pages for non-DITA
content types.2.11.7: <@td.httpRequest>
This tag contains the following attributes:
-
contentType
- The request body content type. (Equivalent to setting
"Content-Type" header.)
- Required: false
- Type: String
- Default: If sending a file, the content type of the file. Otherwise, none.
-
contextId
- Context ID to preserve request context, such as
cookies
and authentication status, across several requests.
- Required: false
- Type: String
- Default: none
-
contextScope
- The scope, for the context identified by the
contextId to be retained. Possible values are "session" (the
default),
in which case the context persists for the duration of
the user's HTTP
session; "request", in which case the context
expires at the end
of
the current (Titania Delivery) request; or
"global", in which case the
context is shared by all Titania
Delivery users.
- Required: false
- Type: String
- Default: session
-
defaultCharset
- The default character set to use when interpreting
the request entity,
unless otherwise specified by the
Content-Type header.
- Required: false
- Type: String
- Default: UTF-8
-
followRedirects
- Maximum number of redirects to follow. Negative means
unlimited.
- Required: false
- Type: int
- Default: -1
-
headers
- The HTTP headers to set on the request.
- Required: false
- Type: Map
- Default: none
-
itemKey
- If sending the contents of a file, the item key of
the file.
- Required: false
- Type: String
- Default: None
-
method
- The HTTP request method.
- Required: false
- Type: String
- Default: GET
-
parameters
- Additional parameters to set on the request. If the
method is POST
and there is no tag body, the parameters will be
put into an
application/x-www-form-urlencoded request entity.
Otherwise, the parameters will be added to the request URL.
- Required: false
- Type: Map
- Default: none
-
password
- Password for HTTP authentication.
- Required: false
- Type: String
- Default: none
-
projectKey
- If sending the contents of a file, the project key of
the file.
- Required: false
- Type: String
- Default: None
-
rendition
- If sending the contents of a file, the ItemRepresentationType of
the rendition to send.
- Required: false
- Type: String
- Default: ORIGINAL
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
timeout
- Timeout value in seconds.
- Required: false
- Type: int
- Default: 20
-
url
- The URL to request.
- Required: true
- Type: String
- Default: none
-
username
- User name for HTTP authentication.
- Required: false
- Type: String
- Default: none
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
-
writeResponse
- Whether to write response body to tag output.
- Required: false
- Type: boolean
- Default: false
2.11.8: <@td.markdown>
This tag has no attributes.
Markdown is a tool that can convert text to HTML but that uses a much simpler and more human-readable syntax than HTML.
Example Usage
<@td.markdown>#Hello, Titania!<@td.markdown>
The above would resolve to the following HTML
<h1>Hello, Titania!</h1>
2.11.9: <@td.metadataFilter>
This tag contains the following attributes:
-
metadataName
- The name of the filter
- Required: true
- Type: String
- Default: none
-
metadataValue
- The value of the filter
- Required: true
- Type: String
- Default: none
Example Usage:
<@td.search var="results" query="Titania" > <@td.metadataFilter name="foo" value="bar" /> <@td.metadataFilter name="baz" value="qux" /> </@td.pageUrl>
The above code would place an array of SearchResultDocuments into results
that match the query
Titania
and that have a metadata rule of foo
with a value of
bar
, and another metadata rule of baz
with a value of
qux
.
2.11.10: <@td.pageUrl>
This tag contains the following attributes:
-
page
- The path to the custom page, relative to the
/pages/custom
folder in the portal theme.
- Required: true
- Type: String
- Default: none
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Example usage:
Assuming the existence of a /pages/custom/demo.ftl
:
<@td.pageUrl page="demo" />
would insert the url to the page created by the demo.ftl
template into
the DOM. It is most useful as the href
attribute to an anchor tag.
<a href=<@td.pageUrl page="demo.ftl" />>Demo Page</a>
Alternatively, the url could be stored in a variable and referenced later in the page:
<@td.pageUrl var=url page="demo.ftl" /> . . . <a href=${url}>Demo Page</a>
The value of the @page
attribute must be a template file relative to
/pages/custom/
.
2.11.11: <@td.pipelineParam>
filterchain:/harp/portal/markFilteredTopics.xml
, which can mark or remove
links to topics not available in the portal. See the pipeline
attribute for
<@td.content>.This tag contains the following attributes:
-
name
- The parameter name.
- Required: true
- Type: String
- Default: none
-
value
- The parameter value.
- Required: true
- Type: Object
- Default: none
2.11.12: <@td.portalUrl>
This tag contains the following attributes:
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
value
- The path within the Portal UI. If omitted, the
Portal
homepage URL will be used.
- Required: false
- Type: String
- Default: The url to the Portal home page.
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Example Usage:
<@td.portalUrl var="url" value="search" urlQuery="term=Titania" /> . . . <a href=${url}>Search for "Titania"</a>
The above code snippet would generate a link pointing to the Search page with a query of
Titania
.
2.11.13: <@td.recordPageview>
This tag contains the following attributes:
-
contextKey
- The context key. Overridden by contextUrl
and/or
contextUrlString and/or the context key specified
in
url/urlString, in
that order.
- Required: false
- Type: String
- Default: none
-
contextUrl
- The ContentLocator of the context from which to load the
data. Used to
configure hyperlinks and image references
in the
resulting content.
- Required: false
- Type: ContentLocator
- Default: none
-
contextUrlString
- The ContentLocator of the context from which to load the
data. Used to
configure hyperlinks and image references
in the
resulting content.
- Required: false
- Type: String
- Default: none
-
itemKey
- The item key. Overridden by url and/or
urlString.
- Required: false
- Type: String
- Default: none
-
projectKey
- The Project key. Overridden by url and/or
urlString.
- Required: false
- Type: String
- Default: none
-
refId
- The reference ID, in cases of a view of content in
the context of another
document, such as a top-level XML document
or DITA map.
- Required: false
- Type: String
- Default: none
-
url
- The ContentLocator object describing the content to
retrieve. Required if searchTerm attribute is not
provided.
- Required: false
- Type: ContentLocator
- Default: none
-
urlString
- The ContentLocator object describing the content to
retrieve. Required if searchTerm attribute is not
provided.
- Required: false
- Type: String
- Default: none
2.11.14: <@td.requestPart>
This tag contains the following attributes:
-
contentType
- The part content type. (Equivalent to setting
"Content-Type" header.)
- Required: false
- Type: String
- Default: If sending a file, the content type of the file. Otherwise, none.
-
filename
- The filename for this part.
- Required: false
- Type: String
- Default: If uploading a file from a project, the name of the file. Otherwise, no default.
-
itemKey
- If sending the contents of a file, the item key of
the file.
- Required: false
- Type: String
- Default: None
-
name
- The name for this part.
- Required: false
- Type: String
- Default: file
-
projectKey
- If sending the contents of a file, the project key of
the file.
- Required: false
- Type: String
- Default: None
-
rendition
- If sending the contents of a file, the ItemRepresentationType of
the rendition to send.
- Required: false
- Type: String
- Default: ORIGINAL
2.11.15: <@td.search>
This tag contains the following attributes:
-
cacheKey
- Unique identifier for this tag. If specified and cacheSecs
is positive, this will serve as the cache key. Otherwise the relevant
attributes will be used and all tags with the same attribute values will
share the cache.
- Required: false
- Type: String
- Default: none
-
cacheSecs
- The number of seconds to cache the results. All calls to
this tag with the same attributes will receive the cached value for
the specified length of time unless the cacheKey attribute is specified, in
which case only tags with the same ID will be affected by the caching.
Specify 0 or a negative number to disable caching.
- Required: false
- Type: int
- Default: 0
-
createdBefore
- A Date value specifying the last creation date for the
search. Only files created since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
createdSince
- A Date value specifying the earliest creation date for the
search. Only files created since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
createdSinceDays
- Only return results created in the preceding number of
days specified by this attribute.
- Required: false
- Type: int
- Default: none
-
escape
- Whether to escape characters in the query so that it
operates as a true full-text search rather than a more formal search
engine query. When set to 'true', colons, parentheses, and other
special characters used to structure queries will be escaped and
treated as plain text. If false, the query will be treated as a formal
search engine query, and syntax errors will cause failures. The
default is false.
- Required: false
- Type: String
- Default: false
- Since: 4.2
-
facets
- A space separated list of search facets. Facets do not affect search results.
- Required: false
- Type: Object
- Default: null
- Since: 4.2
-
filter
- A search query to be used as a search filter. The search filter is applied as a secondary
search on primary search results.
- Required: false
- Type: String
- Default: null
- Since: 4.2
-
highlightSize
- The total number of characters before and after
the
given search term in a result. Note that if the
search term is
"*", then the highlight size will be 0.
Must be an integer n 0
<= n <= 2147483647.
- Required: false
- Type: int
- Default: 300
-
limit
- The maximum number of results per page. Must be a positive
integer n where 0 < n <= 2147483647. This does not limit the total
number of search results, which may be limited by other settings.
- Required: false
- Type: int
- Default: 10
-
maxFacetValues
- The maximum number of facet values to return when
executing the search. The resulting facets will be listed from
most-hits to least-hits. Note that this can have a significant
impact on search performance.
- Required: false
- Type: int
- Default: 10
-
metadataFields
- Space-separated list of metadata fields to return with
each search result. If the list is empty, all default metadata fields will
be returned. Otherwise, only the listed fields will be returned. An asterisk
("*") may be used in any term as a wildcard. Use just "*" to
return all metadata fields (both default and custom).
- Required: false
- Type: String
- Default: null
-
modifiedBefore
- A Date value specifying the last modified date for the
search. Only files modified since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
modifiedSince
- A Date value specifying the earliest modified date for the
search. Only files modified since the given date will be returned.
Values must be java.util.Date objects. Dates can be converted to Strings in
Freemarker templates using the ?date, ?datetime, and ?time built-ins for
Strings. See
http://freemarker.org/docs/ref_builtins_string.html#ref_builtin_string_date
for details.
- Required: false
- Type: Date
- Default: none
-
modifiedSinceDays
- Only return results modified in the preceding number of
days specified by this attribute.
- Required: false
- Type: int
- Default: none
-
portalContent
- Whether and how to include portal content in search.
Valid values are "exclude", "include",
and "only".
- Required: false
- Type: String
- Default: exclude
- Since: 4.2
-
query
- The search query. Must not be the empty string
("").
- Required: false
- Type: String
- Default: *
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
sortBy
- The property or properties to sort by,
separated by whitespace or comma.
- Required: false
- Type: String
- Default: none
-
sortDirection
- A list of sort directions ('ASC' or 'DESC'),
corresponding in order to the list of 'sortBy' fields.
If the list is empty or shorter than the 'sortBy' list,
the default of 'ASC' will be used for the missing directions.
- Required: false
- Type: String
- Default: ASC
-
startAfter
- Alternative pagination mode. The startNextAfter token from a
previous page.
- Required: false
- Type: Object
- Default: null
-
startPage
- The page number to return. Must be an integer 0 <= n
<= 10000. Note that ithe preferred pagination method is to use
the startAfter attribute.
- Required: false
- Type: int
- Default: 0
-
var
- The name of the variable used to access the result.
- Required: true
- Type: String
- Default: none
The Search tag is similar in function to the <@td.searchResultUrl> tag. However, instead of generating a link to the search results page
(/pages/searchResults.ftl
) which renders the results of the given search
parameters, this tag executes the search and places the results into a variable for
use in the
current page. This allows for adding search results from theme-defined parameters
into any page.
Example Usage:
<@td.search var="results" query="Titania" />
The above would place an array of SearchResultDocuments into
results
. Those results could later be iterated over with:
<#list results as result> <#-- Do something with the "result" variable --> </#list>
Metadata filters could be added to the search using any number of <@td.metadataFilter> tags.
<@td.search var="results" query="Titania" > <@td.metadatFilter name="Product" value="Delivery" /> </@td.search>
2.11.16: <@td.searchResultUrl>
This tag contains the following attributes:
-
query
- The query.
- Required: false
- Type: String
- Default: *
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Example Usage:
This tag provides a way to generate links to "canned" searches to direct users to certain collections of content.
<@td.searchResultUrl query="Titania" />
The above would add a link to the Search page with a
query for Titania
. As with the other url-generating tags, this is best used as the value to the
href
attribute of an anchor tag:
<a href=<@td.searchResultUrl query="Titania" />>Search for "Titania"</a>
The url could also be stored in a variable and used later in the page:
<@td.searchResultUrl var=url query="Titania" /> . . . <a href=${url}>Search for "Titania"</a>
Lastly, the search can be refined by adding any number of metadataFilter tags to the body:
<@td.searchResultUrl query="Titania" > <@td.metadataFilter name="product" value="Delivery" /> <@td.metadataFilter name="version" value="2.0" /> </@td.searchResultUrl>
2.11.17: <@td.setContentFilter>
This tag contains the following attributes:
-
filter
- The search clause for filtering content.
- Required: true
- Type: String
- Default: None
<#-- Assuming a function "getCountry()" will return a country code --> <#assign targetCountry=getCountry()!"US"/> <@td.setContentFilter filter="country_md:${targetCountry}" />
The above would add a session-scoped search filter to exclude all documents without the specified "country" metadata value.
This directive should be used carefully, because it affects all content queries in the user's session, and could have the unintended consequence of restricting access to needed content items. The filter can be removed with a directive like:
<@td.setContentFilter filter=""/>
2.11.18: <@td.themeFileUrl>
This tag contains the following attributes:
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
value
- The path within the "static" folder.
- Required: false
- Type: String
- Default: The base URL to the "static" folder
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Example Usage:
Assuming the presence of /static/logo.png
in the Portal Theme:
<@td.themeFileUrl value="logo.png" />
The above would add a url pointing to logo.png
to the page. As with other
tags, this url could be used directly as an attribute value or stored in a variable:
<img src=<@td.themeFileUrl value="logo.png" /> />
<@td.themeFileUrl var="logoUrl" value="logo.png" /> . . . <img src=${logoUrl} />
The file pointed to by the @value
attribute must be a file relative to the
static/
directory.
2.11.19: <@td.urlParam>
This tag contains the following attributes:
-
name
- The parameter name
- Required: true
- Type: String
- Default: none
-
value
- The parameter value
- Required: true
- Type: String
- Default: none
This tag is available for use inside the body of the following tags:
Example Usage:
<@td.pageUrl var="url" value="demo.ftl" > <@td.urlParam name="foo" value="bar" /> <@td.urlParam name="baz" value="qux" /> </@td.pageUrl> . . . <a href=${url}>Custom Page With Params</a>
The value of url
in the above example would point to the page generated by
/pages/custom/demo.ftl
and have a query string of
?foo=bar&baz=qux
.
2.11.20: <@td.viewerUrl>
This tag contains the following attributes:
-
contextualizedChild
- A Contextualization object. If specified, the
preview
rendition of this contextualized child will be
used.
- Required: false
- Type: Contextualization
- Default: none
-
portal
- The PortalIdentity object. If not
specified,
there must
be a ${portal} attribute in scope.
- Required: false
- Type: PortalIdentity
- Default: The PortalIdentity object on the current page
-
scope
- The scope of the @var attribute. Valid values are
"page" and "request".
- Required: false
- Type: String
- Default: "request"
-
searchResult
- The SearchResultDocument object. This data is
placed
into the model of the searchResults.ftl page and returned by
<@td.Search> and <@td.groupSearch> tags. If not
specified, there must be
a ${doc} variable storing a
SearchResultDocument object in scope.
- Required: false
- Type: SearchResultDocument
- Default: SearchResultDocument object stored in a variable called ${doc}
-
url
- The ContentLocator of the item. If context information
is
provided
via other attributes, it will override any
context
information in this
object.
- Required: false
- Type: ContentLocator
- Default: none
-
urlQuery
- The query string. This value will NOT be URL-encoded, so it
should be encoded already. You can also use nested <@td.urlParam> tags
to specify individual URL parameters in a URL-escaped way.
- Required: false
- Type: String
- Default: none
-
urlString
- The ContentLocator of the item.
If context information
is
provided
via other attributes, it will override any
context
information in this
object.
- Required: false
- Type: String
- Default: none
-
var
- The name of the variable used to access the result.
- Required: false
- Type: String
- Default: none
Titania Delivery determines whether mapViewer.ftl
or
viewer.ftl
will be rendered depending on the content.
Example Usage:
Assuming that a variable to a SearchResultDocument called
${doc}
is available on the current page:
<@td.viewerUrl var="url" searchResult=doc /> . . . <a href=${url}>Document</a>
2.11.21: <@td.xslParam>
Chapter 3: Static Assets
static
directory can contain files such as graphics,
JavaScript, CSS style sheets, and any other static resources that need to be made
available to a
portal. 3.1: Managing Static Files for a Portal
/static
folder.The files in the /static
directory should not be referenced via static URL.
Instead, Titania Delivery provides the <@td.themeFileUrl> tag for generating
URLs for static file references.
3.2: SASS and LESS Support
When referenced by a portal page, files with a .sass
or
.scss
file extension will be converted to CSS using SASS rules. Files
ending in .less
will be compiled using LESS. This means that the browser
will be served a single compiled CSS file, but portal theme developers can take advantage
of
the advanced features and simplicity of these pre-compiled languages. If an error
occurs
during stylesheet compilation, the output will be a CSS comment containing the error
message.
Chapter 4: XSLT Files
xsl
directory contains the XSLT stylesheets that can be used to
transform content that is referenced using the <@td.content>
tag in
portal theme pages.The @xsl
attribute on the <@td.content>
tag specifies a
path relative to the xsl
directory. This attribute specifies the
stylesheet that will be applied to the content.
4.1: Writing XSLT for DITA
The theme XSLT templates are applied to the FLATTENED ItemRepresentationType of topics, or to the MONOLITH rendition of maps--not to the original XML document that was uploaded to the project. The processed version will include the results of conventional DITA processing expectations such as adding the DITA @class attribute on all elements, resolving external references and content inclusions, applying any profiling filters, and adding navigation links based on the topic's map context.
4.1.1: DITA XSLT Module URIs
The built-in XSLT source files may be downloaded from a Titania Delivery server at
a URL
like:
td-server-base-url/resources/td-xsl-lib.zip
. An XSLT
developer may override any of these templates in a portal theme.
-
urn:titania:dita-xsl:topic-html-fragment.xsl
- This module will convert a DITA topic into basic
HTML5 markup, without wrapping
<html>
or<body>
elements. -
urn:titania:dita-xsl:map-html-fragment.xsl
- This module will convert a DITA map into basic
HTML5 markup, without wrapping
<html>
or<body>
elements. The root element is a<div class="map">
element containing<ul id="toc">
with the structure of the map.
4.1.2: Writing Specialization-Aware XSLT
Specialization in DITA is implemented using the special format of the @class
attribute. When writing a template, the @match
attribute should not
use a tag name.
<!-- DO NOT match on DITA element name! --> <xsl:template match="note"><!-- bad practice -->
Instead, match on the @class
attribute.
<!-- This is OK, but verbose. It will match on "note" elements and all specializations therefrom --> <xsl:template match="*[contains(@class, ' topic/note ')]">
Titania Delivery provides a utility entity file that contains entity declarations
for all of
the base DITA elements mapping to the @class
-qualified form, in a way that is
easier to read. This allows the above to be rewritten as:
<xsl:template match="¬e;"/>
For every element in the base DITA vocabulary, the entity file referenced above contains entries similar to the following:
<!ENTITY note-condition "contains(@class, ' topic/note ')"> <!ENTITY note "*[¬e-condition;]">
To use these entities, link in the entity file using the public ID
-//Titania//ENTITIES DITA XPath Definitions//EN
.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xsl:stylesheet [ <!ENTITY % tags PUBLIC "-//Titania//ENTITIES DITA XPath Definitions//EN" "dita-xpaths.ent"> %tags; ]> <xsl:stylesheet version = "2.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" > <xsl:import href= "urn:titania:dita-xsl:topic-html-fragment.xsl" /> <xsl:template match="¬e;" mode="html #default"> <!-- Custom note handling --> </xsl:template> </xsl:stylesheet>
4.1.3: DITA XSLT Conventions
- The
@class
attribute in HTML output elements is comprised of:- Every tag name in the DITA specialization hierarchy for the source element.
- The value of the
@outputclass
attribute, if any.
<b>
is a specialization of<ph>
,<b outputclass="superBold">
would become<b class="ph b superBold">
. This allows you to do most of your DITA styling using CSS instead of XSLT. - For the most part, the templates are configured in both the
#default
andhtml
modes. The exception is<map>
and<topicref>
processing, which is generally processed usingmode="toc"
, switching formode="html"
for visible content, like<navtitle>
content. - Conditional processing attributes -
@product
,@platform
,@audience
,@otherprops
, and any@props
specializations identified in the@domains
attribute of the root element - will be preserved in HTML output, prefixed with@data-
(for example,@data-audience
). - All templates in these modules have a negative
@priority
, so that they can be easily overridden by stylesheets that reference them. -
@id
attributes are converted into named anchors of the form<a name="{@id}" class="xmlId"/>
- The
@xtrc
and@xtrf
attributes, generated during processing to identify the source of a given XML element, are represented as@data-xtrc
and@data-xtrf
in the HTML output.Note: The Comment Manager uses@data-xtrc
and@data-xtrf
to trace comment locations back to source XML. -
@xml:lang
attributes are converted to@lang
, and@dir
is preserved.
4.1.4: Customizing the Built-In DITA XSLT Output
The built-in DITA XSLT stylesheet uses a common pattern for all elements, enabling simple customization using custom template modes.
-
html-tag-name
- Use this mode to specify the HTML element
name.
<xsl:template match="&topic;/&topic;//&topic;/&title;" mode="html-tag-name"> <xsl:text>h4</xsl:text> </xsl:template>
-
html-atts
- Use this mode to specify additional attributes to be placed on the HTML element for
the
tag.
<xsl:template match="¬e;" mode="html-atts"> <xsl:attribute name="data-note-type" select="@type"/> </xsl:template>
-
output-class
- Use this mode to contribute tokens to the HTML @class attribute on the
generated HTML element. It's generally a good idea to end such a template with
<xsl:next-match/>
to ensure all contributions to @class are processed.<xsl:template match="&tm;" mode="output-class"> <xsl:value-of select="@tmtype"/> <xsl:next-match/> </xsl:template>
Note: By default, all element names in the specialization hierarchy are automatically included in the HTML @class attribute. For example, the @class attribute for <xmlelement>, which is specialized from <markupname> and <keyword>, isclass="keyword markupname xmlelement"
. In addition, the @outputclass values also appended to the HTML @class. -
gentext-before-outer
-
gentext-before-inner
-
gentext-after-inner
-
gentext-after-outer
- These modes enable you to easily insert content before and/or after an element's
content. The
inner
variants will place the generated code inside the wrapper element; theouter
variations, outside the wrapping elements. When using this mode, it's best practice to end with<xsl:next-match/>
to ensure that all generated text is processed.<xsl:template match="&q;" mode="gentext-before-inner gentext-after-inner"> <xsl:text>"</xsl:text> <xsl:next-match/> </xsl:template>
4.1.5: Default DITA Element Mappings
By default, all DITA elements are converted into <div>
tags, unless
otherwise specified below.
- HTML Equivalents
- The following elements and their specializations are converted directly into their
HTML
equivalents.
-
<p>
-
<b>
-
<i>
-
<u>
-
<sup>
-
<sub>
-
<dl>
-
<ul>
-
<ol>
-
<li>
-
<pre>
-
<object>
-
<param>
-
<dt>
-
<dd>
-
<q>
-
- Simple Inline Elements
- The following elements and their specializations
are converted into simple
<span>
tags.-
<ph>
-
<keyword>
-
<cite>
-
<term>
- Children of
<personname>
- Children of
<locality>
-
<foreign>
-
<unknown>
-
- Inline Code Elements
- The following elements and their specializations
are converted to
<code>
tags.-
<filepath>
-
<codeph>
-
<cmdname>
-
<apiname>
-
- Deleted Tags
- The following elements and their contents are
not represented in the output HTML at all by
default using these modules.
-
<abbreviated-form>
-
<fn>
-
<data>
-
<data-about>
-
<indexterm>
-
<reltable>
-
<titlealts>
-
<prolog>
-
4.1.6: DITA Elements with Special Processing
<image>
Converted into an <img> tag, setting @width and @height values, if any, using @style, and representing any <alt> tag in both the @alt and @title attributes. The @href attribute becomes @src, but is otherwise untouched; link and graphic references are updated to web URLs automatically after the XSLT runs.<xref>
Converted into <a> tags. The <desc> element,
if present, is converted into @title attribute. The @href
attribute is untouched; link and graphic references are updated to web URLs automatically
after the XSLT runs. However, you can customize this behavior by overriding the named
get-xref-href
template.
Processing of <xref> also calls the named
extra-xref-attrs
template. By default, this sets
target="_blank"
on links whose @scope is not
"local"
.
<note>
- The @type attribute value is included in the output @class attribute.
- A <h4 class="noteHeader"> element containing the @type value is prepended to the note contents.
<table> and <simpletable>
The table structures represented by both <simpletable> and <table> are converted to the HTML table model.<title>
- Top-level map and topic titles become <h1>.
- Second-level topic titles become <h2>.
- All other topic titles become <h3>.
- Section and example titles also become <h3>.
- All other titles become <h4>.
<dl>
Definition lists are converted into simple HTML <dl> tags; <dlhead> elements are removed.<dlentry>
These are removed unless they contain profiling attributes or attributes from the DITA metadata attribute group, in which case it will be converted into a <div> to carry the HTML versions of those attributes. (This is not valid HTML5, but HTML5 does not provide a valid way to wrap <dt> and <dd> tags, and the use of <div> renders invisibly on all modern browsers.)<xmlelement>
Wrapped in angle brackets (<>).<xmlatt>
Prefixed with "@".<tm>
Appends the appropriate symbol (as specified by @tmtype) to the content. In addition, the @tmtype, @trademark, @tmowner, and @tmclass attributes are converted into HTMLdata-
attributes.<menucascade>
The children of this element are joined together using a joining character that can
be
controlled using the $menucascade-separator
parameter ( ⇒ by default).
<object data="*.mp4">
When a <object> tag references an MPEG-4 video (as identified by the extension of the @data attribute), it is converted into an HTML5 <video> tag.<lines>
This becomes <pre class="lines"> instead of a <div>.<sl> and <sli>
These are converted into <ul> and <li>, respectively.4.1.7: Related Link Handling
Following standard DITA rules, the Titania Delivery DITA processing engine will insert
the
appropriate related links based on the map structure and reltables, as well as preserving
any
manually-authored links, all with the appropriate @role
attributes applied.
The processing order can be customized.
Link Groupings
The default template for
<related-links>
looks like
this:
<xsl:template match="&related-links;[.//&link;]" priority="-20" mode="#default html"> <div> <xsl:call-template name="generate-common-attrs" /> <xsl:call-template name="do-child-links" /> <xsl:call-template name="do-sequence-links" /> <xsl:call-template name="do-sibling-links" /> <xsl:call-template name="do-link-groups" /> <xsl:call-template name="do-other-links" /> <xsl:call-template name="do-parent-links" /> </div> </xsl:template>
It calls the following named templates, in this order.
-
do-child-links
(role="child"
) -
do-sequence-links
(role="previous"
androle="next"
) -
do-sibling-links
(role="sibling"
) -
do-link-groups
(links wrapped in<linklist>
) -
do-other-links
(all other links except@role="parent"
) -
do-parent-links
(role="parent"
)
You can override this template to change the order of links in HTML output, or to eliminate various groups of links.
Default Link Structures
The <linklist>
element is converted into an
<ol>
, and each link it contains is wrapped in
<li>
. Other links are simply placed within
<div>
elements. Within its container, each link consists of
- An
<a>
tag, with the link itself. - For child links, a
<div>
containing the short description of the topic, if present. (The DITA engine also generates or populates<desc>
tags for related links when possible in the XML presented to the stylesheet.)
Customizing Link Presentation
The built-in related links module includes two special modes for customizing link presentation.
-
get-link-label
- Used to get a label for the link. This is separate from the link text. By default,
the
module provides "Previous Topic," "Next Topic," and "Parent topic" for
@role='previous'
,@role='next'
, and@role='parent'
links, respectively. -
get-link-class-tokens
- This mode is used to retrieve any additional HTML @class attribute tokens to include on the generated wrapper element for the link. By default, the @class attribute will include the link tag's specialization hierarchy as well as the value of the @role attribute.
For example, to provide custom @class and label for links whose
@role is "sibling"
, you could add code like the
following.
<xsl:template match="&link;[@role='sibling']" mode="get-link-label"> <xsl:text>Sibling Topic:</xsl:text> </xsl:template> <xsl:template match="&link;[@role='sibling']" mode="get-link-class-tokens"> <xsl:text>sibling-link my-special-class</xsl:text> </xsl:template>
4.1.8: Profiling Attributes
data-
attributes in the output HTML.Profiling and metadata attributes include
- Attributes from the standard Metadata attribute group.
- Any attribute specializations of @props or @base.
Any such attributes that survive the DITA preprocessing step, including conref processing
and
DITAVAL-based profiling, will be added to the appropriate HTML elements prefixed with
data-
. For example,
<p audience="Expert" importance="urgent">Expert Paragraph</p>
Would be converted into
<p data-audience="Expert" data-importance="urgent">Expert Paragraph</p>
4.2: Writing XSLT for Non-DITA XML
Non-DITA content is processed and decorated with namespaced attributes describing each element's role using rules configured in the document type. This means that all non-DITA document types can be treated similarly by reading the decoration attributes instead of the element names. Additionally, non-DITA doctypes may include a basic, universal XSLT transform that should be applied in all portal themes.
Titania Delivery provides a "virtual" XSLT module, called
urn:titania:xsl:modules:decorated-html.xsl
, that can be used to style
most non-DITA XML content. This module will pull in the document type's default transform,
if
present, as well as supply default styling based on the configuration-based role attributes.
Most portal theme stylesheets for non-DITA XSLT can probably be a simple inclusion
of this
module.
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:include href="urn:titania:xsl:modules:decorated-html.xsl"/> </xsl:stylesheet>
Utility Modes
This stylesheet also includes a number of template modes that can be used to easily customize certain aspects of certain elements.
-
html-tag
- This mode is called on every XML element to determine the HTML element in the output.
You can use this mode to customize this
behavior.
<xsl:template match="sidebar" mode="html-tag"> <xsl:text>section</xsl:text> </xsl:template>
-
html-attrs
- This mode will be called on all elements, and can be used to override the attributes
placed on the resulting HTML dlement for specific source XML elements. The default
implementation calculates the @class attribute and then applies this
mode to all attributes on the element, so to add a representation of a specific
attribute in the HTML output, you can simply match on that
attribute.
<!-- Customize attributes on a specific tag --> <xsl:template match="info" mode="html-attrs"> <xsl:attribute name="class">info</xsl:attribute> <xsl:attribute name="data-label" select="concat(@label, ' ', @date)"/> </xsl:template> <!-- Customize a specific attribute on a specific tag --> <xsl:template match="sidebar/@appliesTo" mode="html-attrs"> <xsl:attribute name="data-appliesTo" select="."/> </xsl:template>
-
class-tokens
- This mode can be used to augment the HTML @class attribute contents
for specific
elements.
<xsl:template match="graphic" mode="class-tokens"> <xsl:text>img-fluid contentGraphic</xsl:text> </xsl:template>
By default, the @class attribute contains the source element name as well as the roles described by the document type'sdoctype.xml
file for the element.
See Non-DITA XML Processing for additional details.
4.3: Localizing Generated Text
Gentext translation is implemented using a simple XSLT function called
{http://www.titaniasoftware.com/namespace/puck-saxfilter-dita}getString()
(the namespace is commonly mapped to the prefix p
, so
p:getString()
). This function takes the English string as a parameter and
returns the translated string. The default Titania Delivery portal theme implements
this
function to load strings from XML dictionaries stored in the portal theme itself under
the
xsl/i18n
folder.
String Lookup Strategy
The default portal theme uses the following algorithm to determine the effective language to use.
- If the root element of the document carries an @xml:lang attribute, that
value is used. You can disable this behavior by specifying the parameter
docLangOverrides=no
to the transformation. - If there is no @xml:lang or the
docLangOverrides=no
is used, the$defaultLang
parameter is used. The default value for this parameter isen
.
You can override this behavior, or the entire translation scheme itself, by modifying
the
/xsl/i18n/strings.xsl
module in the portal theme.
The default p:getString()
implementation follows the following algorithm
to look up a string.
- Look for an XML document matching the current language. If it exists, look up the string in that document. If found, return.
- If the current language is regionalized - that is, contains an underscore or dash (like 'en-US' or 'fr_FR'), strip off the suffix and look for a document matching only the language code (so 'en-GB' would fall back to 'en'). Start over at step one with the truncated language code.
- If the current language is different from the
$defaultLang
parameter (because of @xml:lang), start over at step one with$defaultLang
. - Otherwise, simply return the input parameter as the string to use.
Adding or Modifying Translated Generated Text Strings
To add new strings, simply modify the XML documents in the /xsl/i18n
folder of your theme. These documents use an extremely simple format:
<strings> <string key="englishString">Translation</string> <!-- Other Strings --> </strings>
Modify these documents to update the strings used in generated text. To pull in a
new
string, simply use the p:getString()
function from your XSLT files. For
example:
<xsl:value-of select="p:getString('My Custom Gentext')"/>
Adding New Languages and Language Variants
To add new languages to the generated text system, simply create a new string library
file
named for the locale and add it to the /xsl/i18n
folder.
You can also add new language variants, such as en_GB
or
fr_CA
by adding appropriately-named XML files. If a string is missing
from a regionalized document, the translation system will fall back to the unlocalized
library. For example, if a string is missing from fr_CA.xml
, the system
will look for it in fr.xml
.
4.4: Troubleshooting XSLT
For example:
<!--ERROR Error parsing stylesheet "harp://559d46e9e4b09b79fafb191c/p/xsl/topic/topic.xsl". Errors: Unexpected token "<eof>" in path expression; SystemID: harp://559d46e9e4b09b79fafb191c/pr/ORIGINAL/xsl/topic/topic.xsl; Line#: 36; Column#: 18 --> <div class="renderingError"> <h2>Content Rendering Error</h2> <p>An error occurred rendering this content. Please contact your system administrator.</p> </div>
Chapter 5: Offline Packagers
Offline packagers are features of portal themes, and are placed beneath the root-level
/packagers
folder in the theme, for example,
/packagers/webhelp
.
The /packagers
directory may include other files and directories that
are used by more than one packager. Packager directories are distinguished by having
a
packager.ftl
file and an optional config.json
file
directly within them. For example, in the following directory list, only the
webhelp
directory is a packager directory. The others contain common
templates and resources that may be used by all packagers.
packagers/ common/ helpers/ scripts/ webhelp/ config.json packager.ftl
The packager folder consists of the following files.
- A
packager.ftl
Freemarker script, which is the entry-point for the creation of the package's contents. - An optional configuration file called
config.json
that specifies various options for the packager. - Any Freemarker component scripts referenced by
packager.ftl
. - Files to be included in all generated packages, like styling assets, licensing boilerplate, or other static assets not used by the online theme.
In terms of the actual output file format, all packages are ZIP archives. However, many other file formats, such as ePub, Java WAR applications, and even Microsoft Office documents are actually implemented as ZIP archives. A packager script could be written to emit archives meeting any of these specifications.
The packager.ftl
file will have access to a set of APIs specific to
building packages. It will not have access to most of the tag library used for online
portal pages, though similar tags will be provided by the API in some cases. For example,
a
tag called <@packager.docContents/>
will serve a similar purpose to
<@td.content/>
in online templates, namely, inserting XML, HTML, or
text content into a file, possibly with an XSLT transform.
The config.json
file specifies metadata for a package, such as its file
name, MIME type, and the algorithm to use when determining where in the package to
place the
documents being packaged, and what their output extensions will be. These algorithms
are
expressed using Freemarker expressions.
When a portal user requests a package for a document or documents, the server will
execute
the packager.ftl
template. That script will receive the list of documents
to be packaged as well as a number of other configuration options. Using those variables
and
the packager APIs, the script will add content to the package, and then the built
package will
be delivered to the user.
A Simple Packager
A very basic package builder might look like this.
<#-- Add the /static folder from the theme to the root of the archive --> <@package.put src="/static"/> <#-- Compile the SASS stylesheet --> <@package.preprocessCSS src="/static/style/main/default.scss" dest="/static/style/main/default.css"/> <#-- Add a LICENSE statement from the current packager's directory --> <@package.put src="LICENSE.txt" dest="/about/LICENSE.txt"/> <#-- Generate homepage with links to the documents --> <@package.generate dest="/index.html"> <!DOCTYPE html> <html> <head> <title>${(parameters.title!'WebHelp')?html}</title> <link rel="stylesheet" href="static/style/main/default.css"/> </head> <body> <h1>${portal.displayName?html} Export for ${user.displayName?html}</h1> <ul> <#list documents as doc> <li> <a href="${package.relativeUri(doc)?html}"> ${doc.metadata.title[0]?html} </a> </li> </#list> </ul> </body> </html> </@package.generate> <#-- Generate web pages for the content --> <#list documents as doc> <#-- Actual page templates managed as standalone files --> <#if doc.contentType?contains('pdf')> <#include "docPages/pdf.ftl"/> <#elseif doc.properties.is_ditaMap??> <#include "docPages/map.ftl"/> <#elseif doc.properties.is_ditaTopic??> <#include "docPages/topic.ftl"/> <#else> <#-- Just copy the source into the package. --> <#-- The getDocLocation() function above will determine 'dest' --> <@package.putDocument document=doc/> </#if> </#list>
5.1: Packager Variables
The packager.ftl
template is provided with the following global
variables.
-
documents
- The list of documents to be included in the packaged, represented as a Freemarker
array
of
PackageDocument
objects, the structure of which is described below. -
parameters
- A hash of the parameters passed when the package was requested.
-
online
- A boolean specifying whether the script is running in 'online' or 'offline' mode.
In a
packager, this will always be
false
. This value is also available to all online portal theme pages with a value oftrue
. This will allow page components used for both online pages and package pages to determine whether or not they're running for a packager, and adjust themselves accordingly.<#if online> <#-- Generate live page contents with online APIs --> <#else> <#-- Generate offline content with packager APIs --> </#if>
-
offline
- The opposite of
online
.
The PackageDocument
Data Structure
The documents
array contains a list of objects describing the properties
and metadata of each document to be included in the package. The packager script iterates
over these documents, placing each into the appropriate location in the bundle, possibly
after transformation (e.g. XML to HTML5).
In addition, each document contains an array referring to the other files, like graphics or, for DITA Maps, contextualized topics. The packager infrastructure provides various utility mechanisms for automatically including graphics and contextualized DITA topics into generated packages, but you can use the relationships to perform custom, manual processing of such files.
The formal definition of the PackageDocument
structure follows (TypeScript
syntax).
class PackageDocument { // Properties of the file itself. key: string; project: ProjectInfo; label: string; // file name, e.g. foo.xml projectPath: string; // path within the project, e.g. /path/to/foo.xml folderPath: string; // The path of the folder containing the file, including leading / basename: string; // The base name of the file extension: string; // The file extension contentType: string; size: number; lastModified: Date; createDate: Date; packageRoot: boolean; // Whether this document is a package entry-point, that is, // included explicitly in the package request. isVirtual: boolean; // Typically for topichead virtual documents. // Indicates if there is a search record for this document. // A map of strings to arrays of strings metadata: {[name: string]: string[]} // The properties of the document, analogous to the 'properties' variable in online // viewer page templates. properties: {[name: string]: any} // For documents referenced by other documents // (map-to-topic references, images, etc.), the // referencing document. context: PackageDocument; hasContext: boolean; // For topics referenced by maps, the topicref ID. refId: string; // 'Child' references, e.g. topicrefs, graphics. outgoingReferences: Reference[]; // Helpful for building search indices. keywords: string[]; textContents: string; } enum ReferenceType { // Inclusions, like DITA topicrefs or xincludes PARENT_CHILD, // Non-contextualizing references, like hyperlinks LINK, // Graphic references GRAPHIC, // XML doctype references DOCTYPE, // Generic, non-DITA links FILEREF } class Reference { parent: PackageDocument; child: PackageDocument; type: ReferenceType; } class ProjectInfo { key: string; name: string; }
Freemarker package directive template output
A packager freemarker template's primary purpose is to create a zip archive as specified
by
the @package.*
directives. It will also produce text output as a result of
normal freemarker template processing. The output generated by the
@package.*
directives will be an informational transcript of the actions
taken, including warnings about any requested actions that may not have been completed
as
expected. If the configuration buildLogEntry
is not null, the output will
be written to the designated package entry.
5.2: Packager Configuration
The config.json
file is used to configure certain behaviors of the
packager and its output. The file is optional; if not present, various fields' default
values
will be used. The packager infrastructure uses the following fields:
-
buildLogEntry
- The location in the generated archive of the file containing the output of the
packager.ftl
script. Set tonull
to omit the build log. Default:.tdbuild.log
. -
cacheDays
- Because packages may be expensive to build, they are cached such that whenever the
same
package is requested, the already-built version will be sent. The cache will be cleared
when any of the documents in the package are modified, or after this number of days.
If
not specified or negative, caches never expire. If zero, the cache is not used (not
recommended). Default:
-1
. -
contextualizedDocLocation
- Similar to
docLocation
, but used for documents (almost always DITA topics) that have been contextualized by another (almost always a DITA map). Since the same source document may appear with multiple contextualizations, it may need to be represented by distinct output artifacts. Default:${doc.project.name}/${doc.context.folderPath}/${doc.context.basename}_files/${doc.refId}.${config.outputExtensions[doc.extension?lower_case]!doc.extension}
-
defaultContentEncoding
- The default encoding used for files built using
<@package.generate>,
<@package.generateDoc>, and
<@package.preprocessCSS>, when those elements'
@encoding attributes are not specified. By default, the
encoding
setting is used. -
docLocation
- The location in the generated archive for the file representing a document, as specified
via the
doc
Freemarker variable. Thedoc
variable is of typePackageDocument
. This template is used to generate the default locations of generated files, as well as when resolving links between documents. Default:${doc.project.name}/${doc.folderPath}/${doc.basename}.${config.outputExtensions[doc.extension?lower_case]!doc.extension}
-
encoding
- The character encoding used for metadata and file paths in the generated zip archive.
Default:
UTF-8
. -
filename
- The name of the generated package file. This value is evaluated as a Freemarker
template; see Packager Variables for the list of valid variables.
Default:
${params.packageBasename!portal.displayName}-package.zip
-
logLevel
- The threshold level for writing log messages. Must be one of
DEBUG
,INFO
,WARNING
orERROR
. Default:INFO
. -
mimeType
- The MIME type of the packages generated by this packager. Used when delivering the
package over HTTP. Default:
application/zip
. -
outputExtensions
- Maps the source document file extensions to the extension of the file in the package.
This allows certain file types, especially XML documents, to use
.html
as their file extension in the package instead of.xml
..dita
, or.ditamap
. The default mappings are:xml
html
dita
html
ditamap
html
md
html
eps
png
cgm
png
tif
png
tiff
png
-
scriptOutputMaxSize
- How many characters of the build log to store with the package information document.
Because the build logs can be quite large, only a portion of the log should be stored.
(The full build log is in the package archive at the
buildLogEntry
location.) Default:50000
.
The docLocation
, contextualizedDocLocation
, and
filename
entries are Freemarker scripts that are used to dynamically
calculate values at runtime. These scripts have access to the following variables:
-
portal
- The portal through which the package is being built.
-
config
- The data structure described in
config.json
. -
params
- The parameters passed to the packager.
-
doc
(docLocation
only) - The
PackageDocument
whose filename to render.
Here is a sample config.json
, which uses default settings for all
fields:
{ "mimeType": "application/zip", "encoding": "UTF-8", "defaultContentEncoding": "UTF-8", "cacheDays": -1, "scriptOutputMaxSize": 50000, "buildLogEntry": ".tdbuild.log", "logLevel": "INFO", "filename": "${params.packageBasename!portal.displayName}.zip", "docLocation": "${doc.project.name}/${doc.folderPath}/${doc.basename}.${config.outputExtensions[doc.extension?lower_case]!doc.extension}", "outputExtensions": { "xml": "html", "dita": "html", "ditamap": "html", "md": "html", "eps": "png", "cgm": "png", "tif": "png", "tiff": "png" } }
5.3: The package
API
package
Freemarker namespace.Directives (Tags)
<@package.add>
Adds a document to the archive. The document is not modified in any way, and is simply placed as-is. This is primarily for non-textual document formats, like PDF, Microsoft Office, images, video, and audio files.
- @document
- Required. The
PackageDocument
instance to insert. - @dest
- Optional. The location in the archive to place the document. If not specified, the
location in the archive will be determined by the
docLocator
orcontextualizedDocLocator
patterns from theconfig.json
file. - @failOnDuplicate
- Whether to fail the packager if an attempt is made to add a duplicate entry to the
archive. If
false
(the default), subsequent adds to the same package entry will fail silently. Otherwise the packager will fail with an exception. - @representation
- Optional. An array of ItemRepresentationTypes, in
priority order. The first type for which there is database content for the specified
document will be placed in the package. This attribute supports conversion of
non-web-friendly graphics to web-friendly renditions for display inline in an HTML
page. For example, if the current pkgDoc is an EPS file referenced from a web page,
the following directive would place the PNG rendition in the package (if available),
or fall back to the original file
type.
<@package.add document=pkgDoc representation=["PREVIEW","ORIGINAL"]/>
For example:
<@package.add document=curDocument/>
<@package.put>
Puts files and directories from the portal theme to the archive.
- @src
-
The portal theme file or directory to add, as a path-like string. If the value begins with a forward slash (/), the location is found from the root of the portal theme. Otherwise, the path from the portal theme root is calculated from the current lexical template location. Relative
src
paths may include "../
" components to refer to the parent directory.If the source is a folder, its contents will be recursively copied. If the path ends with "/*", only the contents of the named folder will be copied. Otherwise, the final folder in the
src
path (and its contents) will be copied. - @dest
- Optional. The path in the archive where to put the copied source files or folder. If not specified, files and folders are added at the root of the archive. The @dest attribute value is implicitly an absolute directory path, so leading and trailing slashes are assumed, whether or not the template author writes them.
- @failOnDuplicate
- Whether to fail the packager if an attempt is made to add a duplicate entry to the
archive. If
false
(the default), subsequent adds to the same package entry will fail silently. Otherwise the packager will fail with an exception.
For example:
<#-- Copy the theme's /static directory and its contents to /stuff/static in the archive. --> <@package.put src="/static" dest="/stuff/"/> <#-- Copy the contents of the theme's /static directory into the /stuff directory in the archive. --> <@package.put src="/static/*" dest="/stuff"/> <#-- Copy favicon.ico from the theme's /static directory to the root of the archive. --> <@package.put src="/static/favicon.ico"/> <#-- Copy all files from the template's parent directory's "images" sibling directory into the archive root "images" entry. --> <@package.put src="../images/*" dest="images"/> <#-- Same as preceding example. --> <@package.put src="../images"/>
<@package.preprocessCSS>
TD online portals support LESS or SASS stylesheets, which must be compiled into CSS before being used by browsers. This directive is similar to <@package.put>, except that it compiles the LESS or SASS file, as determined by file extension, to CSS before placement in the archive.
- @src
-
Path to a LESS or SASS file in the portal theme. Relative paths will be resolved from the current lexical template location, and may include "
../
" components to refer to the parent directory. - @dest
-
The path in the archive where to put the compiled CSS file. This is implicitly an absolute path from the archive root. A value must be supplied; there is no default destination.
- @encoding
- The character encoding to use for the contents of the generated CSS file. Optional.
If not specified, the configuration's
defaultContentEncoding
property is used.
<@package.preprocessCSS src="/static/style/main/default.scss" dest="/static/default.css"/>
<@package.generate>
Executes the nested Freemarker code to generate a file, placing it in the archive at the specified location.
- @dest
- The location in the archive for the generated file.
- @encoding
- The character encoding to use for the contents of the generated file. Optional. If
not specified, the configuration's
defaultContentEncoding
property is used.
For example, the following code will generate a /COPYRIGHT.txt
file
in the bundle using the current year:
<@package.generate dest="/COPYRIGHT.txt"> Copyright (c) ${.now?string.yyyy} Titania Software. All rights reserved. </@package.generate>
<@package.generateDoc>
Similar to <@package.generate> but instead generates a file using Freemarker that will contain/represent the content of the document. Many document types, like XML documents, should not be included in a package as-is. Instead, it should be wrapped in a page containing branding and navigation.
- @document
- The
PackageDocument
instance whose page to generate. The location in the archive will be determined by theconfig.json
file'sdocLocator
orcontextualizedDocLocator
patterns. - @encoding
- Optional. The character encoding to use for the content of the file. If not
specified, the configuration's
defaultContentEncoding
property is used.
<@package.docContents>
Used for inserting a textual, XML, or HTML document within the context of a <@package.generateDoc> or <@package.generate> directive. This is similar to the <@td.content> directive for online templates, adapted for package use.
- @document
- Required. The document instance to insert.
- @expandReferences
- A boolean indicating whether references to other documents should be rendered
inline; primarily for use with DITA maps. The default is
false
. - @installMedia
-
A boolean indicating whether referenced media should be installed in the archive. The default is
true
. Specifically, the HTML will be scanned for the following elements and attributes:-
img/@src
(images) -
video/@src
-
audio/@src
-
source/@src
-
object/@data
When generating the HTML representation of content, any references in the source should be left unchanged. The packager will automatically rewrite these HTML references to use the appropriate relative URI in the package.
This works in addition to the packager XSLT function
package:mediaReference()
function described below. -
- @storeResult
- If set to
false
, the rendered output will not be stored in the system cache. The default istrue
. - @timeout
- Optional. Set the XSLT transformation timeout in milliseconds.
- @xsl
-
If the content is XML, this directive will specify the XSL transformation in which to pass the content through. If omitted, the XML will be inserted as-is. If the value begins with a slash (/), it will be considered relative to the
/xsl
directory in the portal theme. Otherwise, it will be considered relative to the packager root directory.
Nested <@package.xslParam> directives may be used to pass parameters to the XSL transformation.
<@package.xslParam>
Used to specify xsl parameters inside a <@package.docContents> directive. This is similar to the <@td.xslParam> directive for online templates.
- @name
- Required. The name of the XSL parameter.
- @value
- The value of the parameter. This can be a string, numeric, boolean, sequence, or hash freemarker value.
<@package.statusMessage>
Updates the status message of the offline package request with the rendered directive contents. The status message may be displayed in the status window as the package is being prepared.
<@package.log>
Writes a log message to the freemarker template output. Log messages will only be written if the level specified in the directive attribute is at or above the log level configured in the packager.
- level
- The log level at which to write the message. The allowed values are, "DEBUG", "INFO", "WARNING", or "ERROR". If not specified, defaults to "INFO".
Functions
package.relativeUri(to[, from])
Used within <@package.generate> or <@package.generateDoc>, this function determines the relative URI to the given package location from the given source location.
-
to
- Required. The object being referred to. This can either be a string containing the
target path within the package, or a
PackageDocument
object, in which case the configuration's @docLocator will be used to determine the target location. -
from
- Optional. The package location to use as the base when generating the relative URI.
If from
is omitted, the current location (as specified by the parent
<@package.generate> or
<@package.generateDoc> directive) is used.
<a href="${package.relativeUri('/index.html')?html}">Link</a> <a href="${package.relativeUri(doc)?html}">${doc.metadata['title'][0]?html}</a> <img src="${package.relativeUri('/static/images/logo.png')?html}">
package.getDocLocation(doc)
This function returns the default location in the archive for the output artifact
corresponding to the given input document, as calculated using the rules in
config.json
.
-
doc
- The
PackageDocument
instance whose output location to retrieve.
package.setStatusMessage(message)
This is a functional version of the <@package.statusMessage> tag; updates the current status message for the package as it executes.
Variables
package.currentPackageLocation
When inside a directive that is writing to a location in the package, like <@package.generate> or <@package.generateDoc>, this variable contains the location of the entry in the output archive.
package.hexSignatures
When digital signing is enabled, this variable will contain a map of digital signatures generated for files placed into the package. The key in the map is the location in the package of the files that have been generated so far; the values are the digital signatures for those files, as hex-binary strings.
package.base64Signatures
When digital signing is enabled, this variable will contain a map of digital signatures generated for files placed into the package. The key in the map is the location in the package of the files that have been generated so far; the values are the digital signatures for those files, as Base64-encoded binary strings.
package.signaturesXmlDoc
When digital signing is enabled, this variable will hold a DOM Document representing an XML Signatures file in the EPUB signature format for all files in the package (so far). This document can be manipulated using Freemarker's XML processing APIs. For example, the XML could be serialized to the package using instructions like the following:
<@package.generate dest="META-INF/signatures.xml"> ${package.signaturesXmlDoc.@@markup} </@package.generate>
5.4: Packager XSLT Support
Parameters
-
td.online
andtd.offline
- Boolean parameters passed by the <@package.docContents>
directive.
td.online
will always be false andtd.offline
will always be true. These parameters will also be passed to templates used by the online <td.content> tag, where the reverse values will be used. This will allow the use of common XSLT modules for both online and offline. -
td.packageLocation
- The package folder path containing the file being written in the package from the primary output of the stylesheet. Any secondary result documents will be written to the package relative to this location.
-
td.packager
- The name of the packager.
Functions
The following functions are all in the
http://www.titaniasoftware.com/xmlns/td-packager
name space.
-
package:relativeUri(to[,secondaryFromLocation])
function -
Essentially the same as
package.relativeUri()
in the Freemarker Functions list. Determines a relative URI to the specified location, exceptto
is always a string. The optionalsecondaryFromLocation
argument specifies the location of the current secondary result document relative to the primary output (given by thetd.packageLocation
parameter). An emptysecondaryFromLocation
argument will be ignored.When TD processes an XML document, it normalizes all references into URIs of the form
harp://stuffIdentifyingTheDocument
orpuckditaxref:referenceId
. If the specified target is one of those formats, this function will determine the location of the specified document in the package, and use the package configuration to determine the target URI. Otherwise, the path should be an absolute location within the archive.<xsl:template match="xref[@scope='local' and @format='dita']"> <a href="{package:relativeUri(@href)}"> <xsl:apply-templates/> </a> </xsl:template>
The following example illustrates how
package:relativeUri()
can be used while creating a secondary result document.<xsl:variable name="result-doc" select="concat('sub/doc',position(),'.html')"/> <xsl:result-document href="{$result-doc}" method="html"> <xsl:apply-templates> <xsl:with-param name="doc-href" tunnel="yes" select="$result-doc"/> </xsl:apply-templates/> </xsl:result-document> <xsl:template match="xref[@scope='local' and @format='dita']"> <xsl:param name="doc-href" tunnel="yes"/> <a href="{package:relativeUri(@href,$doc-href)}"> <xsl:apply-templates/> </a> </xsl:template>
-
package:mediaReference(href[,secondaryFromLocation])
function - This will determine the packaged location of the referenced media object, add the
media object to the archive if necessary, and return a relative path to the media
object. The optional
secondaryFromLocation
argument specifies the location of the current secondary result document relative to the primary output (given by thetd.packageLocation
parameter). An emptysecondaryFromLocation
argument will be ignored.<xsl:template match="image"> <img src="{package:mediaReference(@href)}"/> </xsl:template>
Important: Stylesheets making use of this function should always be called by passingstoreOutput=false
and/orignoreCache=true
on the <@package.docContents> directive. Otherwise subsequent renderings for the same input will not add the media to the archive.
Other XSLT Processing Details
The following XSLT constructs behave slightly differently when being used in the context of <@package.docContents>.
-
document()
function - The
document()
function is a built-in XSLT function for reading an XML document. In the context of the packager, attempts to open aharp://
orpuckditaxref:
URL will attempt to read the referenced TD document. - <xsl:result-document>
- The <xsl:result-document> element will write its contents to some location other than the default XSLT output. When used within a packager, the result will be an entry in the package. In this way, package developers can "burst" a single XML document into multiple package artifacts.
5.5: Offline Package Management API
Freemarker Directives
The following Titania Delivery tags are available for managing packages in the portal.
- <@td.offlinePackages>
- Analogous to
HARPPortal.listPackages()
, this directive lists the packages requested by the current user and stores them in a variable.- @var
- The variable to hold the list.
- @startPage
- The page number to return.
- @limit
- The max number of results to return. Must be a positive integer n where 0 < n <= 2147483647.
- @anonymous
- Whether to return the list of anonymous packages or those for the current user. The default is 'false'.
- <@td.offlinePackageDownloadUrl>
- Retrieves the download URL for an offline package, either inline in the page or in
a variable.
- @package
- The package whose URL to load. Either this or the @key attribute must be specified.
- @key
- The key of the package whose URL to load. Either this or @package must be specified.
- @var
- The variable in which to store the URL. If not specified, the URL is output to the page.
Javascript APIs
The HARPPortal
Javascript library will have new methods for managing
offline packages.
-
requestPackage(request: PackageRequest, [anonymous: boolean]): Promise<PackageInfo>
-
Requests a package be created using the info in the given request. The package will be private to the currently-authenticated user unless
anonymous
istrue
. This will send an HTTP POST request to the new URL endpoint/portals/rpc/{portalPath}/offline/request
containing the JSON representation of thePackageRequest
object.
-
getPackageStatus(key: string): Promise<PackageStatus>
- Requests the status of the given package key. The result will be one of
"QUEUED"
,"WORKING"
,"FINISHED"
, or"FAILED"
. -
getPackageInfo(key: string): Promise<PackageInfo>
- Retrieves details about the given package.
-
getPackageDownloadUrl(key: string): string
- Retrieves the URL from which the finished package can be downloaded.
-
getPackageHashUrl(key: string[, format: string = 'sha512']): string
- Retrieves the URL of the SHA-512 checksum of the finished package. The optional
format
parameter can be one of the following:-
sha512
- The hex representation of the checksum, followed by the filename. This is the default.
-
binary
- The raw binary bits of the digital checksum.
-
hex
- A hex-encoded string of the checksum.
-
base64
- A base64-enoded string of the checksum.
-
-
getPackageSignatureUrl(key: string[, format: string = 'binary']): string
- Retrieves the URL of the digital signature for the finished package, if available.
The
optional
format
attribute can be one of the following:-
binary
- The raw binary bits of the digital signature. This is the default behavior.
-
hex
- A hex-encoded string of the signature.
-
base64
- A base64-enoded string of the signature.
-
-
deletePackage(key: string): Promise<boolean>
- Deletes the package with the given key.
-
listPackages(anonymous: boolean): Promise<PackageInfo[]>
- Lists the currently-authenticated user's packages. If not logged in, or
anonymous
is set totrue
, packages created by anonymous users are listed. Otherwise, only packages created by the currently-authenticated user are listed.
Javascript Data Structures
The data structures used by these methods are defined as follows, using TypeScript syntax.
class PackageRequest { packager: string; parameters: {[key: string]: any}; documents?: PackageRequestDocument[]; search?: string; includeContextualizedTopics?: boolean; // true by default ignoreCache?: boolean; // false by default signContents?: boolean; // false by default signaturePathPrefix?: string; signaturePathSuffix?: string; signatureAlgorithm?: string; makeXmlSignatures?: boolean; } class PackageRequestDocument { projectKey: string; itemKey: string; contextKey?: string; refId?: string?; } class PackageInfo { key: string; portalKey: string; packager: string; createdBy: string; createDate: number; // Epich timestamp documents: PackageDocument[]; params: {[key: string]: any}; status: PackageStatus; statusMessage: string; filename: string; mimeType: string; scriptOutput: string; hash: string; // Hex string of the SHA-512 hash signature: string; // Hex string of the digital signature, if any } enum PackageStatus { QUEUED, WORKING, FINISHED, FAILED }
PackageRequest
Properties
-
packager
- The packager to execute. This will be the name of the folder beneath the
packagers
folder in the portal theme containing thepackager.ftl
entry point. -
parameters
- A map of parameters that control various aspects of package generation, accessible
from within the packager execution via the
parameters
variable. -
documents
- The documents to include.
-
search
- A search string; the results of the search will be packaged.
Note: If neither
search
nordocuments
are specified, all documents in the portal will be packaged. If both are specified,search
takes precedence. -
includeContextualizedTopics
- When packaging compound documents, like DITA maps or chunked non-DITA XML files, the
search
ordocuments
need only specify the root documents and set this totrue
to capture the root document and all of its component topics. -
ignoreCache
- Generated package contents are typically cached to improve performance for
subsequent re-generation of the package; setting this to
true
skips that caching. -
signContents
- Whether to automatically generate and store side-files containing digital signatures
of each file in the package. If set to
true
, one or both ofsignaturePathPrefix
andsignaturePathSuffix
must be specified or no signatures will be added to the package. This isfalse
by default. -
signaturePathPrefix
- A string to prepend to the paths for digital signature side files, commonly used to
put signatures in their own root-level folder in the package. For instance, set to
/signatures/
to create a mirror of the package folder structure beneath thesignatures
folder for digital signatures. This is blank by default. -
signaturePathSuffix
- A string to append to file paths for digital signature side files. This is
.signature
by default, meaning signature files will be in the same folder as the file they're signing, with a.signature
extension. -
signatureAlgorithm
- The signature algorithm to use to generate digital signatures of the package itself
and its contents. Must be one of the following values:
-
SHA512withRSA
(default) -
SHA384withRSA
-
SHA256withRSA
-
SHA224withRSA
-
SHA1withRSA
-
-
makeXmlSignatures
- If set to
true
, the packager will build up an XML document that contains digital signatures for each file in the package. This document is available via thepackage.signaturesXmlDoc
variable and can be inserted into the package using Freemarker code like this:<@package.generate dest="META-INF/signatures.xml"> ${package.signaturesXmlDoc.@@markup} </@package.generate>
Sample Javascript Code for Requesting a Package
For example:
HARPPortal.requestPackage({ packager: 'WebHelp', parameters: { title: 'My Fancy WebHelp Package' }, documents: [ 'harp://blahblahblah', {projectKey: 'abc', itemKey: '123'} ] }).then(checkStatus); function checkStatus(info) { switch(info.status) { case 'QUEUED': case 'WORKING': console.log('Current status is ' + info.status + '. Checking again in 5 seconds.'); setTimeout(function() { HARPPortal.getPackageInfo(info.key).then(checkStatus); }, 5000); return; case 'FAILED': alert('Packager failed.\n' + info.scriptOutput); return; case 'FINISHED': if (confirm('Package completed. Download?')) { window.open(HARPPortal.getPackageDownloadUrl(info.key)); } return; } }
JSON HTTP Endpoints for Package Management
-
POST
/portals/rpc/portalPath/offline/request[?anonymous=true]
- Requests the creation of a portal. The response will be a JSON document describing
the
package. The result is a
PackageInfo
document. Use theanonymous
query parameter to request a public package not associated with the current user. -
DELETE
/portals/rpc/portalPath/offline/packageKey
-
POST
/portals/rpc/portalPath/package/packageKey/delete
- Deletes the specified package.
-
GET
/portals/rpc/portalPath/offline/packageKey/status
- Requests the status of the given packager. The return value will be a JSON string
containing one of the following values:
-
"QUEUED"
-
"WORKING"
-
"FINISHED"
-
"FAILED"
-
-
GET
/portals/rpc/portalPath/offline/packageKey/info
- Returns a
PackageInfo
document describing the package. Some fields will not be present for some statuses. -
GET
/portals/rpc/portalPath/offline/packageKey/download
- Downloads the package, if it is in the FINISHED state. Otherwise callers will receive
a JSON document containing a
"error"
or"message"
keys describing the reason for the refusal. -
GET
/portals/rpc/portalPath/offline/list[?anonymous=true]
- Lists the
PackageInfo
objects created by the currently-authenticated user. use theanonymous
query parameter to request anonymous packages even if logged in. -
GET
/portals/rpc/portalPath/offline/packageKey/hash
- Retrieves the SHA-512 checksum of the package. This parameter takes an optional
format
URL parameter which can have one of the following values:-
sha512
- The hex representation of the checksum, followed by the filename. This is the default.
-
binary
- The raw binary bits of the digital checksum.
-
hex
- A hex-encoded string of the checksum.
-
base64
- A base64-enoded string of the checksum.
-
-
GET /portals/rpc/portalPath/offline/packageKey/signature
- Retrieves the digital signature of the package, if any. This endpoint takes an
optional
format
URL parameter which can have one of the following values:-
binary
- The raw binary bits of the digital signature. This is the default behavior.
-
hex
- A hex-encoded string of the signature.
-
base64
- A base64-enoded string of the signature.
-
5.6: Offline Search Support
Overview
One major disadvantage to offline browsing is that users cannot use the features provided by the TD search engine, like full-text or faceted search. However, there are some document formats that may want a specially-formatted index file or files to enable search in the archive's viewer.
The PackageDocument
object has a textContents
property
that can be used to extract the textual contents of the file without any markup or
styling,
primarily for building a full-text index.
Building the search index
The Freemarker template, packagers/common/search-index.ftl
, will
prepare lunr.js
indexes (in multiple languages) of text content in
package documents.
In addition to the normal package variables, this page uses the following Freemarker variables to communicate with the template process.
- docsToIndex
- A sequence of package documents to index. This could be used to exclude certain package documents, such as large PDF documents, from indexing. Defaults to package documents list.
- lunrLangScripts
- A sequence of
lunr-languages
source file names that must be loaded in the browser to support searching.
This template uses <@package.generate>
to load required libraries
from lunr.js
and lunr-languages
into Nashorn script
engine, then runs the lunr
indexer to build search indexes for specified
package documents. For each document to be indexed:
- The document language is identified from document metadata locale (preferably) or lang fields.
- Determine if language can be indexed. Since
lunr-languages
does not handle regional variants, only 2-letter language codes are considered. Only Chinese language codes indicating Simplified Chinese (zh-CN
,zh-SG
,zh-HANS
) are handled. - Group documents by language, for more efficient indexing.
- Load needed javascript source files to handle languages.
After grouping the documents by language (omitting documents in unhandled languages),
the
index is built. The indexing function is defined in
packagers/scripts/server/search-index.js
The result of the indexing process is a javascript snippet that defines a structure
containing the lunr.js
indexes (in all applicable languages) and minimal
document metadata to support navigation to documents returned from searches. This
snippet is
print
ed to the template content.
Indexing a large multi-lingual document collection can take several minutes. Since TD version 4.2, indexing progress will be updated in the package status dialog. (Prior to 4.2, only the start of indexing will be shown in the status dialog.) Indexing Simplified Chinese documents is particularly slow.
Browser searching
The utility template, helpers/searchHelpers.ftl
will write the
required <script> elements into the HTML page heads, and add search
input control and page division for displaying search results.
The script, scripts/browser-search.js
, executes the search and formats
the results. The results will show a snippet of the document with search hits highlighted.
Since lunr.js
will in many cases return only the stemmed token that
scored the hits, the script tries to find complete words that match the token. This
process
is not completely accurate, but normally will show several valid variants of the stem
token
that produced the hit. In some cases, there is no match found, and the snippet will
be
empty.
Chapter 6: Portal Parameters
config.xml
file at the root level of the theme.6.1: Authoring config.xml
config.xml
file allows portal theme developers to parameterize
portal themes with settings that can be set when the theme is associated with a
portal.The structure of this files is as follows.
Groups
The input configurations are organized into <group> elements. In the User Interface, each group will be rendered as a tab using the group's @label attribute.
Parameter Descriptor Elements
- <string>
- A simple string, without line breaks.
- <password>
- A password or other secret string value. This value will never be displayed in the admin interface, and will be masked when it is modified.
- <text>
- larger amounts of text, with three possible formats
-
@type="html"
- Text is interpreted as HTML code. -
@type="markdown"
- Text is converted to HTML using Markdown rules. -
@type="text"
- Any HTML characters are escaped.
Note: While you almost always should escape strings displayed on portal pages using the?html
directive, you should not do this for <text> parameters, as the appropriate HTML markup will already be built as the value of the parameter. -
- <number>
- A numerical value.
- <checkbox>
- A boolean value.
- <select>
- Enables the user to select a value from a list of possible values. A select element
will have one or more <option> child elements listing the
available values. In addition, the @multi attribute is used to describe
whether multiple values may be selected.
-
@multi="true"
- Select an array of options (including order) from a set -
@multi="false"
- Select a single option from a set (the same effect can be achieved by omitting the@mutli
attribute)
-
- <themeFile>
- Enables the user to select a file from a specific folder in the portal theme. This
is
similar to <select> except that the available
<option> values are derived from the files beneath the
specified folder. Attributes:
- @dir
- The directory path in which to search for files, relative to the folder implied by the @type attribute.
- @type
- Controls the type of file being listed, which controls the base folder for the
@dir attribute as well as how the value is provided when requested.
-
customPage
- Relative to
/pages/custom
. The value provided to portal pages will be suitable for use with the <@td.pageUrl> tag. -
static
- Relative to
/static
. The value provided to portal pages will be suitable for use with the <@td.themeFileUrl> tag. -
xsl
- Relative to
/xsl
. The value provided to portal pages will be suitable for use with the <@td.content> tag's @xsl attribute.
-
- <linkList>
- A container for <link> elements describing links to be displayed somewhere in the UI. Each <link> element carries @href, @label, and @target attributes describing the link to be rendered.
In addition to these inputs, the <instructions> element can be inserted anywhere within a <group> or as the first child of any input. Instructions will be rendered as user-visible text in the form.
Parameter Attributes
All parameters require a @name
attribute which is used to access
them from the Freemarker templates. The @label
attribute is also
recommended and supplies an external label for the parameter that is shown when the
form is
rendered. Authors can hide a parameter (and force each portal to use its default value)
by
setting the @hidden
attribute to true
.
Default Values
The @default
attribute is used to define default values for parameters
(excluding those of type text
, select
, and
linkList
). Defaults for select
elements are define by
setting the @default
attribute on the options desired within the
select
tag. Defaults for text
elements are defined by a
separate <default>
tag within the <text>
tag. The
@default
attribute should be included if possible when writing your
config.xml
, but is not required.
Using Parameters
These parameters must be defined in config.xml
, but may be used anywhere
in the portal theme. Access to these parameters is gained by using the
parameters
collection on the portal
object. For example,
if using a parameter named "stylesheet", it would be accessed with the syntax
portal.parameters.stylesheet
.
<link rel="stylesheet" href="<@td.themeFileUrl value="${portal.parameters.stylesheet}" />"/>
Parameter Configuration DTD
<?xml version="1.0" encoding="UTF-8"?> <!-- =============================================================== --> <!-- Titania Delivery Portal Theme Parameter Descriptor --> <!-- Describes a portal theme's parameters and the User Interface --> <!-- used to populate their values. --> <!-- --> <!-- <!DOCTYPE parameters PUBLIC --> <!-- "-//Titania//DTD Portal Theme Parameter Configuration 1.0//EN" --> <!-- "theme-param-config.dtd"> --> <!-- =============================================================== --> <!ENTITY % commonAtts-nodeflt "name ID #REQUIRED label CDATA #IMPLIED hidden (true|false) 'false' tooltip CDATA #IMPLIED" > <!ENTITY % commonAtts "%commonAtts-nodeflt; default CDATA #IMPLIED" > <!ELEMENT parameters (group)+> <!ELEMENT group (string | text | number | checkbox | select | themeFile | linkList | instructions )*> <!ATTLIST group label CDATA #REQUIRED > <!ELEMENT string (instructions?)> <!ATTLIST string %commonAtts;> <!ELEMENT text (instructions?, default)> <!ATTLIST text %commonAtts-nodeflt; type (text | markdown | html) 'text' > <!ELEMENT default (#PCDATA)*> <!ELEMENT number (instructions?)> <!ATTLIST number %commonAtts;> <!ELEMENT checkbox EMPTY> <!ATTLIST checkbox %commonAtts;> <!ELEMENT select (instructions?, option+)> <!ATTLIST select %commonAtts-nodeflt; multi (true|false) 'false' > <!ELEMENT option (#PCDATA)> <!ATTLIST option default (true|false) 'false' value CDATA #IMPLIED > <!ELEMENT themeFile (instructions?)> <!ATTLIST themeFile %commonAtts; type (customPage | static | xsl) #REQUIRED dir CDATA #IMPLIED > <!ELEMENT linkList (instructions?, link*)> <!ATTLIST linkList %commonAtts-nodeflt; > <!ELEMENT link EMPTY> <!ATTLIST link href CDATA #REQUIRED label CDATA #REQUIRED target (_blank|_self) '_blank' > <!ELEMENT instructions (#PCDATA)*>
6.2: Example Portal Parameter Configurations
Portal Display Name and Description
<string name="title" label="Portal Display Name"/> <text name="description" label="Portal Description" type="markdown"> <default> <![CDATA[Welcome to *Titania Delivery*!]]> </default> </text>
This sample defines two portal theme parameters, title
and
description
, which can be used to provide a site-wide label and homepage
description for the portal. The matchinf form would look something like this:

The values could be used in the portal theme pages via Freemarker like the following:
<h1>${portal.parameters.title?html}</h1> <div>${portal.parameters.description}</div>
?html
directive, you should not do this for
<text> parameters, as the appropriate HTML markup will already be
built as the value of the parameter.Configurable Styling Details
<themeFile name="stylesheet" label="Stylesheet" type="static" dir="style/main" default="default.less"/> <text name="css" label="Custom CSS" type="html"/> <themeFile name="siteLogo" label="Site Logo" type="static" dir="images/logos" default="harp_128.png"/> <themeFile name="header_bg" label="Header Background Image" type="static" dir="images/backgrounds" default="orange-arch.jpg"/>
This sample provides four parameters.
-
stylesheet
- This lists all of the files in the
static/style/main
folder of the theme for the user to select from. -
css
- This provides a textbox allowing the administrator to add some custom CSS code that can be injected on every page.
-
siteLogo
- This lists all of the files in the
static/images/backgrounds
folder of the theme for the user to choose from. This could be used as a logo on the homepage and/or in the header of every page. -
header_bg
- This lists all of the files in the
static/images/backgrounds
folder. This could be used as the background for the banner at the top of the homepage, and/or the background of the header.

You can use these parameters in the theme as follows:
<!DOCTYPE html> <html> <head> <title>Portal Title (probably also a parameter)</title> <link rel="stylesheet" href="'<@td.themeFileUrl value=portal.parameters.stylesheet/>"> <style> ${portal.parameters.css} </style> </head> <body> <div style="background: url('<@td.themeFileUrl value=portal.parameters.header_bg/>');"> <img src="<@td.themeFileUrl value=portal.parameters.siteLogo/>"> <h1>Site Title</h1> </div> </body> </html>
Multi-Select
The following markup enables users to specify the available sections on a homepage, and to sort them into a particular order.
<select name="homepage-modes" label="Homepage Sections" multi="true"> <option default="true" value="document-lists"> Recently Modified Document Lists </option> <option value="onemap-circles"> Single DITA Map with Circular Graphics </option> <option value="multimap-divs"> Multiple DITA Map as Page Divisions </option> </select>
This is rendered as follows, allowing the end user to use drag-and-drop to add/remove sections, as well as sort them.

The parameter value is the array of selected values. From a portal theme page, you can use this parameter as follows:
<#list portal.parameters['homepage-modes'] as mode> <#if mode = 'document-lists'> <#include 'document-lists.ftl'/> <#elseif mode = 'onemap-circles'> <#include 'onemap-circles.ftl'/> <#elseif mode = 'multimap-divs'> <#include 'multimap-divs.ftl'/> </#if> </#list>
Chapter 7: Portal Pages
7.1: Content-Security-Policy and Portal Pages
Content Security Policy (CSP) is a W3C recommendation for specifying restrictions on how browsers should handle potentially dangerous components in an HTTP response entity. As of this writing, 2 levels of the recommendation are available.
- CSP Level 2 (recommendation 2016-12-15)
- CSP Level 3 (working draft; many features implemented in modern browsers)
By default, the TD platform does not include any Content-Security-Policy HTTP headers on portal pages. If your corporate security guidelines require CSP directives on your TD portal pages, here are some options.
Adding CSP header to portal pages
The portal theme provides the ability to add <meta> tags to the <head> element of any HTML page generated by the portal. One way to deliver CSP headers to the browser is by adding a <meta> tag like:
<meta http-equiv="Content-Security-Policy" value="{your-csp-here}"></meta>Replace
{your-csp-here}
with the actual policy desired.
http-equiv
<meta> tags may be superseded by HTTP CSP headers added to the
response.If all portal pages on a site should be subject to the same CSP, contact Oberon Support to add the desired CSP to the site settings. This policy will be delivered as the Content-Security-Policy HTTP header on all portal pages.
Generating CSP-compliant portal pages
The portal theme developer is responsible for ensuring that all pages generated in the portal comply with the effective CSP.
When a Content-Security-Policy is in effect for a web page, disallowed components
in the page
will be disabled. This could affect the appearance, behavior, and usability of the
web page.
Disallowed unsafe-inline
and unsafe-eval
script and style
sources are a common cause of problems. Many TD portal themes now in use violate these
policies
(including the built-in and provided themes, as well as custom themes derived from
them).
Before implementing strict CSP on portal pages, review and test the portal theme to
find and
remove components that would violate the intended CSP. For example, if the CSP includes
script-src 'self';
, then <script> elements and script
attributes will be disabled. Any part of the theme that generates these elements
and attributes
must be modified.
Any theme that relies on TD XSLT modules for transforming XML to HTML could generate
inline
style elements and attributes in a portal page. These will be disallowed by CSP unless
the
policy includes style-src 'self' 'unsafe-inline';
. The impact on portal page
display will range from minor to severe. In cases where style unsafe-inline
is
not allowed, significant changes may be required to over-ride the built-in XSLT stylesheets
to
eliminate inline styles.