UNPKG

jsharmony-cms

Version:
236 lines (199 loc) 9.1 kB
/* 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/>. */ var _ = require('lodash'); var Cloner = require('../utils/cloner'); var FieldModel = require('./fieldModel'); /** @typedef {DataModelTemplate_FormPreview} DataModelTemplate_FormPreview */ /** * @class * @classdesc Normalizes the model for use in the form preview * editor. Creates a model template that can then be used to generate * unique instances of the model for editing. * @param {import('./componentTemplate').ComponentTemplate} componentTemplate * @param {object} dataModel - the raw data model from the component config */ function DataModelTemplate_FormPreview(componentTemplate, dataModel) { /** @private @type {Object} */ this._jsh = componentTemplate._jsh; /** @private @type {Object} */ this._cms = componentTemplate._cms; /** @private @type {Object} */ this._componentTemplate = componentTemplate; /** @private @type {string} */ this._componentTemplateId = componentTemplate.getTemplateId(); /** @private @type {string} */ this._itemTemplate = ''; /** @private @type {object} */ this._modelTemplate = {}; /** @private @type {string} */ this._rawOriginalJs = ''; this.buildTemplate(componentTemplate, dataModel); } /** * @private * @param {import('./componentTemplate').ComponentTemplate} componentTemplate * @param {object} dataModel - the raw data model from the component config */ DataModelTemplate_FormPreview.prototype.buildTemplate = function(componentTemplate, dataModel) { var modelConfig = Cloner.deepClone(dataModel || {}); if (modelConfig.layout !== 'grid_preview' && modelConfig.layout !== 'form') return undefined; var componentConfig = this._componentTemplate && this._componentTemplate._componentConfig; if(modelConfig.js && _.isString(modelConfig.js) && modelConfig.js.trim()) modelConfig.js = '(function(){ var cms = '+this._cms._instance+';' + modelConfig.js + ' })();'; this._rawOriginalJs = '\r\n' + (modelConfig.js || '') + '\r\n'; var popup = _.isArray(modelConfig.popup) ? modelConfig.popup : []; var fields = modelConfig.fields || []; fields.unshift({ control:'html', value:'<div class="jsharmony_cms">', captionclass:'hidden'}); fields.push({ control:'html', value:'</div>', captionclass:'hidden'}); fields.push({ caption: '', control:'html', value:'<div class="jsharmony_cms_preview_editor jsharmony_cms_component_preview" data-id="previewWrapper"></div>', 'block':true, captionclass:'hidden' }); var model = _.extend({}, modelConfig); this._modelTemplate = model; model.title = modelConfig.title ? modelConfig.title : 'Edit ' + componentTemplate.getCaptions()[1]; model.popup = [ _.isNumber(popup[0]) ? popup[0] : 400, _.isNumber(popup[1]) ? popup[1] : 200 ]; model.fields = fields; model.layout = 'form'; model.unbound = true; model.onecolumn = true; model.formclass = ((model.formclass||'')+' '+(componentConfig&&componentConfig.options&&componentConfig.options.component_preview_size=='collapse'?'jsharmony_cms_component_preview_collapse':'jsharmony_cms_component_preview_expand')).trim(); model.ejs = ''; model.js = this._rawOriginalJs; this._jsh.XPage.ParseModelDefinition(model, null, null, { ignoreErrors: true }); _.forEach(fields, function(field) { if (field.type != undefined && field.mediaBrowserControlInfo == undefined) { field.onchange = '(function() { var m = jsh.App[modelid]; if (m && m.onChangeData) m.onChangeData(); })()'; } }); var templateHtml = '<div>' + modelConfig.ejs + '</div>'; var itemTemplate = ''; var selItemPreview = (modelConfig.templates || {}).itemPreview; if(selItemPreview){ //If itemPreview is set, extract the template from the model.ejs file var itemPreview = this._jsh.$(templateHtml).find(selItemPreview); if (itemPreview.length > 1) throw new Error('Item template must contain a single root element. Found ' + itemPreview.length + ' elements'); itemTemplate = itemPreview ? itemPreview.html() : undefined; } else { //If templates are not used, return the entire model.ejs as the template itemTemplate = templateHtml; } this._itemTemplate = itemTemplate; }; /** * Get the link browser field info (if exists) for the link field with * the given field name. * @public * @param {string} fieldName * @returns {(import('./componentTemplate').MediaBrowserControlInfo | undefined)} */ DataModelTemplate_FormPreview.prototype.getBrowserFieldInfo = function(fieldName) { var field = _.find(this._modelTemplate.fields, function(field) { return field.mediaBrowserControlInfo && field.mediaBrowserControlInfo.dataFieldName === fieldName; }); return field ? field.mediaBrowserControlInfo : undefined; }; /** * Get the link browser field infos * @public * @returns {import('./componentTemplate').MediaBrowserControlInfo[]]} */ DataModelTemplate_FormPreview.prototype.getBrowserFieldInfos = function() { var retVal = []; _.forEach(this._modelTemplate.fields, function(field) { if (field.mediaBrowserControlInfo) { retVal.push(field.mediaBrowserControlInfo); } }); return retVal; }; /** * Get the EJS string used to render the item preview * @public * @returns {string} */ DataModelTemplate_FormPreview.prototype.getItemTemplate = function() { return this._itemTemplate || ''; }; /** * @public */ DataModelTemplate_FormPreview.prototype.getModelInstance = function() { var model = Cloner.deepClone(this._modelTemplate); model.id = DataModelTemplate_FormPreview.getNextInstanceId(this._componentTemplate); return model; }; /** * Return the raw model JavaScript. * @public * @returns {Object} */ DataModelTemplate_FormPreview.prototype.getModelJs = function() { return this._rawOriginalJs; }; /** * Get a unique ID for the model instance * @private * @returns {string} */ DataModelTemplate_FormPreview.getNextInstanceId = function(componentTemplate) { if (DataModelTemplate_FormPreview._id == undefined) DataModelTemplate_FormPreview._id = 0; var id = DataModelTemplate_FormPreview._id++; return 'DataModel_FormPreview_' + componentTemplate.getClassName() + '_' + id; }; /** * Create a pristine copy of the data. * This will remove extraneous properties (that don't exist in the model) * and do data conversions. It will also add missing fields. * The returned value will match the field model exactly. * * NOTE: this does not set default values! If the value is not set in * dataInstance then the property will be set to undefined. * * @public * @param {Object} dataInstance - the existing field values. * @returns {Object} a copy of the dataInstance with type conversions done and extraneous * properties removed. */ DataModelTemplate_FormPreview.prototype.makePristineCopy = function(dataInstance) { return FieldModel.makePristineCopy(dataInstance, this._modelTemplate.fields); }; /** * Iterates through the fieldModels * to look for fields with "type" property. If a field has the type property * then the field will be added to the new data instance object. * * Setting the field follows specific rules * 1. If the data instance does not contain the property key * then the property is set to either undefined or the default value. * 2. If the data instance contains the property and the property value is * defined then it is left as-is. * 3. If the data instance contains the property and the property value is * null/undefined then the property is overridden if there is a default AND * it is a required field. If it is not required then the value is left as * null/undefined (which allows the user to clear default values that are * not required fields). * * This will also correctly convert values as needed. * * This mutates the dataInstance. * @public * @param {Object} dataInstance - the data instance. Each property corresponds * to a field in the field array. This object will be mutated. * @returns {Object} the new or mutated data */ DataModelTemplate_FormPreview.prototype.populateDataInstance = function(dataInstance) { return FieldModel.populateDataInstance(dataInstance, this._modelTemplate.fields || []); }; exports = module.exports = DataModelTemplate_FormPreview;