Add mode TemplateOutput to represent {content + blocks} from template

This commit is contained in:
Samy Pesse
2016-05-05 11:00:05 +02:00
parent c621380b66
commit 34947b5e20
13 changed files with 132 additions and 101 deletions
+10
View File
@@ -107,6 +107,16 @@ function encodeGlobal(output) {
return outputFolder;
},
/**
Resolve a file from the output root
@param {String} fileName
@return {String}
*/
resolve: function(fileName) {
return path.resolve(outputFolder, fileName);
},
/**
Convert a filepath into an url
@return {String}
+12 -42
View File
@@ -8,8 +8,6 @@ var TemplateShortcut = require('./templateShortcut');
var NODE_ENDARGS = '%%endargs%%';
var blockBodies = {};
var TemplateBlock = Immutable.Record({
// Name of block, also the start tag
name: String(),
@@ -26,9 +24,6 @@ var TemplateBlock = Immutable.Record({
// List of shortcuts to replace with this block
shortcuts: Immutable.Map(),
// Function to execute in post processing
post: null,
parse: true
}, 'TemplateBlock');
@@ -36,10 +31,6 @@ TemplateBlock.prototype.getName = function() {
return this.get('name');
};
TemplateBlock.prototype.getPost = function() {
return this.get('post');
};
TemplateBlock.prototype.getParse = function() {
return this.get('parse');
};
@@ -85,7 +76,7 @@ TemplateBlock.prototype.getExtensionName = function() {
@return {Nunjucks.Extension}
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext) {
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
@@ -195,7 +186,7 @@ TemplateBlock.prototype.toNunjucksExt = function(mainContext) {
return that.applyBlock(mainBlock, ctx);
})
.then(function(result) {
return that.blockResultToHtml(result);
return that.blockResultToHtml(result, blocksOutput);
})
.nodeify(callback);
};
@@ -221,19 +212,19 @@ TemplateBlock.prototype.applyBlock = function(inner, context) {
var r = processFn.call(context, inner);
if (Promise.isPromiseAlike(r)) {
return r.then(this.handleBlockResult.bind(this));
return r.then(this.normalizeBlockResult.bind(this));
} else {
return this.handleBlockResult(r);
return this.normalizeBlockResult(r);
}
};
/**
Handle result from a block process function
Normalize result from a block process function
@param {Object} result
@param {Object|String} result
@return {Object}
*/
TemplateBlock.prototype.handleBlockResult = function(result) {
TemplateBlock.prototype.normalizeBlockResult = function(result) {
if (is.string(result)) {
result = { body: result };
}
@@ -246,15 +237,17 @@ TemplateBlock.prototype.handleBlockResult = function(result) {
Convert a block result to HTML
@param {Object} result
@param {Object} blocksOutput: stored post processing blocks in this object
@return {String}
*/
TemplateBlock.prototype.blockResultToHtml = function(result) {
TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) {
var parse = this.getParse();
var indexedKey;
var toIndex = (!parse) || (this.getPost() !== undefined);
var toIndex = (!parse) || (result.post !== undefined);
if (toIndex) {
indexedKey = TemplateBlock.indexBlockResult(result);
indexedKey = genKey();
blocksOutput[indexedKey] = result;
}
// Parsable block, just return it
@@ -267,29 +260,6 @@ TemplateBlock.prototype.blockResultToHtml = function(result) {
};
/**
Index a block result, and return the indexed key
@param {Object} blk
@return {String}
*/
TemplateBlock.indexBlockResult = function(blk) {
var key = genKey();
blockBodies[key] = blk;
return key;
};
/**
Get a block results indexed for a specific key
@param {String} key
@return {Object|undefined}
*/
TemplateBlock.getBlockResultByKey = function(key) {
return blockBodies[key];
};
/**
Create a template block from a function or an object
+2 -2
View File
@@ -67,7 +67,7 @@ TemplateEngine.prototype.getBlock = function(name) {
@return {Nunjucks.Environment}
*/
TemplateEngine.prototype.toNunjucks = function() {
TemplateEngine.prototype.toNunjucks = function(blocksOutput) {
var loader = this.getLoader();
var blocks = this.getBlocks();
var filters = this.getFilters();
@@ -101,7 +101,7 @@ TemplateEngine.prototype.toNunjucks = function() {
// Add blocks
blocks.forEach(function(block) {
var extName = block.getExtensionName();
var Ext = block.toNunjucksExt(context);
var Ext = block.toNunjucksExt(context, blocksOutput);
env.addExtension(extName, new Ext());
});
+44
View File
@@ -0,0 +1,44 @@
var Immutable = require('immutable');
var TemplateOutput = Immutable.Record({
// Text content of the template
content: String(),
// Map of blocks to replace / post process
blocks: Immutable.Map()
}, 'TemplateOutput');
TemplateOutput.prototype.getContent = function() {
return this.get('content');
};
TemplateOutput.prototype.getBlocks = function() {
return this.get('blocks');
};
/**
Update content of this output
@param {String} content
@return {TemplateContent}
*/
TemplateOutput.prototype.setContent = function(content) {
return this.set('content', content);
};
/**
Create a TemplateOutput from a text content
and an object containing block definition
@param {String} content
@param {Object} blocks
@return {TemplateOutput}
*/
TemplateOutput.create = function(content, blocks) {
return new TemplateOutput({
content: content,
blocks: Immutable.fromJS(blocks)
});
};
module.exports = TemplateOutput;
+2 -2
View File
@@ -30,8 +30,8 @@ function getPDFTemplate(output, type) {
return Templating.renderFile(engine, 'ebook/' + filePath, context)
// Inline css and assets
.then(function(html) {
return Promise.nfcall(juice.juiceResources, html, {
.then(function(tplOut) {
return Promise.nfcall(juice.juiceResources, tplOut.getContent(), {
webResources: {
relativeTo: outputRoot
}
+2 -2
View File
@@ -29,8 +29,8 @@ function writeSummary(output) {
return Templating.renderFile(engine, prefix + '/summary.html', context)
// Write it to the disk
.then(function(html) {
return writeFile(output, filePath, html);
.then(function(tplOut) {
return writeFile(output, filePath, tplOut.getContent());
});
}
+10 -4
View File
@@ -47,12 +47,18 @@ function generatePage(output, page) {
return Templating.render(engine, filePath, content, context);
})
// Render page using parser (markdown -> HTML)
.then(parser.parsePage.bind(parser)).get('content')
.then(function(output) {
var content = output.getContent();
return parser.parsePage(content)
.then(function(result) {
return output.setContent(result.content);
});
})
// Post processing for templating syntax
.then(function(content) {
return Templating.postRender(engine, content);
.then(function(output) {
return Templating.postRender(engine, output);
})
// Return new page
+2 -2
View File
@@ -27,8 +27,8 @@ function onFinish(output) {
return Templating.renderFile(engine, prefix + '/languages.html', context)
// Write it to the disk
.then(function(html) {
return writeFile(output, filePath, html);
.then(function(tplOut) {
return writeFile(output, filePath, tplOut.getContent());
});
}
+2 -2
View File
@@ -67,8 +67,8 @@ function onPage(output, page) {
return Templating.renderFile(engine, prefix + '/page.html', context)
// Write it to the disk
.then(function(html) {
return writeFile(output, filePath, html);
.then(function(tplOut) {
return writeFile(output, filePath, tplOut.getContent());
});
});
}
+32 -7
View File
@@ -1,5 +1,27 @@
var Promise = require('../utils/promise');
var replaceBlocks = require('./replaceBlocks');
/**
Replace position markers of blocks by body after processing
This is done to avoid that markdown/asciidoc processer parse the block content
@param {String} content
@return {Object} {blocks: Set, content: String}
*/
function replaceBlocks(content, blocks) {
var newContent = content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) {
var replacedWith = match;
var block = blocks.get(key);
if (block) {
replacedWith = replaceBlocks(block.get('body'), blocks);
}
return replacedWith;
});
return newContent;
}
/**
Post render a template:
@@ -7,22 +29,25 @@ var replaceBlocks = require('./replaceBlocks');
- Replace block content
@param {TemplateEngine} engine
@param {String} content
@param {TemplateOutput} content
@return {Promise<String>}
*/
function postRender(engine, content) {
function postRender(engine, output) {
var content = output.getContent();
var blocks = output.getBlocks();
var result = replaceBlocks(content);
return Promise.forEach(result.blocks, function(blockType) {
var block = engine.getBlock(blockType);
var post = block.getPost();
return Promise.forEach(blocks, function(block) {
var post = block.get('post');
if (!post) {
return;
}
return post();
})
.thenResolve(result.content);
.thenResolve(result);
}
module.exports = postRender;
+13 -3
View File
@@ -1,6 +1,6 @@
var Promise = require('../utils/promise');
var timing = require('../utils/timing');
var TemplateOutput = require('../models/templateOutput');
var replaceShortcuts = require('./replaceShortcuts');
/**
@@ -10,16 +10,23 @@ var replaceShortcuts = require('./replaceShortcuts');
@param {String} filePath
@param {String} content
@param {Object} context
@return {Promise<String>}
@return {Promise<TemplateOutput>}
*/
function renderTemplate(engine, filePath, content, context) {
context = context || {};
var env = engine.toNunjucks();
// Mutable objects to contains all blocks requiring post-processing
var blocks = {};
// Create nunjucks environment
var env = engine.toNunjucks(blocks);
// Replace shortcuts from plugin's blocks
content = replaceShortcuts(engine, filePath, content);
return timing.measure(
'template.render',
Promise.nfcall(
env.renderString.bind(env),
content,
@@ -28,6 +35,9 @@ function renderTemplate(engine, filePath, content, context) {
path: filePath
}
)
.then(function(content) {
return TemplateOutput.create(content, blocks);
})
);
}
+1 -1
View File
@@ -8,7 +8,7 @@ var render = require('./render');
@param {TemplateEngine} engine
@param {String} filePath
@param {Object} context
@return {Promise<String>}
@return {Promise<TemplateOutput>}
*/
function renderTemplateFile(engine, filePath, context) {
var loader = engine.getLoader();
-34
View File
@@ -1,34 +0,0 @@
var Immutable = require('immutable');
var TemplateBlock = require('../models/templateBlock');
/**
Replace position markers of blocks by body after processing
This is done to avoid that markdown/asciidoc processer parse the block content
@param {String} content
@return {Object} {blocks: Set, content: String}
*/
function replaceBlocks(content) {
var blockTypes = new Immutable.Set();
var newContent = content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) {
var replacedWith = match;
var block = TemplateBlock.getBlockResultByKey(key);
if (block) {
var result = replaceBlocks(block.body);
blockTypes = blockTypes.add(block.name);
blockTypes = blockTypes.concat(result.blocks);
replacedWith = result.content;
}
return replacedWith;
});
return {
content: newContent,
blocks: blockTypes
};
}
module.exports = replaceBlocks;