diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/models/book.js | 10 | ||||
-rw-r--r-- | lib/output/createTemplateEngine.js | 2 | ||||
-rw-r--r-- | lib/output/website/createTemplateEngine.js | 7 | ||||
-rw-r--r-- | lib/output/website/listSearchPaths.js | 23 | ||||
-rw-r--r-- | lib/output/website/onAsset.js | 2 | ||||
-rw-r--r-- | lib/templating/index.js | 3 | ||||
-rw-r--r-- | lib/templating/themesLoader.js | 117 | ||||
-rw-r--r-- | lib/utils/path.js | 15 |
8 files changed, 173 insertions, 6 deletions
diff --git a/lib/models/book.js b/lib/models/book.js index 9b9f769..eb8011b 100644 --- a/lib/models/book.js +++ b/lib/models/book.js @@ -105,6 +105,16 @@ Book.prototype.getRoot = function() { }; /** + Return root for content of the book + + @return {String} +*/ +Book.prototype.getContentRoot = function() { + var fs = this.getContentFS(); + return fs.getRoot(); +}; + +/** Check if a file is ignore (should not being parsed, etc) @param {String} ref diff --git a/lib/output/createTemplateEngine.js b/lib/output/createTemplateEngine.js index a79f93f..9b29b2a 100644 --- a/lib/output/createTemplateEngine.js +++ b/lib/output/createTemplateEngine.js @@ -16,7 +16,7 @@ var defaultFilters = require('../constants/defaultFilters'); function createTemplateEngine(output) { var plugins = output.getPlugins(); var book = output.getBook(); - var rootFolder = book.getRoot(); + var rootFolder = book.getContentRoot(); var logger = book.getLogger(); var filters = plugins diff --git a/lib/output/website/createTemplateEngine.js b/lib/output/website/createTemplateEngine.js index 9aed746..1a70667 100644 --- a/lib/output/website/createTemplateEngine.js +++ b/lib/output/website/createTemplateEngine.js @@ -1,4 +1,6 @@ +var Templating = require('../../templating'); var TemplateEngine = require('../../models/templateEngine'); +var listSearchPaths = require('./listSearchPaths'); /** Create templating engine to render themes @@ -7,8 +9,11 @@ var TemplateEngine = require('../../models/templateEngine'); @return {TemplateEngine} */ function createTemplateEngine(output) { - return new TemplateEngine({ + var searchPaths = listSearchPaths(output); + var loader = new Templating.ThemesLoader(searchPaths); + return new TemplateEngine({ + loader: loader }); } diff --git a/lib/output/website/listSearchPaths.js b/lib/output/website/listSearchPaths.js new file mode 100644 index 0000000..c45f39c --- /dev/null +++ b/lib/output/website/listSearchPaths.js @@ -0,0 +1,23 @@ + +/** + List search paths for templates / i18n, etc + + @param {Output} output + @return {List<String>} +*/ +function listSearchPaths(output) { + var book = output.getBook(); + var plugins = output.getPlugins(); + + var searchPaths = plugins + .valueSeq() + .map(function(plugin) { + return plugin.getPath(); + }) + .toList(); + + return searchPaths.unshift(book.getContentRoot()); +} + + +module.exports = listSearchPaths; diff --git a/lib/output/website/onAsset.js b/lib/output/website/onAsset.js index a2342ae..8659ca6 100644 --- a/lib/output/website/onAsset.js +++ b/lib/output/website/onAsset.js @@ -11,7 +11,7 @@ function onAsset(output, asset) { var book = output.getBook(); var options = output.getOptions(); - var rootFolder = book.getRoot(); + var rootFolder = book.getContentRoot(); var outputFolder = options.get('root'); var filePath = path.resolve(rootFolder, asset); diff --git a/lib/templating/index.js b/lib/templating/index.js index 4cdf6ef..a33965d 100644 --- a/lib/templating/index.js +++ b/lib/templating/index.js @@ -4,5 +4,6 @@ module.exports = { renderFile: require('./renderFile'), postRender: require('./postRender'), - ConrefsLoader: require('./conrefsLoader') + ConrefsLoader: require('./conrefsLoader'), + ThemesLoader: require('./themesLoader') }; diff --git a/lib/templating/themesLoader.js b/lib/templating/themesLoader.js new file mode 100644 index 0000000..2b436a4 --- /dev/null +++ b/lib/templating/themesLoader.js @@ -0,0 +1,117 @@ +var Immutable = require('immutable'); +var nunjucks = require('nunjucks'); +var fs = require('fs'); +var path = require('path'); + +var PathUtils = require('../utils/path'); + +/** + +*/ +var ThemesLoader = nunjucks.Loader.extend({ + init: function(searchPaths) { + this.searchPaths = Immutable.List(searchPaths) + .map(path.normalize); + }, + + /* + Read source of a resolved filepath + @param {String} + @return {Object} + */ + getSource: function(fullpath) { + if (!fullpath) return null; + + fullpath = this.resolve(null, fullpath); + var templateName = this.getTemplateName(fullpath); + + if(!fullpath) { + return null; + } + + var src = fs.readFileSync(fullpath, 'utf-8'); + + src = '{% do %}var template = template || {}; template.stack = template.stack || []; template.stack.push(template.self); template.self = ' + JSON.stringify(templateName) + '{% enddo %}\n' + + src + + '\n{% do %}template.self = template.stack.pop();{% enddo %}'; + + return { + src: src, + path: fullpath, + noCache: true + }; + }, + + /* + Nunjucks calls "isRelative" to determine when to call "resolve". + We handle absolute paths ourselves in ".resolve" so we always return true + */ + isRelative: function() { + return true; + }, + + /* + Get original search path containing a template + @param {String} filepath + @return {String} searchPath + */ + getSearchPath: function(filepath) { + return this.searchPaths + .sortBy(function(s) { + return -s.length; + }) + .find(function(basePath) { + return (filepath && filepath.indexOf(basePath) === 0); + }); + }, + + /* + Get template name from a filepath + @param {String} filepath + @return {String} name + */ + getTemplateName: function(filepath) { + var originalSearchPath = this.getSearchPath(filepath); + return originalSearchPath? path.relative(originalSearchPath, filepath) : null; + }, + + /* + Resolve a template from a current template + @param {String|null} from + @param {String} to + @return {String|null} + */ + resolve: function(from, to) { + var searchPaths = this.searchPaths; + + // Relative template like "./test.html" + if (PathUtils.isPureRelative(to) && from) { + return path.resolve(path.dirname(from), to); + } + + // Determine in which search folder we currently are + var originalSearchPath = this.getSearchPath(from); + var originalFilename = this.getTemplateName(from); + + // If we are including same file from a different search path + // Slice the search paths to avoid including from previous ones + if (originalFilename == to) { + var currentIndex = searchPaths.indexOf(originalSearchPath); + searchPaths = searchPaths.slice(currentIndex + 1); + } + + // Absolute template to resolve in root folder + var resultFolder = searchPaths.find(function(basePath) { + var p = path.resolve(basePath, to); + + return ( + p.indexOf(basePath) === 0 + && fs.existsSync(p) + ); + }); + if (!resultFolder) return null; + return path.resolve(resultFolder, to); + } +}); + +module.exports = ThemesLoader; diff --git a/lib/utils/path.js b/lib/utils/path.js index c233c92..a4968c8 100644 --- a/lib/utils/path.js +++ b/lib/utils/path.js @@ -42,7 +42,7 @@ function resolveInRoot(root) { return result; } -// Chnage extension +// Chnage extension of a file function setExtension(filename, ext) { return path.join( path.dirname(filename), @@ -50,9 +50,20 @@ function setExtension(filename, ext) { ); } +/* + Return true if a filename is relative. + + @param {String} + @return {Boolean} +*/ +function isPureRelative(filename) { + return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0); +} + module.exports = { isInRoot: isInRoot, resolveInRoot: resolveInRoot, normalize: normalizePath, - setExtension: setExtension + setExtension: setExtension, + isPureRelative: isPureRelative }; |