stick
Version:
JSGI based webapp framework
125 lines (105 loc) • 4 kB
JavaScript
/**
* @fileOverview This module provides middleware for rendering responses
* using ringo/mustache.
*
* This middleware installs a `render` function in the application object
* which is used to render HTTP responses. The behaviour of `app.render` can
* be tweaked by setting the following properties:
*
* - `render.base` - the base path or repository to look for templates
* - `render.helpers` - helper functions that will be merged in the context
* - `render.master` - master template to apply to every page
* - `render.contentType` - MIME type to use for HTTP response
* - `render.charset` - charset name to use for HTTP response
*
* @example
* app.configure("render");
* app.render.base = module.resolve("templates");
* app.render("index.tmpl", {data: "Hello World!"});
*/
var objects = require("common-utils/objects");
var mustache = require("mustache");
function isRelative(path) {
return path.indexOf('/');
}
/**
* Middleware for template based response generation.
* @param {Function} next the wrapped middleware chain
* @param {Object} app the Stick Application object
* @returns {Function} a JSGI middleware function
*/
exports.middleware = function render(next, app) {
var _base, _master, _helpers,
_contentType = "text/html",
_charset = "utf-8";
app.render = function(template, context, options) {
var content = app.renderPart(template, context, options);
var base = options && options.base || _base;
var contentType = options && options.contentType || _contentType;
var charset = options && options.charset || _charset;
var req = app.request;
var master = options && options.master
|| req && req.env.masterTemplate
|| _master;
if (_helpers) {
context = objects.merge(context, _helpers);
}
if (master) {
context.content = content;
content = mustache.to_html(resolve(master, base), context);
}
return {
status: 200,
headers: {"Content-Type": contentType + "; charset=" + charset},
body: [content]
};
};
app.renderPart = function(template, context, options) {
var base = options && options.base || _base;
if (_helpers) {
context = objects.merge(context, _helpers);
}
template = resolve(template, base);
return mustache.to_html(template, context);
};
function resolve(template, base) {
if (Object.prototype.toString.call(template) == '[object String]') {
template = base && isRelative(template) ?
base.getResource(template) : getResource(template);
}
if (!template || !template.exists()) {
throw new Error("Template " + template + " not found");
}
return template.getContent();
}
Object.defineProperty(app.render, "base", {
get: function() { return _base; },
set: function(value) {
_base = Object.prototype.toString.call(value) == '[object String]' ?
getRepository(value) : value;
},
enumerable: true
});
Object.defineProperty(app.render, "master", {
get: function() { return _master; },
set: function(value) {_master = value},
enumerable: true
});
Object.defineProperty(app.render, "helpers", {
get: function() { return _helpers; },
set: function(value) {_helpers = value},
enumerable: true
});
Object.defineProperty(app.render, "contentType", {
get: function() { return _contentType; },
set: function(value) {_contentType = value},
enumerable: true
});
Object.defineProperty(app.render, "charset", {
get: function() { return _charset; },
set: function(value) {_charset = value},
enumerable: true
});
// We don't actually add any middleware
return next;
};