Files
bible/assets/js/render.js
T
2026-10-21 15:33:08 -04:00

73 lines
2.1 KiB
JavaScript

(function (scope) {
'use strict';
var TITLE_RE = /<title>([\s\S]*?)<\/title>/i;
var TEMPLATE_RE = /data-template="([a-z0-9_-]+)"/i;
var TEMPLATES = './templates/';
var NAMES = [
'base.njk',
'page.njk',
'book.njk',
'index.njk',
'version.njk',
'notice.njk'
];
scope.TEMPLATE_URLS = NAMES.map(function (name) { return TEMPLATES + name; });
scope.createRenderer = function (readText) {
function Loader() {}
Loader.prototype.async = true;
Loader.prototype.getSource = function (name, callback) {
readText(TEMPLATES + name).then(
function (src) { callback(null, { src: src, path: name, noCache: false }); },
function (err) { callback(err); });
};
var env = new nunjucks.Environment(new Loader(), { autoescape: true });
var loaded = null;
// Nunjucks resolves {% include %} asynchronously. A template that is not
// compiled yet when the render reaches it is skipped, taking the rest of
// the block it sits in with it, and the render still succeeds.
function loadAll() {
if (!loaded) {
loaded = Promise.all(NAMES.map(function (name) {
return new Promise(function (resolve) {
env.getTemplate(name, true, null, false, function () { resolve(); });
});
}));
}
return loaded;
}
function render(name, context) {
return loadAll().then(function () {
return new Promise(function (resolve, reject) {
env.render(name, context, function (err, out) {
return err ? reject(err) : resolve(out);
});
});
});
}
return {
render: render,
compose: function (fragment) {
var title = (TITLE_RE.exec(fragment) || ['', ''])[1].trim();
var content = fragment.replace(TITLE_RE, '');
var name = (TEMPLATE_RE.exec(content) || ['', 'page'])[1] + '.njk';
return render(name, { title: title, content: content });
},
notice: function (heading, text) {
return render('notice.njk', { heading: heading, text: text });
}
};
};
})(self);