For the next post in my “eat your own dog food” series, I want to talk about one of our uses of the nuxeo-template-rendering module for the internal “Techlead report”.

(Check out the first post in the series: A Simple Workflow for the Human Resources Department.

About the Techlead report

The Techlead report is an on going institution at Nuxeo that everyone reads to keep up to date on what is happening, from the pre-sales team to the CEO, to the developers and the support team. Laurent also publishes minutes of the report on this blog - you may have read it already.

Approximately once every two-three weeks, all the developers meet Thierry D. and Florent, CTO and Director of research and development respectively, to discuss what they are working on, both on the product implementation side and on the customer consulting side. During this meeting we gather all the technical challenges that the platform meets so as to prioritize the evolution - try to find new solutions to old problems, find some help on which angle to take on a new module implementation, and so on…

Thierry writes down the minutes of each discussion and every two-three weeks produces the “Techlead report." As you can guess, it's very long and the challenge was to get something “light” to read and easy to browse, while staying easy to author. Its format has evolved quite a bit in the past years: a simple mail, a Nuxeo “Blog Post”, a bare Note document type.... The last format, a Note document type, written in Markdown, with a website generated using the nuxeo-template-rendering module has been there for long enough to let us think we finally found the right recipe. :)

Using Nuxeo Drive

Thierry writes the global report content using his favorite text editor (no troll here, I won’t give the name) and it's automatically synchronized as a Note document type in the intranet using Nuxeo Drive. Thanks to Nuxeo Drive, Thierry can work on the report at any time, anywhere and the content of the report is always synced in the intranet.

Markdown format support on Nuxeo Platform

Thierry writes the global report content using the Markdown syntax. This syntax is easy to read: you barely need a rendering engine to understand the “format” the author wanted to display. Of course, you still want bold, titles, subtitles, etc... in the end. :) Nuxeo supports the Markdown format on its Note document type, and can act as a rendering engine for Markdown syntax.

You can test it by creating a Note and choose “Markdown”, in the syntax field. Then type the following string: “

This is a title

This a subtitle

  • and this is a bullet point
  • and another bullet point with some bold text.

and save.

You can see that Nuxeo automatically displays on the summary tab of the Note correctly formatted content. Yet, if the content is too long, the “summary tab” of Nuxeo is probably not the best option, plus it doesn’t allow you to browse among all the sections.

Another available option is to download it as a PDF, with correct formatting of the content (the markdown rendition is automatically integrated to the pdf conversion by the converter system of the platform). Still, being on the browser and then being redirected to another application (namely a PDF reader) is not 100% great in terms of flow.

Using the Nuxeo Template Rendering module

Thierry thought of using the nuxeo-template-rendering module to generate, on-the-fly, an autonomous website, based on the markdown Note content. The result is the following website, where users see an index of all the sections and subsections on the left, and can click on each subsection.


The first time Thierry creates the document in Nuxeo, he clicks on the “bind template” user action (on the top right bar of actions) and chooses the “Techlead report template”. The template had previously been created as a document under the Template folder, at the root of the domain.

The template document holds:

  • A main file, the freemarker template that will generate the website.

  • JavaScript/CSS resource files, used by the generated website.

  • Configuration properties.

  • A filter to set which Nuxeo document types it use.

  • The rendering engine to use, i.e. freemarker in this case (There are many others, like xdoc for renditions based on .doc files, jod for open office documents, jxl for Excel files, XSL/FOP - the platform allows you to contribute other rendition engines).

  • Variable replacement logic. The freemarker template below contains the variable @{htmlContent}. This variable must be referenced as a parameter on the Nuxeo Template. The nuxeo-template-rendering module handles several kinds of parameters: string, date, boolean, document property, image, inclusion. String, date and boolean include static values. Document propriety allows you to dynamically add the value of a property of a document. Image includes a picture, and inclusion is used for other kinds of content inclusion. For our use case, we use inclusion, and more specifically, HTML Preview - we include in the freemarker template the generated html preview (that will be tweaked by the JavaScript libraries that are added). Since there is a bug setting it on the template, the parameter is set specifically on the document, on the template parameters tab.

  • The “rendition” from which the result of the rendering engine is made accessible - Webview in our case.

In the end, a fixed URL can be used to provide access to the dynamically generated website:


This URL is accessible on the summary tab:


Get your hands dirty
If you want to try, you can:

  • Install the nuxeo-template-rendering module on your server, from the marketplace

  • Download this zip, and drop it in the Template folder of your Nuxeo instance. It will automatically create the required template.

  • Create a note with some markdown content (don’t forget the little selector for Markdown).

  • Bind this note to the newly created template.

  • Set the htmlContent parameter (selecting Include > HTML Preview) and save.

To go further

The FreeMarker Template

<title> ${doc.title} </title>
<meta name="title" content="${doc.title}"/>
<meta name="description" content="${doc.dublincore.description}"/>
<meta name="author" content="${doc.dublincore.creator}"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link class="component" href="${jaxrs.getResourceUrl("jquery.tocify.css")}" rel="stylesheet" type="text/css" />
<link class="component" href="${jaxrs.getResourceUrl("bootstrap.css")}" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="${jaxrs.getResourceUrl("jquery-1.8.3.min.js")}"></script>
<script type="text/javascript" src="${jaxrs.getResourceUrl("jquery-ui-1.9.1.custom.min.js")}"></script>
<script type="text/javascript" src="${jaxrs.getResourceUrl("jquery.tocify.js")}"></script>
body {
padding-top: 20px;
p {
font-size: 16px;
.headerDoc {
color: #005580;
.tlHeader {
padding : 10px;
background-color : #F8F8FA;
@media (max-width: 767px) {
#toc {
position: relative;
width: 100%;
margin: 0px 0px 20px 0px;
<div style="float:right">

<div class="container-fluid">
<div class="row-fluid">
<div class="span3">
<div id="toc">
</div><!--/.well -->
<div class="span9">
<div class="hero-unit">

$(function() {
var t = $("h1")[0];
var p = t.parentNode;
$("h2,h3").css({borderWidth : "0px 0px 1px 0px", borderStyle : "solid", borderColor : "#CCCCCC", paddingTop : "5px", paddingLeft : "5px"});
$("h4,h5,h6").css({paddingTop : "5px"});