Add loader for themes

This commit is contained in:
Samy Pessé
2016-04-25 14:44:49 +02:00
parent 525bcd8295
commit 4552ccd7d7
8 changed files with 173 additions and 6 deletions
+10
View File
@@ -104,6 +104,16 @@ Book.prototype.getRoot = function() {
return fs.getRoot();
};
/**
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)
+1 -1
View File
@@ -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
+6 -1
View File
@@ -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
});
}
+23
View File
@@ -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;
+1 -1
View File
@@ -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);
+2 -1
View File
@@ -4,5 +4,6 @@ module.exports = {
renderFile: require('./renderFile'),
postRender: require('./postRender'),
ConrefsLoader: require('./conrefsLoader')
ConrefsLoader: require('./conrefsLoader'),
ThemesLoader: require('./themesLoader')
};
+117
View File
@@ -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;
+13 -2
View File
@@ -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
};