jsharmony-cms
Version:
193 lines (165 loc) • 7.06 kB
JavaScript
/*
Copyright 2020 apHarmony
This file is part of jsHarmony.
jsHarmony is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jsHarmony is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this package. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @typedef {Object} RenderConfig
* @property {Object} data - the component data
* @property {Object} properties - the component properties
* @property {string} template - the template being rendered
* @property {string} baseUrl
* @property {(GridPreviewRenderContext | undefined )} gridContext
*/
/**
* @typedef {Object} RenderContext
* @property {Object} data - the component data
* @property {Object} properties - the component properties
* @property {('component' | 'gridRowDataPreview' | 'gridItemPreview')} type
* @property {string} baseUrl
* @property {(GridPreviewRenderContext | undefined )} gridContext
*/
/**
* @typedef {Object} GridPreviewRenderContext
* @property {number} rowIndex
*/
/**
* @class
* @public
* @static
*/
function TemplateRenderer() {}
/**
* Create a mutable object that can be preprocessed before rendering.
* @public
* @static
* @param {string} template
* @param {Object} data - the component data
* @param {Object} properties - the component properties
* @param {Object} cms
* @returns {RenderConfig}
*/
TemplateRenderer.createRenderConfig = function(template, data, properties, cms) {
/** @type {RenderConfig} */
var config = {
data: data,
properties: properties,
template: template,
baseUrl: (cms._baseurl || '').replace(/\/+$/, '') + '/',
};
return config;
};
/**
* @public
* @static
* @param {('component' | 'gridRowDataPreview' | 'gridItemPreview')} type
* @param {RenderConfig} config
* @param {Object} jsh
* @param {Object} cms
* @returns {string}
*/
TemplateRenderer.render = function(config, type, jsh, cms, componentConfig, additionalRenderParams) {
var _ = jsh._;
var XValidate = jsh.XValidate;
var renderPlaceholder = function(params){
return jsh.RenderEJS(jsh.GetEJS('jsHarmonyCMS.ComponentPlaceholder'),_.extend({
componentConfig: componentConfig,
XExt: jsh.XExt,
errors: '',
}, params));
};
var renderOptions = {
renderType: type,
data: null,
properties: config.properties || {},
};
if(config.data && ('items' in config.data)) renderOptions.data = config.data.items;
else if(config.data && ('item' in config.data)) renderOptions.data = config.data.item;
else{
if(componentConfig && (componentConfig.multiple_items)) renderOptions.data = [];
else renderOptions.data = {};
}
var renderContext = cms.componentManager.getComponentRenderParameters(null, renderOptions, _.extend({
baseUrl: config.baseUrl,
gridContext: config.gridContext,
isInEditor: true,
isInPageEditor: true,
isInComponentEditor: ((type=='gridRowDataPreview') || (type=='gridItemPreview')),
componentRenderClass: 'jsharmony_cms_componentRender_'+jsh.XExt.escapeCSSClass((componentConfig&&componentConfig.id)||'')+'_'+cms.componentManager.getUniqueId().toString(),
getMediaThumbnails: function(url){ return cms.componentManager.getMediaThumbnails(url); },
renderPlaceholder: renderPlaceholder,
}, additionalRenderParams));
if(componentConfig){
var generateValidators = function(model){
var xvalidate = new XValidate(jsh);
if(model){
_.each(model.fields, function(field){
if(field.validate && field.name){
for(var j=0;j<field.validate.length;j++){
var validator = jsh.XPage.ParseValidator(field.validate[j], { actions: 'BIU' }, field, 'BIU');
for(var i=0;i<validator.funcs.length;i++){
if(!_.isFunction(validator.funcs[i])) validator.funcs[i] = eval(validator.funcs[i]);
}
xvalidate.AddValidator('_obj.'+field.name, validator.caption, validator.actions, validator.funcs);
}
}
});
}
return xvalidate;
};
var validate = function(xvalidate, data, desc){
var verrors = xvalidate.Validate('B', data||{});
if (!_.isEmpty(verrors)) return 'Error: ' + desc + '\n' + verrors[''].join('\n');
return '';
};
//Generate missing validators
var dataValidators = generateValidators(componentConfig.data);
var propertyValidators = generateValidators(componentConfig.properties);
//Show placeholder if editor_placeholder.items_empty=true, and multiple_items, and empty items array
if(componentConfig.editor_placeholder && componentConfig.editor_placeholder.items_empty){
if((componentConfig.multiple_items) && (!renderContext.items || !renderContext.items.length)){
return renderPlaceholder();
}
}
//Show placeholder if editor_placeholder.invalid_fields=true
if(componentConfig.editor_placeholder && componentConfig.editor_placeholder.invalid_fields){
//Single item, validation error in data or properties
if(!componentConfig.multiple_items){
let dataErrors = validate(dataValidators, renderContext.item, 'Component Data');
if(dataErrors) return renderPlaceholder({ errors: dataErrors });
let propertyErrors = validate(propertyValidators, renderContext.properties, 'Component Configuration');
if(propertyErrors) return renderPlaceholder({ errors: propertyErrors });
}
else if(componentConfig.multiple_items){
let propertyErrors = validate(propertyValidators, renderContext.properties, 'Component Configuration');
if(propertyErrors) return renderPlaceholder({ errors: propertyErrors });
}
}
if(componentConfig.multiple_items){
for(var i=0;i<renderContext.items.length;i++){
let dataErrors = validate(dataValidators, renderContext.items[i], 'Component Data');
if(dataErrors) renderContext.items[i].jsh_validation_errors = dataErrors;
}
}
}
var rendered = '';
try {
rendered = jsh.ejs.render(config.template || '', renderContext);
} catch (error) {
rendered = cms.componentManager.formatComponentError('Component Rendering Error: '+error.toString());
console.log('Render Context:'); // eslint-disable-line no-console
console.log(renderContext); // eslint-disable-line no-console
console.error(error); // eslint-disable-line no-console
}
return rendered;
};
exports = module.exports = TemplateRenderer;