marko/runtime/html/index.js

170 lines
4.5 KiB
JavaScript

'use strict';
// helpers provide a core set of various utility methods to compiled templates
var helpers;
/**
* Method is for internal usage only. This method
* is invoked by code in a compiled Marko template and
* it is used to create a new Template instance.
* @private
*/
exports.c = function createTemplate(path) {
return new Template(path);
};
var AsyncStream;
function createOut(globalData) {
return new AsyncStream(globalData);
}
// If the optional "stream" module is available
// then Readable will be a readable stream
var extend = require('raptor-util/extend');
exports.AsyncStream = AsyncStream;
function Template(path, func, options) {
this.path = path;
this._ = func;
this._shouldBuffer = !options || options.shouldBuffer !== false;
this.meta = undefined;
}
Template.prototype = {
createOut: createOut,
renderSync: function(data) {
var localData;
var globalData;
if ((localData = data)) {
globalData = localData.$global;
} else {
localData = {};
}
var out = new AsyncStream(globalData);
out.sync();
this._(localData, out);
return out.getOutput();
},
/**
* Renders a template to either a stream (if the last
* argument is a Stream instance) or
* provides the output to a callback function (if the last
* argument is a Function).
*
* Supported signatures:
*
* render(data, callback)
* render(data, out)
* render(data, stream)
* render(data, out, callback)
* render(data, stream, callback)
*
* @param {Object} data The view model data for the template
* @param {AsyncStream} out A Stream or an AsyncStream instance
* @param {Function} callback A callback function
* @return {AsyncStream} Returns the AsyncStream instance that the template is rendered to
*/
render: function(data, out, callback) {
var renderFunc = this._;
var finalData;
var globalData;
if (data) {
finalData = data;
if ((globalData = data.$global)) {
// We will *move* the "$global" property
// into the "out.global" object
data.$global = null;
}
} else {
finalData = {};
}
if (out) {
// The out can either be a callback function or AsyncStream...
if (out.isAsyncStream) {
if (callback) {
out
.on('finish', function() {
callback(null, out.getOutput(), out);
})
.once('error', callback);
}
if (globalData) {
extend(out.global, globalData);
}
renderFunc(finalData, out);
return out;
} else if (typeof out === 'function') {
callback = out;
out = null;
}
}
var shouldBuffer = this._shouldBuffer;
var finalOut = new AsyncStream(globalData, out, null, shouldBuffer);
if (callback) {
finalOut
.on('finish', function() {
callback(null, finalOut.getOutput(), finalOut);
})
.once('error', callback);
}
// Invoke the compiled template's render function to have it
// write out strings to the provided out.
renderFunc(finalData, finalOut);
// Automatically end output stream (the writer) if we
// had to create an async writer (which might happen
// if the caller did not provide a writer/out or the
// writer/out was not an AsyncStream).
//
// If out parameter was originally an AsyncStream then
// we assume that we are writing to output that was
// created in the context of another rendering job.
return finalOut.end();
},
stream: function() {
throw new Error('You must require("marko/stream")');
}
};
function createInlineMarkoTemplate(filename, renderFunc) {
return new Template(filename, renderFunc);
}
exports.createWriter = function(writer) {
return new AsyncStream(null, writer);
};
exports._inline = createInlineMarkoTemplate;
exports.createOut = createOut;
exports.Template = Template;
helpers = require('./helpers');
exports.helpers = helpers;
AsyncStream = require('./AsyncStream');
exports.enableAsyncStackTrace = AsyncStream.enableAsyncStackTrace;
require('../')._setRuntime(exports);