08 Printouts - Handlebars
SRS supports the Handlebars templating engine. Template files should be stored in the /templates directory of the application.
Execute
To execute a Handlebars template, use the following API:
HTTP /api/srs/{id}/{template-name}.hbs.html
To create a new template with basic helpers: srs_administrator
HTTP /api/srs/{id}/_new.hbs.html
You can also use the following extensions:
.hbs.html - HTML
.hbs.pdf - PDF
.hbs.csv - CSV
.hbs.txt - plain text
.hbs.xml - XML
.hbs.epp - EPP
.hbs.svg - SVG
Example data object
JavaScript {
dataset0 : { // object
"field0" : "some test <b>test</b>" ,
"field1" : "some test2" ,
"field2" : "some test3"
},
dataset1 : [ // array
{
"field0" : "some text4" ,
"field1" : "some text5" ,
"field2" : "some text6"
}
],
dataset2 : [] // empty array
}
Handlebars FAQ
Built-in functions
isArray — checks whether a value is an array
Text Only {{#if (isArray this)}}
...
{{/if}}
fnAdd — adds a number (useful for 1-based index display)
Text Only {{#each items}}
{{fnAdd @index 1}}
{{/each}}
fnSum — sums all values in a column of a dataset
isEqual — compares two values for equality; useful for cross-dataset filtering
Text Only {{#each items}}
{{#each ../files}}
{{#if (isEqual this.commisionID ../commisionID)}}
<img src="data:image/png;base64,{{path}}" />
{{/if}}
{{/each}}
{{/each}}
get — retrieves a property value from an object by key name
Text Only {{get commandname "ret"}}
{{get srstranslation "ret"}}
When inside a loop, escape the dataset reference with ../:
Text Only {{#each items}}
<div>{{get ../srstranslation label}} {{label}}</div>
{{/each}}
Variables
@index Current iteration index (0-based)
@key Current key (for object iteration)
@first true on first iteration
@last true on last iteration
@length Total number of items in the array
Example:
Text Only {{#each items}}
<div {{#unless @last}}class="break"{{/unless}}>
Hello
</div>
{{/each}}
Iterate datasets
Text Only {{#each this}}
<li>{{@key}}</li>
{{/each}}
IF in Handlebars
Text Only {{#if dataset2}}
NOT VISIBLE - array is empty
{{/if}}
{{#if dataset0}}
VISIBLE - object is not empty
{{/if}}
Text Only {{#unless isValid}}
{{/unless}}
{{! You can also use {{else}} inside {{#if}} or {{#unless}} blocks }}
Raw text in Handlebars
Text Only raw (unescaped HTML): {{{dataset0.field0}}}
html-escaped: {{dataset0.field0}}
Generate CSV
Replace the space separator with any character, e.g. comma: {{#unless @last}},{{/unless}}
Text Only {{#each api}}
{{#each this}}{{{this}}}{{#unless @last}} {{/unless}}{{/each}}
{{/each}}
Includes (images)
There are two ways to include images in a Handlebars template.
Direct reference to storage
Include images from any storage location using [[ and ]] tags:
HTML < img src = "data:image/png;base64,[[/api/core/storage/get/www/images/logo.png]]" />
SRS data object
Include images from the SRS data object using the tbase64 column type.
SRS definition:
XML <srs>
<itm model= "column" type= "tbase64" name= "testimg" />
<itm model= "command" opts= "dtsingle" name= "settings" >
select '33d52ff9-9914-923c-10bd-3251ea2db555.png' testimg
</itm>
</srs>
Template:
HTML < img src = "data:image/png;base64,{{{settings.testimg}}}" />
Text Only {{! This comment will not appear in the output }}
Generic table (horizontal)
HTML < table >
<!--START Optional column widths -->
< colgroup >
< col style = "width:20mm" >
< col style = "width:40mm" >
< col style = "width:60mm" >
</ colgroup >
<!--END Optional column widths -->
< thead >
< tr >
{{#each dataset1.[0]}}
< th > {{@key}}</ th >
{{/each}}
</ tr >
</ thead >
< tbody >
{{#each dataset1}}
< tr >
{{#each this}}
< td > {{this}}</ td >
{{/each}}
</ tr >
{{/each}}
</ tbody >
</ table >
Generic table (vertical)
HTML < table >
< tbody >
{{#each dataset1}}
{{#each this}}
< tr >
< td > {{@key}}</ td >
< td >< b > {{this}}</ b ></ td >
</ tr >
{{/each}}
{{/each}}
</ tbody >
</ table >
Template structure
Page size and margins are configured in the @page CSS section
The <header> element is repeated on every page
The <footer> element is repeated on every page
The following jq:page-template-* meta tags are experimental and available in dev versions only. They control background PDF overlays:
jq:page-template-first — applied to the first page
jq:page-template-last — applied to the last page
jq:page-template-all — applied to all pages
HTML <!doctype html>
< html >
< head >
< meta name = "jq:page-width" content = "210mm" > <!--DEFAULT-->
< meta name = "jq:page-height" content = "297mm" > <!--DEFAULT-->
< meta name = "jq:margin-top" content = "10mm" > <!--DEFAULT-->
< meta name = "jq:margin-bottom" content = "10mm" > <!--DEFAULT; use 30mm with a background page-->
< meta name = "jq:margin-left" content = "10mm" > <!--DEFAULT-->
< meta name = "jq:margin-right" content = "10mm" > <!--DEFAULT-->
< meta name = "jq:footer-right" content = "[page]/[topage]" > <!--DEFAULT-->
< meta name = "jq:footer-spacing" content = "0" > <!--DEFAULT; use 19 with a background page-->
< meta name = "jq:page-template-first" content = "/api/core/storage/get/appui/assets/first.pdf" >
< meta name = "jq:page-template-last" content = "/api/core/storage/get/appui/assets/last.pdf" >
< meta name = "jq:page-template-all" content = "/api/core/storage/get/appui/assets/background.pdf" >
</ head >
...
Example background page template: background.docx
Full template example with background image:
HTML <!doctype html>
< html >
< head >
< title > TITLE</ title >
< meta charset = "utf-8" />
</ head >
< body >
< header > HEADER SECTION</ header >
CONTENT
< footer > FOOTER SECTION</ footer >
< style >
@ page {
width : 210mm ;
height : 297mm ;
margin-top : 20mm ;
margin-bottom : 20mm ;
}
/* EXAMPLE: background image */
body {
background : url ( 'data:image/png;base64,[[/api/core/storage/get/appui/assets/images/logo-background.png]]' );
background-repeat : no-repeat ;
background-position : 50 % 300 px ;
background-attachment : fixed ;
background-size : 100 % ;
min-height : 800 px ;
}
</ style >
</ body >
</ html >