Offline Packagers

An Offline Packager is a collection of files containing the rules for building a ZIP archive from the documents in a Titania Delivery portal.

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>