var escapeXml = require('raptor-util/escapeXml'); var escapeXmlAttr = escapeXml.attr; var runtime = require('./'); // Circular dependnecy, but that is okay var extend = require('raptor-util/extend'); var attr = require('raptor-util/attr'); var attrs = require('raptor-util/attrs'); var forEach = require('raptor-util/forEach'); var markoRegExp = /\.marko(.xml|.html)?$/; var req = require; var arrayFromArguments = require('raptor-util/arrayFromArguments'); var logger = require('raptor-logging').logger(module); function notEmpty(o) { if (o == null) { return false; } else if (Array.isArray(o)) { return !!o.length; } else if (o === '') { return false; } return true; } function createLazyRenderer(handler) { var lazyRenderer = function(input, out) { lazyRenderer.renderer(input, out); }; // This is the initial function that will do the rendering. We replace // the renderer with the actual renderer func on the first render lazyRenderer.renderer = function(input, out) { var rendererFunc = handler.renderer || handler.render; if (typeof renderFunc !== 'function') { throw new Error('Invalid tag handler: ' + handler); } // Use the actual renderer from now on lazyRenderer.renderer = rendererFunc; rendererFunc(input, out); }; return lazyRenderer; } var WARNED_INVOKE_BODY = 0; module.exports = { s: function(str) { return (str == null) ? '' : str; }, fv: function (array, callback) { if (!array) { return; } if (!array.forEach) { array = [array]; } var i = 0; var len = array.length; var loopStatus = { getLength: function () { return len; }, isLast: function () { return i === len - 1; }, isFirst: function () { return i === 0; }, getIndex: function () { return i; } }; for (; i < len; i++) { var o = array[i]; callback(o || '', loopStatus); } }, f: forEach, fl: function (array, func) { if (array != null) { if (!Array.isArray(array)) { array = [array]; } func(array, 0, array.length); } }, fp: function (o, func) { if (!o) { return; } for (var k in o) { if (o.hasOwnProperty(k)) { func(k, o[k]); } } }, e: function (o) { return !notEmpty(o); }, ne: notEmpty, x: escapeXml, xa: escapeXmlAttr, nx: function (str) { return { toString: function () { return str; } }; }, a: attr, as: attrs, /** * Loads a template */ l: function(path) { if (typeof path === 'string') { if (markoRegExp.test(path)) { return runtime.load(path); } else { return req('view-engine').load(path); } } else if (path.render) { // Assume it is already a pre-loaded template return path; } else { return runtime.load(path); } }, /** * Returns the render function for a tag handler */ r: function(handler) { var renderFunc = handler.renderer || handler.render || handler; // If the user code has a circular function then the renderer function // may not be available on the module. Since we can't get a reference // to the actual renderer(input, out) function right now we lazily // try to get access to it later. if (typeof renderFunc !== 'function') { return createLazyRenderer(handler); } return renderFunc; }, // ---------------------------------- // Helpers that require an out below: // ---------------------------------- /** * Invoke a tag handler render function */ t: function (out, renderFunc, input, body, hasOutParam) { if (!input) { input = {}; } if (body) { input.renderBody = body; input.invokeBody = function() { if (!WARNED_INVOKE_BODY) { WARNED_INVOKE_BODY = 1; logger.warn('invokeBody(...) deprecated. Use renderBody(out) instead.', new Error().stack); } if (!hasOutParam) { var args = arrayFromArguments(arguments); args.unshift(out); body.apply(this, args); } else { body.apply(this, arguments); } }; } renderFunc(input, out); }, c: function (out, func) { var output = out.captureString(func); return { toString: function () { return output; } }; }, i: function(out, path, data) { if (!path) { return; } if (data.body) { data.invokeBody = function() { if (!WARNED_INVOKE_BODY) { WARNED_INVOKE_BODY = 1; logger.warn('data.invokeBody() deprecated. Use data.body instead.', new Error().stack); } return data.body; }; } if (typeof path === 'string') { runtime.render(path, data, out); } else if (typeof path.render === 'function') { path.render(data, out); } else { throw new Error('Invalid template'); } return this; }, xt: extend };