Skip to main content

Generic layout and helpers

The following layout and helper examples are not geared towards a specific flow, such as C&C, but instead help you get a good grasp of what they can offer.

You may want to copy and paste them somewhere with a bit more space so you can read their contents easily.

Layout

HTML
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
/* -------------------------------------
RESPONSIVE AND MOBILE FRIENDLY STYLES
------------------------------------- */
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}

/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #34495e !important;
}
.btn-primary a:hover {
background-color: #34495e !important;
border-color: #34495e !important;
}
}
</style>
</head>
<body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">

<!-- START CENTERED WHITE CONTAINER -->
<table role="presentation" class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">

<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">
{#body}
</td>
</tr>
</table>
</td>
</tr>

<!-- END MAIN CONTENT AREA -->
</table>

<!-- START FOOTER -->
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table role="presentation" border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<span class="apple-link" style="color: #999999; font-size: 12px; text-align: center;">Your company here, 221 Baker Street, London, Zip c0d3</span>
</td>
</tr>
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://www.newblack.io" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">EVA</a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->

<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
</tr>
</table>
</body>
</html>

Helpers

Generic helpers
JavaScript
function date(value, format, culture, timezone='Europe/Amsterdam') {
return require('moment-timezone').tz(value, timezone).locale(culture).format(format);
}

// The above helper facilitates date formatting

function padLeft(str, n) {
return Array(Math.max(n-String(str).length + 1, 0) || 0).join(' ') + str;
}

// The above helper facilitates text alignment to the right, by adding padding to the left

function abs(value) {
return Math.abs(value);
}

// The above helper facilitates rounding of a number

function country(countryId, languageId) {
return require('i18n-iso-countries').getName(countryId, languageId);
}

// The above helper facilitates the conversion of a country code into a country name

function rateToPercentage(rate) {
return (Math.round((rate - 1 + Number.EPSILON) * 10000) / 10000 * 100).toFixed(2) + '%';
}

// The above helper facilitates converting a rate into a percentage

Currency helpers
JavaScript
function currency(value, currencyId, locale, maximumFractionDigits) {

// locale should be mandatory
if(locale == undefined) return currencySymbol(currencyId) + ' ' + Number.parseFloat(value || 0.00).toFixed(2).replace('.', ',');

// maximumFractionDigits is no longer supported
if(maximumFractionDigits != undefined) return currencySymbol(currencyId) + ' ' + Number.parseFloat(value || 0.00).toFixed(maximumFractionDigits).replace('.', ',');

return value.toLocaleString(locale, { style: 'currency', currency: currencyId });
}

function currencyAbs(value, currencyId, locale) {
return currency(Math.abs(value), currencyId, locale);
}

How the currency helper helps

Value, currencyId and locale are all three required.

  • The value is a number (float) to represent the amount of money
  • The currencyId is the standard ISO-4217 code for the currency
  • The locale is formatted with a ISO-639-1 language code, underscore, and a ISO-3166-1-alpha-2 country code. This comes down to the following format: currency(123.123, 'EUR', 'nl-NL') or currency(123.123, 'USD', 'en-US')

This function will help format the currency in the proper way everywhere, for example no periods but spaces as thousand-separators in France, and no decimals for JPY.

Image helpers
JavaScript
function barcode(type, value, width, height, includeText) {
var url = model.AssetsUrl + '/barcode/' + type + '/' + width + '/' + height + '/' + value + '/no-margin';
if (!includeText) {
url += '/pure';
}
return url;
}

function qrcode(value, size) {
return barcode('qr', value, size, size, false);
}

function ean(value, width, height, includeText) {
return barcode('ean', value, width, height, includeText);
}

function code39(value, width, height, includeText) {
return barcode('code39', value, width, height, includeText);
}

function code128(value, width, height, includeText) {
return barcode('code128', value, width, height, includeText);
}
Discount lines tax rate helper

This helper is used when you'd like to have a tax rate displayed on discount line(s).


The usual scenario is that tax rates are not displayed on invoice templates however, with this helper you can inherit the tax rate applied on the regular product line (connected to the discount line by ParentID) and render it to the discount line as well.


JavaScript
function renderDiscountLines(pLine,lines){
var ParentTaxRate
txtLine='';
if (pLine.TaxRate !== null){
ParentTaxRate=pLine.TaxRate + '%';
}
else{
ParentTaxRate='0 %';
}
lines.forEach(vLine=>{
if (vLine.ParentID === pLine.ID) {
txtLine+='<tr><td class="text-right" style="width:5%"></td><td class="text-left"><p class="bold order orderline" style="word-wrap: break-word">Discount: ' +
vLine.Description +
'<br/></p></td><td class="text-right"></td><td class="text-right"><p class="bold">'+ParentTaxRate+'</p></td><td class="text-right"><p class="bold">' + fixed(vLine.TotalAmountInTaxInvoiced) +
'</p></td></tr>';
}
})
return txtLine;
}
Debugging helper

If you are troubleshooting a template and can't seem to find the issue, this helper and code reference could be helpful.


By using this helper you can print the source input of the template. It will result in a JSON file of the of the actual event which triggered the template and allow you to check the content for what data might not be available and/or in an incorrect format (such as FirstName.User or User.FirstName).


JavaScript
// Use {{:~printJSON(~root)}} to print all the available data

function printJSON(data) {
var jsonString = JSON.stringify(data, null, 4);
var a = "<pre><code>" + jsonString + "</pre></code>";
return a;
}
Remove the debugger after use

Take in mind that you should remove the helper again after having used it on the template. Furthermore, be sure to only use this on a Test environment.