dojo-templater
Version:
Easy HTML emails with variables
243 lines (171 loc) • 6.24 kB
text/coffeescript
Mustache = require("mustache")
i18n = require("i18next")
fs = require("fs")
Handlebars = require("handlebars")
handlebarsLayouts = require("handlebars-layouts")(Handlebars)
juice = require("juice")
charttile = require('./charttile')
path = require('path')
TEMPLATE_DIR = "#{__dirname}/../email_templates"
LAYOUT_DIR = "#{__dirname}/../layouts"
LANGUAGE_DIR = "#{__dirname}/../language"
CSS_DIR = "#{__dirname}/../"
DEFAULT_LAYOUT = "teacher_email"
FIXTURES = require("./fixtures")
class Templater
###
constructor
Loads templates into memory
###
constructor: () ->
@templates = {}
@translate_functions = {}
files = fs.readdirSync TEMPLATE_DIR
## Register all Handlebars layouts
@layouts = { } # { name: path }
files = fs.readdirSync LAYOUT_DIR
for file in files
if file.indexOf('.hb') isnt -1
layoutPath = [LAYOUT_DIR, file].join("/")
partial = fs.readFileSync layoutPath, 'utf8'
layoutName = file.replace('.hb', '')
@layouts[layoutName] = partial
# Options for inlining css
@juiceOptions =
applyStyleTags: false
removeStyleTags: false
url: ["file://", CSS_DIR].join("")
# Get the template if it has already been loaded to memory
# Otherwise, load it into memory
_getTemplate: (fileName, language) =>
if not @templates[fileName]?
@templates[fileName] = {}
if fileName.indexOf(".hb") is -1
fileNameExt = fileName + ".hb"
if @templates[fileName][language]?
return @templates[fileName][language]
else
templates = [
'parentMain',
'pipes',
'responsiveMain',
'studentMain',
'teacherMain',
'template3',
'template3White',
'template_CDM',
'teacherNew'
]
for templateName in templates
Handlebars.registerPartial templateName, @layouts[templateName]
# end terrible hack.
templatePath = [TEMPLATE_DIR, fileNameExt].join("/")
templateRaw = fs.readFileSync templatePath, 'utf8'
template = Handlebars.compile templateRaw
@templates[fileName][language] = template
return @templates[fileName][language]
# render handlebars email
fetchEmail: (fileName, templateVars, options, callback) =>
# Only use the basename of the file for fixtures and such
fullFilename = fileName
fileName = path.basename(fileName)
# Set language if not passed in
if not options.language?
options.language = 'en'
# Get translate function
@_get_translate_function options.language, (t) =>
# Helper for translations in handlebars
# The second param 'options' is used for passing in data to
# translation strings.
# Example usage:
# {{ I18n "dojo-templater.emails:initial_parent_invite.would_like_to_share" link1=inviteLink }}
Handlebars.registerHelper 'I18n', (str, options) =>
if options and options.hash
options = options.hash
else
options = {}
return t(str, options)
# helper function for {{ifeq a 5}} ... {else} ... {/ifeq}
Handlebars.registerHelper 'ifeq', (a, b, options) ->
if(a is b)
return options.fn(this);
else
return options.inverse(this);
# Get the template
try
template = @_getTemplate fullFilename, options.language
catch err
return callback err
# Use fixtures?
if options.useFixtures
templateVars = FIXTURES[fileName]
# templateVars must be defined, or handlebars will throw an error
if not templateVars?
templateVars = {}
# Compile template with vars
compiled = template(templateVars)
# Inline CSS
juice.juiceContent compiled, @juiceOptions, (err, htmlEmail) =>
# make the object to return
result =
html: htmlEmail
plain: @_html_to_plain(htmlEmail)
subject: @_getSubject fileName, templateVars, t
# callback
callback err, result
###
###
# Swap {{ var }} with the variable name in the template
_insert_vars: (template_html, template_vars) =>
output = Mustache.render(template_html, template_vars)
return output
###
###
# Get subject for a given filename
# The subject line is in a field called '_subject' in the language
# file for this email. Translate it here
_getSubject: (file_name, template_vars, t) =>
subject = t("dojo-templater.emails:#{file_name}._subject")
subjectTemplate = Handlebars.compile subject
compiled = subjectTemplate(template_vars)
## Hack to catch when subject does not get translated
## Currently, subject works fine locally, not on staging or production
if compiled.indexOf("dojo-templater") isnt -1
compiled = "Welcome to ClassDojo :)"
return compiled
###
###
###
Every language needs to be inited seperately, but
we cache the function so that we don't have to load
the resource files every time
###
_get_translate_function: (language, callback) =>
# console.log "Initing with lang: #{language} <br/><br/>"
if not @translate_functions[language]?
i18n.init {
lng: language,
fallbackLng: 'en',
ns: {
namespaces: ['dojo-templater.layouts', 'dojo-templater.emails'],
defaultNs: 'dojo-templater.layouts'
},
resGetPath: "#{__dirname}/../language/__lng__/__ns__.json"
}, (t) =>
@translate_functions[language] = t
callback(t)
else
callback(@translate_functions[language])
###
###
# Take an html string and return a plain text string
_html_to_plain: (html) =>
return if not html?
str=html
str=str.replace(/<style>([^<]*)<\/style>/, "")
str=str.replace(/<br>/gi, "\n");
str=str.replace(/<p.*>/gi, "\n");
str=str.replace(/<a.*href=\"(.*?)\".*>(.*?)<\/a>/gi, " $2 (Link->$1) ");
str=str.replace(/<(?:.|\s)*?>/g, "");
return str
module.exports = Templater