From 6b39a2400256d9b84927925eaec3c6ffb0b3c3b0 Mon Sep 17 00:00:00 2001 From: Steve King Date: Sat, 15 Oct 2016 09:42:54 +0100 Subject: [PATCH] Add support for using relative paths as the name of a partial - partially closes #2 --- README.md | 27 ++++++++++++++- src/template-engine.js | 75 +++++++++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 222c07f..77002c1 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,28 @@ In this case there is a file named `home.mustache` in the `views` directory that

{{SiteName}}

+ +Configuration +============= + +Optional functionality in the middleware can be set before passing it into express: + +``` +var hoganMiddleware = require('hogan-middleware'); +hoganMiddleware({ + filter: ['**.mustache'], // override the default file extension searched for + // default is just the mustache file extension + + flatten: true, // make all partials available with just their file name + // rather than the slash delimited path. default is enabled + + watch: true // set to false to remove the live updating watchers - + // can be useful for running in production where files + // will not be regularly changing. +}); + +app.engine('mustache', hoganMiddleware.__express); +``` Partial Templates ================= @@ -43,7 +65,10 @@ to it for use as partials, so could in turn have `{{>b}}` to include a nested pa To allow for a tidy source tree, templates can be in any number of sub-directories under the main views directory, they are all made available for use as partials without any path identifier. -Note - multiple templates with the same name but in different directories will overwrite each other. +Note - multiple templates with the same name but in different directories will overwrite each other. Set the +`flatten` configuration option to false to always use the relative path as the name of the partials +(ie: `{{>app/header}}` instead of just `{{>header}}`). Whether the `flatten` option is enabled or not, the relative +path name will always be available. Note - don't include the same template as a partial inside itself. diff --git a/src/template-engine.js b/src/template-engine.js index d0e57ec..776d4f3 100644 --- a/src/template-engine.js +++ b/src/template-engine.js @@ -20,7 +20,9 @@ function TemplateEngine(settings) { } TemplateEngine.__settings = { - filter: ['**.mustache'] + filter: ['**.mustache'], + flatten: true, + watch: true }; /** @@ -58,19 +60,6 @@ TemplateEngine.__express = function(templatePath, templateData, next) { } }; -/** - * Stores an individual template based on the supplied path, the name of the template is the file's basename without - * the extension. - * - * @param {String} templatePath - */ -TemplateEngine._storeTemplate = function(templatePath) { - var templateName = Path.basename(templatePath, Path.extname(templatePath)); - TemplateEngine.__templates[templateName] = Hogan.compile(FS.readFileSync(templatePath, 'utf-8')); - - debug('Stored template %s', templateName); -}; - /** * Gets all templates, when the template path hasn't yet been scanned it will be read synchronously to ensure there are * always templates available, the template directory is then watched to allow templates to be changed while the server @@ -81,7 +70,15 @@ TemplateEngine._storeTemplate = function(templatePath) { TemplateEngine._getTemplates = function(templatesPath) { if(!TemplateEngine.__templates) { TemplateEngine._refreshTemplates(templatesPath); - FS.watch(templatesPath, {persistent: false}, TemplateEngine._refreshTemplates.bind(TemplateEngine, templatesPath)); + FS.watch( + templatesPath, + { + persistent: false + }, + function refreshTemplates (a,b,c) { + return TemplateEngine._refreshTemplates(templatesPath); + } + ); } return TemplateEngine.__templates; }; @@ -91,6 +88,11 @@ TemplateEngine._getTemplates = function(templatesPath) { * @param {String} templatesPath */ TemplateEngine._refreshWatches = function(templatesPath) { + if (TemplateEngine.__settings.watch === false) { + debug('Refreshing watched directories has been disabled.'); + return; + } + debug('Refreshing watched directories'); // Remove any existing watches @@ -111,17 +113,46 @@ TemplateEngine._refreshWatches = function(templatesPath) { * Reads all templates in the supplied path (synchronously). Can be called at any time, and is used as the handler for * the file system watch of the templates directory. * - * @param {String} templatesPath + * @param {String} templateRootPath */ -TemplateEngine._refreshTemplates = function(templatesPath) { - debug('Refreshing templates for %s', templatesPath); +TemplateEngine._refreshTemplates = function(templateRootPath) { + debug('Refreshing templates for %s', templateRootPath); + + TemplateEngine._refreshWatches(templateRootPath); - TemplateEngine._refreshWatches(templatesPath); + var settings = TemplateEngine.__settings; + + findTemplates(templateRootPath, settings.filter) + .map(readTemplate) + .reduce(function (templates, template) { + + if (settings.flatten) { + templates[template.name] = template.content; + } + + templates[template.relative] = template.content; + + return templates; + + }, TemplateEngine.__templates = {}); - TemplateEngine.__templates = {}; - ReadDir.readSync(templatesPath, TemplateEngine.__settings.filter, ReadDir.ABSOLUTE_PATHS) - .forEach(TemplateEngine._storeTemplate, TemplateEngine); debug('Refreshing templates complete'); }; +function findTemplates (rootPath, filter) { + return ReadDir.readSync(rootPath, filter, ReadDir.ABSOLUTE_PATHS); +} + +function readTemplate (absolutePath) { + return { + content: Hogan.compile(FS.readFileSync(absolutePath, 'utf-8')), + name: stripFileExtension(absolutePath) + }; +} + +function stripFileExtension (input) { + return input.replace(/(.+)\.[a-z]+/, '$1'); +} + + module.exports = TemplateEngine;