marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
171 lines (134 loc) • 5.13 kB
JavaScript
"use strict"; // eslint-disable-next-line no-constant-binary-expression
var componentLookup = require("@internal/components-util")._n_;
var req = require("@internal/require");
var makeRenderable = require("../../renderable");
var getComponentsContext =
require("../ComponentsContext").T_;
var modernRenderer = require("../renderer");
var resolveComponentKey = modernRenderer.aZ_;
module.exports = function defineRenderer(renderingLogic) {
var renderer = renderingLogic.renderer;
if (renderer && renderer.b__) {
return renderer;
}
var template = renderingLogic.template;
if (typeof template === "string") {
template = req(template);
}
if (template && template.default) {
template = template.default;
}
if (!renderer) {
var getInitialProps;
var getTemplateData;
var getInitialState;
var getWidgetConfig;
var getInitialBody;
if (renderingLogic) {
getInitialProps = renderingLogic.getInitialProps;
getTemplateData = renderingLogic.getTemplateData;
getInitialState = renderingLogic.getInitialState;
getWidgetConfig = renderingLogic.getWidgetConfig;
getInitialBody = renderingLogic.getInitialBody;
}
// Create a renderer function that takes care of translating
// the input properties to a view state. Also, this renderer
// takes care of re-using existing components.
renderer = function renderer(input, out) {
var componentsContext = getComponentsContext(out);
var globalComponentsContext = componentsContext.p_;
var component = globalComponentsContext.aB_;
var isReceivingNewInput = !component || component._j_;
var parentComponentDef;
if (component) {
component._j_ = false;
}
// Render the template associated with the component using the final template
// data that we constructed
var newProps = input;
var widgetConfig;
var widgetState;
var widgetBody;
var id;
if (!component && componentLookup) {
var key = out.ac_;
if (
(parentComponentDef = componentsContext.o_) &&
key != null)
{
id = resolveComponentKey(key.toString(), parentComponentDef);
} else if (parentComponentDef) {
id = parentComponentDef.aQ_();
} else {
id = globalComponentsContext.aQ_();
}
component = componentLookup[id];
}
if (isReceivingNewInput) {
// If we do not have state then we need to go through the process
// of converting the input to a widget state, or simply normalizing
// the input using getInitialProps
if (getInitialProps) {
// This optional method is used to normalize input state
newProps = getInitialProps(newProps, out) || {};
}
if (getInitialState) {
// This optional method is used to derive the widget state
// from the input properties
widgetState = getInitialState(newProps, out);
}
if (getInitialBody) {
// If we have widget a widget body then pass it to the template
// so that it is available to the widget tag and can be inserted
// at the w-body marker
widgetBody = getInitialBody(newProps, out);
} else {
// Default to using the nested content as the widget body
// getInitialBody was not implemented
widgetBody = newProps.renderBody;
}
} else if (component) {
newProps = newProps || component.O_;
widgetBody = component.___;
widgetState = component.aE_;
widgetConfig = component.widgetConfig;
}
// Use getTemplateData(state, props, out) to get the template
// data. If that method is not provided then just use the
// the state (if provided) or the input data.
var templateData = clone(
getTemplateData ?
getTemplateData(widgetState, newProps, out) :
widgetState || newProps
);
if (isReceivingNewInput && getWidgetConfig) {
// If getWidgetConfig() was implemented then use that to
// get the widget config. The widget config will be passed
// to the widget constructor. If rendered on the server the
// widget config will be serialized.
widgetConfig = getWidgetConfig(newProps, out);
}
// eslint-disable-next-line no-constant-condition
templateData.widgetProps = newProps;
widgetBody && (templateData.renderBody = widgetBody);
widgetState && (templateData.widgetState = widgetState);
widgetConfig && (templateData.widgetConfig = widgetConfig);
template._(templateData, out, id, renderingLogic);
};
}
renderer.b__ = true;
renderer.createOut = template ? template.createOut : renderingLogic.createOut;
renderer.template = template;
makeRenderable(renderer, renderer);
renderer.render = renderer.render.bind(renderer);
return renderer;
};
function clone(src) {
var result = {};
if (src) {
for (var key in src) {
result[key] = src[key];
}
}
return result;
}