diff options
author | Samy Pesse <samypesse@gmail.com> | 2016-05-05 11:00:05 +0200 |
---|---|---|
committer | Samy Pesse <samypesse@gmail.com> | 2016-05-05 11:00:05 +0200 |
commit | 34947b5e207e84ef43a8194c0ec7bac19dccf709 (patch) | |
tree | 06e687700d95590cae678f8bef381e8a62dc0129 | |
parent | c621380b664bcbef087df571b662e7a34e098168 (diff) | |
download | gitbook-34947b5e207e84ef43a8194c0ec7bac19dccf709.zip gitbook-34947b5e207e84ef43a8194c0ec7bac19dccf709.tar.gz gitbook-34947b5e207e84ef43a8194c0ec7bac19dccf709.tar.bz2 |
Add mode TemplateOutput to represent {content + blocks} from template
-rw-r--r-- | lib/api/encodeGlobal.js | 10 | ||||
-rw-r--r-- | lib/models/templateBlock.js | 54 | ||||
-rw-r--r-- | lib/models/templateEngine.js | 4 | ||||
-rw-r--r-- | lib/models/templateOutput.js | 44 | ||||
-rw-r--r-- | lib/output/ebook/getPDFTemplate.js | 4 | ||||
-rw-r--r-- | lib/output/ebook/onFinish.js | 4 | ||||
-rw-r--r-- | lib/output/generatePage.js | 14 | ||||
-rw-r--r-- | lib/output/website/onFinish.js | 4 | ||||
-rw-r--r-- | lib/output/website/onPage.js | 4 | ||||
-rw-r--r-- | lib/templating/postRender.js | 39 | ||||
-rw-r--r-- | lib/templating/render.js | 16 | ||||
-rw-r--r-- | lib/templating/renderFile.js | 2 | ||||
-rw-r--r-- | lib/templating/replaceBlocks.js | 34 |
13 files changed, 132 insertions, 101 deletions
diff --git a/lib/api/encodeGlobal.js b/lib/api/encodeGlobal.js index 8144883..1e7df36 100644 --- a/lib/api/encodeGlobal.js +++ b/lib/api/encodeGlobal.js @@ -108,6 +108,16 @@ function encodeGlobal(output) { }, /** + 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} */ diff --git a/lib/models/templateBlock.js b/lib/models/templateBlock.js index 2ec1328..200e048 100644 --- a/lib/models/templateBlock.js +++ b/lib/models/templateBlock.js @@ -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 @@ -268,29 +261,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 @param {String} blockName diff --git a/lib/models/templateEngine.js b/lib/models/templateEngine.js index 243bfc6..5724d55 100644 --- a/lib/models/templateEngine.js +++ b/lib/models/templateEngine.js @@ -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()); }); diff --git a/lib/models/templateOutput.js b/lib/models/templateOutput.js new file mode 100644 index 0000000..cd65a05 --- /dev/null +++ b/lib/models/templateOutput.js @@ -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; diff --git a/lib/output/ebook/getPDFTemplate.js b/lib/output/ebook/getPDFTemplate.js index f7a450d..354cc29 100644 --- a/lib/output/ebook/getPDFTemplate.js +++ b/lib/output/ebook/getPDFTemplate.js @@ -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 } diff --git a/lib/output/ebook/onFinish.js b/lib/output/ebook/onFinish.js index f365bcb..7f21548 100644 --- a/lib/output/ebook/onFinish.js +++ b/lib/output/ebook/onFinish.js @@ -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()); }); } diff --git a/lib/output/generatePage.js b/lib/output/generatePage.js index 27b4eb1..7e4e454 100644 --- a/lib/output/generatePage.js +++ b/lib/output/generatePage.js @@ -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 diff --git a/lib/output/website/onFinish.js b/lib/output/website/onFinish.js index e3560e2..5267458 100644 --- a/lib/output/website/onFinish.js +++ b/lib/output/website/onFinish.js @@ -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()); }); } diff --git a/lib/output/website/onPage.js b/lib/output/website/onPage.js index 16a5c39..14c7b22 100644 --- a/lib/output/website/onPage.js +++ b/lib/output/website/onPage.js @@ -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()); }); }); } diff --git a/lib/templating/postRender.js b/lib/templating/postRender.js index c4e82a5..2662814 100644 --- a/lib/templating/postRender.js +++ b/lib/templating/postRender.js @@ -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; diff --git a/lib/templating/render.js b/lib/templating/render.js index 22c0dc4..584890a 100644 --- a/lib/templating/render.js +++ b/lib/templating/render.js @@ -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); + }) ); } diff --git a/lib/templating/renderFile.js b/lib/templating/renderFile.js index 9b74e5b..185bec1 100644 --- a/lib/templating/renderFile.js +++ b/lib/templating/renderFile.js @@ -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(); diff --git a/lib/templating/replaceBlocks.js b/lib/templating/replaceBlocks.js deleted file mode 100644 index 4b1c37f..0000000 --- a/lib/templating/replaceBlocks.js +++ /dev/null @@ -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; |