UNPKG

ui-framework-jps

Version:

A simple UI framework for state management and UI components

463 lines 20.8 kB
import { BasicFieldOperations } from "../../model/BasicFieldOperations"; import { FieldType } from "../../model/DataObjectTypeDefs"; import debug from 'debug'; import { RBGFieldOperations } from "./RBGFieldOperations"; import { FIELD_CreatedOn, FIELD_ModifiedOn } from "../../model/BasicObjectDefinitionFactory"; import { ColourEditor } from "./ColourEditor"; import { defaultGetValue, FieldLabelPosition, UIFieldType, UndefinedBoolean } from "../../CommonTypes"; const logger = debug('bootstrap-form-config-helper'); export class BootstrapFormConfigHelper { constructor() { } static getInstance() { if (!(BootstrapFormConfigHelper._instance)) { BootstrapFormConfigHelper._instance = new BootstrapFormConfigHelper(); } return BootstrapFormConfigHelper._instance; } generateConfig(dataObjDef, runtimeConfig) { let fieldOperations = new BasicFieldOperations(); let rbgFieldOperation = new RBGFieldOperations(); // create a form with a single group and button container with Bootstrap styles let fieldGroup = { containedBy: { type: 'div', classes: 'col-sm-12', }, fields: [] }; let shouldAutoScroll = false; if (runtimeConfig.autoscrollOnNewContent) { shouldAutoScroll = (runtimeConfig.autoscrollOnNewContent === UndefinedBoolean.true); } let shouldAutoSave = false; if (runtimeConfig.autoSave) { shouldAutoSave = (runtimeConfig.autoSave === UndefinedBoolean.true); } const formConfig = { id: dataObjDef.id, displayName: dataObjDef.displayName, fieldGroups: [fieldGroup], unsavedChanges: { type: 'div', classes: 'invalid-feedback text-right col-md-12 col-lg-9 offset-lg-3', attributes: [{ name: 'style', value: 'display:block' }], innerHTML: `Pending changes to ${dataObjDef.displayName}`, }, buttonPosition: runtimeConfig.buttonLocation, autoscrollOnNewContent: shouldAutoScroll, autoSave: shouldAutoSave }; // create the Field UI config for each field let fieldUIConfigs = []; dataObjDef.fields.forEach((fieldDef, index) => { let fieldType = UIFieldType.text; switch (fieldDef.type) { case (FieldType.time): case (FieldType.text): case (FieldType.date): case (FieldType.shortTime): case (FieldType.colour): case (FieldType.duration): { break; } case (FieldType.datetime): { // is this the created or modified date if (runtimeConfig.hideModifierFields) { if (fieldDef.id === FIELD_CreatedOn) { fieldType = UIFieldType.hidden; } if (fieldDef.id === FIELD_ModifiedOn) { fieldType = UIFieldType.hidden; } } break; } case (FieldType.userId): { if (runtimeConfig.hideModifierFields) { fieldType = UIFieldType.hidden; } else { fieldType = UIFieldType.text; } break; } case (FieldType.uuid): case (FieldType.id): { fieldType = UIFieldType.hidden; break; } case (FieldType.integer): case (FieldType.float): { fieldType = UIFieldType.number; break; } case (FieldType.email): { fieldType = UIFieldType.email; break; } case (FieldType.password): { fieldType = UIFieldType.password; break; } case (FieldType.boolean): { fieldType = UIFieldType.checkbox; break; } case (FieldType.largeText): { fieldType = UIFieldType.textarea; break; } case (FieldType.choice): { fieldType = UIFieldType.select; break; } case (FieldType.limitedChoice): { fieldType = UIFieldType.radioGroup; break; } case (FieldType.compositeObjectArray): { fieldType = UIFieldType.list; break; } case (FieldType.compositeObject): { fieldType = UIFieldType.composite; break; } case (FieldType.linkedObject): { fieldType = UIFieldType.linked; break; } case (FieldType.linkedObjectArray): { fieldType = UIFieldType.linkedList; break; } } // see if the field was supplied with a display order const displayOrder = runtimeConfig.fieldDisplayOrders.find((value) => value.fieldId === fieldDef.id); let displayOrderValue = index; if (displayOrder) { displayOrderValue = displayOrder.displayOrder; } // construct the field ui config let fieldUIConfig = { field: fieldDef, displayOrder: displayOrderValue, elementType: fieldType, elementClasses: 'form-control col-sm-9', renderer: fieldOperations, formatter: fieldOperations, getValue: defaultGetValue }; if ((fieldDef.type !== FieldType.id) && (fieldDef.type !== FieldType.uuid) && (fieldType !== UIFieldType.hidden) && (fieldType !== UIFieldType.list) && (fieldType !== UIFieldType.composite) && (fieldType !== UIFieldType.linked) && (fieldType !== UIFieldType.linkedList)) { // no labels, descriptions, container for id,uuid fieldUIConfig.containedBy = { type: 'div', classes: 'form-group row' }; fieldUIConfig.label = { label: fieldDef.displayName, classes: 'col-md-12 col-lg-3 col-form-label' }; if (fieldDef.description) { // descriptions if the field has one fieldUIConfig.describedBy = { message: fieldDef.description, elementType: 'small', elementClasses: 'text-muted col-md-12 col-lg-9 offset-lg-3 mt-1' }; } if (!fieldDef.displayOnly) { // no validator for readonly items fieldUIConfig.validator = { validator: fieldOperations, messageDisplay: { type: 'div', classes: 'invalid-feedback col-md-12 col-lg-9 offset-lg-3' }, validClasses: 'is-valid', invalidClasses: 'is-invalid', }; } } // text areas if (fieldDef.type === FieldType.largeText) { fieldUIConfig.textarea = { rows: 5, cols: 20 }; } // select if (fieldDef.type === FieldType.choice) { // subelements are options, with no classes, no labels, and no other container fieldUIConfig.subElement = { element: { type: 'option', classes: '' }, }; fieldUIConfig.datasource = fieldDef.dataSource; } // composite object (single) // if (fieldDef.type === FieldType.compositeObject) { // subelements are options, with no classes, no labels, and no other container // fieldUIConfig.extraActions = [ // { // name:'Edit', // button: { // classes:'btn bg-primary', // iconClasses:'fas fa-edit' // }, // confirm:false // } // ] // fieldUIConfig.validator = undefined; // } // // composite object (array) // if (fieldDef.type === FieldType.compositeObjectArray) { // subelements are options, with no classes, no labels, and no other container // fieldUIConfig.subElement = { // element: { // type: 'li', // classes: 'list-group-item' // }, // container: { // type: 'div', // classes: 'form-check form-check-inline' // }, // }; // fieldUIConfig.extraActions = [ // { // name:'Edit', // button: { // classes:'btn bg-primary', // iconClasses:'fas fa-edit' // }, // confirm:false // } // ] // fieldUIConfig.renderer = undefined; // fieldUIConfig.validator = undefined; // fieldUIConfig.formatter = undefined; // } // // composite object (single) // if (fieldDef.type === FieldType.linkedObject) { // subelements are options, with no classes, no labels, and no other container // fieldUIConfig.extraActions = [ // { // name:'Edit', // button: { // classes:'btn bg-primary', // iconClasses:'fas fa-edit' // }, // confirm:false // } // ] // fieldUIConfig.renderer = undefined; // fieldUIConfig.validator = undefined; // fieldUIConfig.formatter = undefined; // } // // composite object (array) // if (fieldDef.type === FieldType.linkedObjectArray) { // subelements are options, with no classes, no labels, and no other container // fieldUIConfig.subElement = { // element: { // type: 'li', // classes: 'list-group-item' // }, // container: { // type: 'div', // classes: 'form-check form-check-inline' // }, // }; // fieldUIConfig.extraActions = [ // { // name:'Edit', // button: { // classes:'btn bg-primary', // iconClasses:'fas fa-edit' // }, // confirm:false // } // ] // fieldUIConfig.renderer = undefined; // fieldUIConfig.validator = undefined; // fieldUIConfig.formatter = undefined; // } // radio button group if (fieldDef.type === FieldType.limitedChoice) { fieldUIConfig.subElement = { element: { type: 'input', classes: 'form-check-input', attributes: [{ name: 'type', value: 'radio' }] }, container: { type: 'div', classes: 'form-check form-check-inline' }, label: { label: 'label', classes: 'form-check-label', }, }; fieldUIConfig.renderer = rbgFieldOperation; if (fieldUIConfig.validator) fieldUIConfig.validator.validator = rbgFieldOperation; fieldUIConfig.formatter = rbgFieldOperation; fieldUIConfig.datasource = fieldDef.dataSource; } if (fieldDef.type === FieldType.colour) { fieldUIConfig.editor = new ColourEditor(BootstrapFormConfigHelper.COLOUR_PICKER_CONTAINER); } // see if the field was supplied with a field runtime if (runtimeConfig.fieldRuntimeConfigs) { const fieldRuntime = runtimeConfig.fieldRuntimeConfigs.find((runtimeField) => runtimeField.fieldId === fieldUIConfig.field.id); if (fieldRuntime) { if (fieldRuntime.containedBy && fieldUIConfig.containedBy) { fieldUIConfig.containedBy = fieldRuntime.containedBy; } if (fieldRuntime.validator) { if (fieldUIConfig.validator) fieldUIConfig.validator.validator = fieldRuntime.validator; } if (fieldRuntime.label) { if (fieldRuntime.label.labelPosition === FieldLabelPosition.noLabel) { fieldUIConfig.label = undefined; if (fieldUIConfig.containedBy) { fieldUIConfig.containedBy.classes = 'form-group row'; } else { fieldUIConfig.elementClasses = 'form-control'; } } if (fieldRuntime.label.labelPosition === FieldLabelPosition.aboveField) { if (fieldUIConfig.containedBy) { fieldUIConfig.containedBy.classes = 'form-group row'; } } if (fieldRuntime.label.label) { if (fieldUIConfig.label) fieldUIConfig.label.label = fieldRuntime.label.label; } } if (fieldRuntime.editor) { fieldUIConfig.editor = fieldRuntime.editor; } if (fieldRuntime.renderer) { fieldUIConfig.renderer = fieldRuntime.renderer; } if (fieldRuntime.extraActions) { fieldUIConfig.extraActions = fieldRuntime.extraActions; } if (fieldRuntime.elementClasses) { fieldUIConfig.elementClasses = fieldRuntime.elementClasses; } // change dimensions and layout if needed if (fieldRuntime.fieldDimensions) { fieldUIConfig.containedBy = { type: 'div', classes: `col-sm-12 col-md-${fieldRuntime.fieldDimensions.columnSpan}` }; if (fieldRuntime.fieldDimensions.spacingClasses) { fieldUIConfig.containedBy.classes += ' ' + fieldRuntime.fieldDimensions.spacingClasses; } if (fieldUIConfig.label) { fieldUIConfig.label.classes = 'col-12 col-form-label'; } } } } fieldUIConfigs.push(fieldUIConfig); }); if (!runtimeConfig.hasExternalControl) { formConfig.buttonsContainedBy = { type: 'div', classes: 'd-flex w-100 justify-space-between mb-2', }; formConfig.cancelButton = { text: '', classes: 'btn-info rounded p-1 mr-2 mt-2 w-100', iconClasses: 'fas fa-ban' }; formConfig.saveButton = { text: '', classes: 'btn-primary rounded p-1 mt-2 w-100', iconClasses: 'fas fa-save' }; formConfig.activeSave = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>&nbsp;'; } // sort the fields into display order // if runtime config has groups, use those instead if (runtimeConfig.fieldGroups) { formConfig.fieldGroups = []; runtimeConfig.fieldGroups.forEach((runtimeGroup) => { let fieldGroup = { containedBy: runtimeGroup.containedBy, fields: [] }; if (runtimeGroup.subGroups) { fieldGroup.subGroups = []; runtimeGroup.subGroups.forEach((subRuntimeGroup) => { let fieldSubgroup = { containedBy: subRuntimeGroup.containedBy, fields: [] }; subRuntimeGroup.fields.forEach((subRuntimeFieldId) => { const foundIndex = fieldUIConfigs.findIndex((fieldUIConfig) => fieldUIConfig.field.id === subRuntimeFieldId); if (foundIndex >= 0) { fieldSubgroup.fields.push(fieldUIConfigs[foundIndex]); } }); // @ts-ignore fieldGroup.subGroups.push(fieldSubgroup); }); } runtimeGroup.fields.forEach((runtimeFieldId) => { const foundIndex = fieldUIConfigs.findIndex((fieldUIConfig) => fieldUIConfig.field.id === runtimeFieldId); if (foundIndex >= 0) { fieldGroup.fields.push(fieldUIConfigs[foundIndex]); } }); formConfig.fieldGroups.push(fieldGroup); }); // now find the fields that weren't in the runtime field groups and put them in another default field group const defaultFieldGroup = { containedBy: { type: 'div', classes: 'col-sm-12', }, fields: [] }; fieldUIConfigs.forEach((fieldUIConfig) => { if (!this.isFieldInCurrentFieldGroups(formConfig, fieldUIConfig)) { defaultFieldGroup.fields.push(fieldUIConfig); } }); if (defaultFieldGroup.fields.length > 0) formConfig.fieldGroups.unshift(defaultFieldGroup); } else { formConfig.fieldGroups[0].fields = fieldUIConfigs; } formConfig.fieldGroups.forEach((group) => { group.fields.sort((a, b) => { return (a.displayOrder - b.displayOrder); }); }); if (runtimeConfig.deleteButton && !runtimeConfig.hasExternalControl) { formConfig.deleteButton = { text: '', classes: 'btn-warning rounded p-1 mr-2 mt-2 w-100', iconClasses: 'fas fa-trash-alt' }; } logger(formConfig); return formConfig; } getElementIdForDataFieldId(fieldId) { return undefined; } isFieldInCurrentFieldGroups(formConfig, field) { let result = false; formConfig.fieldGroups.forEach((fieldGroup) => { const foundIndex = fieldGroup.fields.findIndex((fieldInGroup) => fieldInGroup.field.id === field.field.id); if (foundIndex >= 0) { result = true; } }); return result; } } BootstrapFormConfigHelper.COLOUR_PICKER_CONTAINER = 'framework-colour-picker-container'; BootstrapFormConfigHelper.SLIDE_BAR_CONTAINER = 'framework-slider-container'; //# sourceMappingURL=BootstrapFormConfigHelper.js.map