diff --git a/src/plugins/index.js b/src/plugins/index.js index 3f295b6..2c8538b 100644 --- a/src/plugins/index.js +++ b/src/plugins/index.js @@ -14,6 +14,8 @@ import viewDataviewEditor from "./web_view_dataview/FNAbviewdataviewEditor.js"; import viewDataviewProperties from "./web_view_dataview/FNAbviewdataview.js"; import viewDetailEditor from "./web_view_detail/FNAbviewdetailEditor.js"; import viewDetailProperties from "./web_view_detail/FNAbviewdetail.js"; +import viewFormEditor from "./web_view_form/FNAbviewformEditor.js"; +import viewFormProperties from "./web_view_form/FNAbviewform.js"; import viewGanttEditor from "./web_view_gantt/FNAbviewganttEditor.js"; import viewGanttProperties from "./web_view_gantt/FNAbviewgantt.js"; import viewGridEditor from "./web_view_grid/FNAbviewgridEditor.js"; @@ -51,6 +53,8 @@ const AllPlugins = [ viewDataviewProperties, viewDetailEditor, viewDetailProperties, + viewFormEditor, + viewFormProperties, viewGanttEditor, viewGanttProperties, viewGridEditor, diff --git a/src/plugins/web_view_form/FNAbviewform.js b/src/plugins/web_view_form/FNAbviewform.js new file mode 100644 index 0000000..1ba128a --- /dev/null +++ b/src/plugins/web_view_form/FNAbviewform.js @@ -0,0 +1,799 @@ +import FNAbviewFormButtonProperties from "./properties/FNAbviewFormButton.js"; +import FNAbviewFormCheckboxProperties from "./properties/FNAbviewFormCheckbox.js"; +import FNAbviewFormConnectProperties from "./properties/FNAbviewFormConnect.js"; +import FNAbviewFormCustomProperties from "./properties/FNAbviewFormCustom.js"; +import FNAbviewFormDatepickerProperties from "./properties/FNAbviewFormDatepicker.js"; +import FNAbviewFormJsonProperties from "./properties/FNAbviewFormJson.js"; +import FNAbviewFormNumberProperties from "./properties/FNAbviewFormNumber.js"; +import FNAbviewFormSelectMultipleProperties from "./properties/FNAbviewFormSelectMultiple.js"; +import FNAbviewFormSelectSingleProperties from "./properties/FNAbviewFormSelectSingle.js"; +import FNAbviewFormTextboxProperties from "./properties/FNAbviewFormTextbox.js"; +import FNAbviewFormTreeProperties from "./properties/FNAbviewFormTree.js"; +import FNAbviewFormUrlProperties from "./properties/FNAbviewFormUrl.js"; + +export default function FNAbviewformProperties({ + AB, + ABViewPropertiesPlugin, + // ABUIPlugin, +}) { + const FABViewContainer = + require("../../rootPages/Designer/properties/views/ABViewContainer").default; + const FABViewRuleListFormRecordRules = + require("../../rootPages/Designer/properties/rules/ABViewRuleListFormRecordRules").default; + const FABViewRuleListFormSubmitRules = + require("../../rootPages/Designer/properties/rules/ABViewRuleListFormSubmitRules").default; + + const ABViewContainer = FABViewContainer(AB); + const uiConfig = AB.Config.uiSettings(); + const L = ABViewContainer.L(); + + var ABViewFormPropertyComponentDefaults = {}; + + const base = "properties_abview_form"; + + const PopupRecordRule = FABViewRuleListFormRecordRules( + AB, + `${base}_popupRecordRule` + ); + + const PopupSubmitRule = FABViewRuleListFormSubmitRules( + AB, + `${base}_popupSubmitRule` + ); + + const ABAbviewformProperties = class ABAbviewformProperties extends ABViewPropertiesPlugin { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + // properties-view : will display in the properties panel of the ABDesigner + } + + constructor(b = null, id = null) { + b = b || base; + id = Object.assign(id || {}, { + // Put our ids here + datacollection: "", + fields: "", + showLabel: "", + labelPosition: "", + labelWidth: "", + height: "", + clearOnLoad: "", + clearOnSave: "", + + buttonSubmitRules: "", + buttonRecordRules: "", + }); + super(b, id); + + this.AB = AB; + ABViewFormPropertyComponentDefaults = + this.AB.ClassManager.viewClass("form").defaultValues(); + } + + static get key() { + return "form"; + } + + ui(elements = null) { + let ids = this.ids; + + elements = elements || []; + + return super.ui( + [ + { + id: ids.datacollection, + view: "richselect", + name: "datacollection", + label: L("Datacollection"), + labelWidth: uiConfig.labelWidthLarge, + skipAutoSave: true, + on: { + onChange: (newId, oldId) => { + this.selectSource(newId, oldId); + }, + }, + }, + + { + view: "fieldset", + label: L("Form Fields:"), + labelWidth: uiConfig.labelWidthLarge, + body: { + type: "clean", + padding: 10, + rows: [ + { + id: ids.fields, + view: "list", + name: "fields", + + select: false, + minHeight: 200, + template: (...params) => { + return this.listTemplate(...params); + }, + type: { + markCheckbox: function (item) { + return ( + "" + ); + }, + }, + onClick: { + check: (...params) => { + return this.check(...params); + }, + }, + }, + ], + }, + }, + { + id: ids.showLabel, + name: "showLabel", + view: "checkbox", + label: L("Display Label"), + labelWidth: uiConfig.labelWidthLarge, + click: () => { + this.onChange(); + }, + }, + { + id: ids.labelPosition, + view: "richselect", + name: "labelPosition", + + label: L("Label Position"), + labelWidth: uiConfig.labelWidthLarge, + options: [ + { + id: "left", + value: L("Left"), + }, + { + id: "top", + value: L("Top"), + }, + ], + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.labelWidth, + view: "counter", + name: "labelWidth", + + label: L("Label Width"), + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.height, + view: "counter", + name: "height", + label: L("Height"), + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.clearOnLoad, + view: "checkbox", + name: "clearOnLoad", + + label: L("Clear on load"), + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.clearOnSave, + view: "checkbox", + name: "clearOnSave", + label: L("Clear on save"), + labelWidth: uiConfig.labelWidthLarge, + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + view: "fieldset", + label: L("Rules:"), + labelWidth: uiConfig.labelWidthLarge, + body: { + type: "clean", + padding: 10, + rows: [ + { + cols: [ + { + view: "label", + label: L("Submit Rules:"), + width: uiConfig.labelWidthLarge, + }, + { + id: ids.buttonSubmitRules, + view: "button", + css: "webix_primary", + name: "buttonSubmitRules", + label: L("Settings"), + icon: "fa fa-gear", + type: "icon", + badge: 0, + click: () => { + this.submitRuleShow(); + }, + }, + ], + }, + // { + // cols: [ + // { + // view: "label", + // label: L("Display Rules:"), + // width: uiConfig.labelWidthLarge, + // }, + // { + // view: "button", + // name: "buttonDisplayRules", + // css: "webix_primary", + // label: L("Settings"), + // icon: "fa fa-gear", + // type: "icon", + // badge: 0, + // click: () => { + // this.displayRuleShow(); + // }, + // }, + // ], + // }, + { + cols: [ + { + view: "label", + label: L("Record Rules:"), + width: uiConfig.labelWidthLarge, + }, + { + id: ids.buttonRecordRules, + view: "button", + name: "buttonRecordRules", + css: "webix_primary", + label: L("Settings"), + icon: "fa fa-gear", + type: "icon", + badge: 0, + click: () => { + this.recordRuleShow(); + }, + }, + ], + }, + ], + }, + }, + ].concat(elements) + ); + } + + async init(AB) { + super.init(AB); + + webix.extend($$(this.ids.component), webix.ProgressBar); + + let allInits = []; + allInits.push(PopupRecordRule.init(AB)); + PopupRecordRule.on("save", () => { + this.onChange(); + this.populateBadgeNumber(); + }); + allInits.push(PopupSubmitRule.init(AB)); + PopupSubmitRule.on("save", (/* settings */) => { + this.onChange(); + this.populateBadgeNumber(); + }); + + return Promise.all(allInits); + } + + populate(view) { + super.populate(view); + let ids = this.ids; + if (!view) return; + + let formCom = view.parentFormComponent(); + let datacollectionId = formCom.settings.dataviewID + ? formCom.settings.dataviewID + : null; + var SourceSelector = $$(ids.datacollection); + + // Pull data collections to options + var dcOptions = view.application + .datacollectionsIncluded() + .filter((dc) => { + const obj = dc.datasource; + return ( + dc.sourceType == "object" && + !obj?.isImported && + !obj?.isReadOnly + ); + }) + .map((d) => { + let entry = { id: d.id, value: d.label }; + if (d.sourceType == "query") { + entry.icon = "fa fa-filter"; + } else { + entry.icon = "fa fa-database"; + } + return entry; + }); + SourceSelector.define("options", dcOptions); + SourceSelector.define("value", datacollectionId); + SourceSelector.refresh(); + + this.propertyUpdateFieldOptions(datacollectionId); + + // update properties when a field component is deleted + view.views().forEach((v) => { + if (v.isFormField) v.once("destroyed", () => this.populate(view)); + }); + + SourceSelector.enable(); + $$(ids.showLabel).setValue(view.settings.showLabel); + $$(ids.labelPosition).setValue( + view.settings.labelPosition || + ABViewFormPropertyComponentDefaults.labelPosition + ); + $$(ids.labelWidth).setValue( + view.settings.labelWidth || + ABViewFormPropertyComponentDefaults.labelWidth + ); + $$(ids.height).setValue( + view.settings.height || ABViewFormPropertyComponentDefaults.height + ); + $$(ids.clearOnLoad).setValue( + view.settings.clearOnLoad || + ABViewFormPropertyComponentDefaults.clearOnLoad + ); + $$(ids.clearOnSave).setValue( + view.settings.clearOnSave || + ABViewFormPropertyComponentDefaults.clearOnSave + ); + + // NOTE: load the object and view BEFORE the .fromSettings(); + PopupRecordRule.objectLoad(this.CurrentObject); + PopupRecordRule.viewLoad(view); + PopupRecordRule.fromSettings(view.settings.recordRules || []); + + PopupSubmitRule.objectLoad(this.CurrentObject); + PopupSubmitRule.viewLoad(view); + PopupSubmitRule.fromSettings(view.settings.submitRules || []); + + // this.propertyUpdateRules(ids, view, datacollectionId); + this.populateBadgeNumber(); + + // when a change is made in the properties the popups need to reflect the change + this.updateEventIds = this.updateEventIds || {}; // { viewId: boolean, ..., viewIdn: boolean } + if (!this.updateEventIds[view.id]) { + this.updateEventIds[view.id] = true; + + view.addListener("properties.updated", () => { + this.populateBadgeNumber(); + }); + } + } + + defaultValues() { + let values = {}; + var ViewClass = this.ViewClass(); + if (ViewClass) { + values = ViewClass.defaultValues(); + } + return values; + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + let ids = this.ids; + let vals = super.values(); + + vals.settings = vals.settings || {}; + + vals.settings.dataviewID = $$(ids.datacollection).getValue(); + vals.settings.showLabel = $$(ids.showLabel).getValue(); + vals.settings.labelPosition = + $$(ids.labelPosition).getValue() || + ABViewFormPropertyComponentDefaults.labelPosition; + vals.settings.labelWidth = + $$(ids.labelWidth).getValue() || + ABViewFormPropertyComponentDefaults.labelWidth; + vals.settings.height = $$(ids.height).getValue(); + vals.settings.clearOnLoad = $$(ids.clearOnLoad).getValue(); + vals.settings.clearOnSave = $$(ids.clearOnSave).getValue(); + + vals.settings.recordRules = PopupRecordRule.toSettings(); + vals.settings.submitRules = PopupSubmitRule.toSettings(); + return vals; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("form"); + } + + // + // + // + + busy() { + $$(this.ids.component)?.showProgress?.({ type: "icon" }); + } + + check(e, fieldId) { + if (this._isBusy) return; + this._isBusy = true; + this.busy(); + const ids = this.ids; + let currView = this.CurrentView; + let formView = currView.parentFormComponent(); + + // update UI list + let item = $$(ids.fields).getItem(fieldId); + item.selected = item.selected ? 0 : 1; + $$(ids.fields).updateItem(fieldId, item); + + let doneFn = () => { + this._isBusy = false; + formView + .refreshDefaultButton(ids) + .save() + .then(() => { + // refresh UI + currView.emit("properties.updated", currView); + this.onChange(); + this.ready(); + }); + + // // trigger a save() + // this.propertyEditorSave(ids, currView); + }; + + // add a field to the form + if (item.selected) { + // Check for duplication + let exists = formView + .fieldComponents() + .find((c) => c.settings.fieldId == fieldId); + if (exists) { + this._isBusy = false; + this.ready(); + return; + } + + let fieldView = formView.addFieldToForm(item); + if (fieldView) { + fieldView.save().then(() => { + fieldView.once("destroyed", () => this.populate(currView)); + formView.viewInsert(fieldView).then(() => { + doneFn(); + }); + }); + } else { + this._isBusy = false; + this.ready(); + } + } + // remove field in the form + else { + let fieldView = formView + .fieldComponents() + .filter((c) => c.settings.fieldId == fieldId)[0]; + if (fieldView) { + // let remainingViews = formView.views(c => c.settings.fieldId != fieldId); + // formView._views = remainingViews; + + fieldView.destroy(); + formView.viewRemove(fieldView).then(() => { + doneFn(); + }); + } else { + this._isBusy = false; + this.ready(); + } + } + } + + populateBadgeNumber(/* */) { + const ids = this.ids; + + let view = this.CurrentView; + + if (!view) return; + + if (view.settings.submitRules) { + $$(ids.buttonSubmitRules).define( + "badge", + view.settings.submitRules.length || null + ); + } else { + $$(ids.buttonSubmitRules).define("badge", null); + } + $$(ids.buttonSubmitRules).refresh(); + + // if (view.settings.displayRules) { + // $$(ids.buttonDisplayRules).define( + // "badge", + // view.settings.displayRules.length || null + // ); + // $$(ids.buttonDisplayRules).refresh(); + // } else { + // $$(ids.buttonDisplayRules).define("badge", null); + // $$(ids.buttonDisplayRules).refresh(); + // } + + if (view.settings.recordRules) { + $$(ids.buttonRecordRules).define( + "badge", + view.settings.recordRules.length || null + ); + } else { + $$(ids.buttonRecordRules).define("badge", null); + } + $$(ids.buttonRecordRules).refresh(); + } + + ready() { + $$(this.ids.component)?.hideProgress?.(); + } + + recordRuleShow() { + PopupRecordRule.fromSettings(this.CurrentView.settings.recordRules); + PopupRecordRule.show(); + } + + submitRuleShow() { + PopupSubmitRule.fromSettings(this.CurrentView.settings.submitRules); + PopupSubmitRule.show(); + } + + listTemplate(field, common) { + let currView = this.CurrentView; + + // disable in form + var fieldComponent = field.formComponent(); + if (fieldComponent == null) + return ` ${field.label}
Disable
`; + + var componentKey = fieldComponent.common().key; + var formComponent = currView.application.viewAll( + (v) => v.common().key == componentKey + )[0]; + + return `${common.markCheckbox(field)} ${ + field.label + }
${ + formComponent ? L(formComponent.common().labelKey) : "" + }
`; + } + + /** + * @method propertyUpdateFieldOptions + * Populate fields of object to select list in property + * + * @param {ABViewForm} view - the current component + * @param {string} dcId - id of ABDatacollection + */ + propertyUpdateFieldOptions(dcId) { + const ids = this.ids; + var formComponent = this.CurrentView.parentFormComponent(); + var existsFields = formComponent.fieldComponents(); + var datacollection = this.AB.datacollectionByID(dcId); + var object = datacollection ? datacollection.datasource : null; + + // Pull field list + var fieldOptions = []; + if (object != null) { + fieldOptions = object.fields().map((f) => { + f.selected = + existsFields.filter((com) => { + return f.id == com.settings.fieldId; + }).length > 0; + + return f; + }); + + this.objectLoad(object); + } + + $$(ids.fields).clearAll(); + $$(ids.fields).parse(fieldOptions); + } + + refreshDefaultButton() { + const ids = this.ids; + const ABViewFormButton = this.AB.ClassManager.viewClass("button"); + + // If default button is not exists, then skip this + let defaultButton = this.views( + (v) => v instanceof ABViewFormButton && v.settings.isDefault + )[0]; + + // Add a default button + if (defaultButton == null) { + defaultButton = ABViewFormButton.newInstance( + this.application, + this + ); + defaultButton.settings.isDefault = true; + } + // Remove default button from array, then we will add it to be the last item later (.push) + else { + this._views = this.views( + (v) => !(v instanceof ABViewFormButton) && !v.settings.isDefault + ); + } + + // Calculate position Y of the default button + let yList = this.views().map((v) => (v.position.y || 0) + 1); + yList.push(this._views.length || 0); + yList.push($$(ids.fields).length || 0); + let posY = Math.max(...yList); + + // Update to be the last item + defaultButton.position.y = posY; + + // Keep the default button is always the last item of array + this._views.push(defaultButton); + + return defaultButton; + } + + selectSource(dcId /*, oldDcId */) { + // TODO : warning message + const ids = this.ids; + this.busy(); + + let currView = this.CurrentView; + let formView = currView.parentFormComponent(); + + currView.settings.dataviewID = dcId; + + // clear sub views + var viewsToRemove = currView._views; + currView._views = []; + + return ( + Promise.resolve() + .then(() => { + var allRemoves = []; + viewsToRemove.forEach((v) => { + allRemoves.push(v.destroy()); + }); + return Promise.all(allRemoves); + }) + // .then(() => { + // // remove all old components + // let destroyTasks = []; + // if (oldDcId != null) { + // let oldComps = formView.views(); + // oldComps.forEach(child => destroyTasks.push(() => child.destroy())); + // } + + // return destroyTasks.reduce((promiseChain, currTask) => { + // return promiseChain.then(currTask); + // }, Promise.resolve([])); + // }) + .then(() => { + // refresh UI + // formView.emit('properties.updated', currView); + + // Update field options in property + this.propertyUpdateFieldOptions(dcId); + + // add all fields to editor by default + if (currView._views.length > 0) return Promise.resolve(); + + let saveTasks = []; + let fields = $$(ids.fields).find({}); + fields.reverse(); + fields.forEach((f, index) => { + if (!f.selected) { + let yPosition = fields.length - index - 1; + + // Add new form field + let newFieldView = currView.addFieldToForm( + f, + yPosition + ); + if (newFieldView) { + newFieldView.once("destroyed", () => + this.populate(currView) + ); + + // // Call save API + saveTasks.push(newFieldView.save()); + } + + // update item to UI list + f.selected = 1; + $$(ids.fields).updateItem(f.id, f); + } + }); + + let defaultButton = formView.refreshDefaultButton(ids); + if (defaultButton) saveTasks.push(defaultButton.save()); + + return Promise.all(saveTasks); + }) + // Saving + .then(() => { + //// NOTE: the way the .addFieldToForm() works, it will prevent + //// the typical field.save() -> triggering the form.save() on a + //// new Field. So once all our field.saves() are finished, we + //// need to perform a form.save() to persist the changes. + return currView.save(); + }) + // Finally + .then(() => { + // refresh UI + formView.emit("properties.updated", currView); + + // Update field options in property + // this.propertyUpdateRules(ids, currView, dcId); + + this.ready(); + this.onChange(); + return Promise.resolve(); + }) + ); + } + }; + + return [ + ABAbviewformProperties, + FNAbviewFormButtonProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormCheckboxProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormConnectProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormCustomProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormDatepickerProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormJsonProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormNumberProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormSelectMultipleProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormSelectSingleProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormTextboxProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormTreeProperties({ AB, ABViewPropertiesPlugin }), + FNAbviewFormUrlProperties({ AB, ABViewPropertiesPlugin }), + ]; +} diff --git a/src/plugins/web_view_form/FNAbviewformEditor.js b/src/plugins/web_view_form/FNAbviewformEditor.js new file mode 100644 index 0000000..43e3a9c --- /dev/null +++ b/src/plugins/web_view_form/FNAbviewformEditor.js @@ -0,0 +1,61 @@ +import FNAbviewFormUrlEditor from "./editors/FNAbviewFormUrlEditor.js"; + +export default function FNAbviewformEditor({ AB, ABViewEditorPlugin }) { + const FABViewContainer = + require("../../rootPages/Designer/editors/views/ABViewContainer").default; + + const ABViewContainer = FABViewContainer(AB); + // var L = UIClass.L(); + // var L = ABViewContainer.L(); + + const ABAbviewformEditor = class ABAbviewformEditor extends ABViewContainer { + static getPluginKey() { + return this.key; + } + + /** + * @method getPluginType + * return the plugin type for this editor. + * plugin types are how our ClassManager knows how to store + * the plugin. + * @return {string} plugin type + */ + static getPluginType() { + return "editor-view"; + // editor-view : will display in the editor panel of the ABDesigner + } + + static get key() { + return "form"; + } + + constructor(view, base = "interface_editor_viewform") { + // base: {string} unique base id reference + + super(view, base); + + // this.component = this.view.component(); + } + + ui() { + let _ui = super.ui(); + _ui.rows[0].cellHeight = 75; + return _ui; + } + + init(AB) { + this.AB = AB; + return super.init(AB); + } + + detatch() { + this.component?.detatch?.(); + } + + onShow() { + this.component?.onShow?.(); + } + }; + + return [ABAbviewformEditor, FNAbviewFormUrlEditor({ ABViewEditorPlugin })]; +} diff --git a/src/plugins/web_view_form/editors/FNAbviewFormUrlEditor.js b/src/plugins/web_view_form/editors/FNAbviewFormUrlEditor.js new file mode 100644 index 0000000..d719d12 --- /dev/null +++ b/src/plugins/web_view_form/editors/FNAbviewFormUrlEditor.js @@ -0,0 +1,62 @@ +import FNAbviewformEditor from "../FNAbviewformEditor.js"; + +/** + * ABViewFormEditor + * The widget that displays the UI Editor Component on the screen + * when designing the UI. + */ +var myClass = null; +// {singleton} +// we will want to call this factory fn() repeatedly in our imports, +// but we only want to define 1 Class reference. + +export default function FNAbviewFormUrlEditor({ ABViewEditorPlugin }) { + const ABViewForm = FNAbviewformEditor({ ABViewEditorPlugin }); + + if (!myClass) { + // var L = UIClass.L(); + // var L = ABViewContainer.L(); + + myClass = class ABViewFormEditor extends ABViewForm { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "editor-view"; + } + static get key() { + return "form-url"; + } + + // constructor(view, base = "interface_editor_viewform") { + // // base: {string} unique base id reference + + // super(view, base); + + // // this.component = this.view.component(); + // } + + // ui() { + // let _ui = super.ui(); + // _ui.rows[0].cellHeight = 75; + // return _ui; + // } + + // init(AB) { + // this.AB = AB; + // return super.init(AB); + // } + + // detatch() { + // this.component?.detatch?.(); + // } + + // onShow() { + // this.component?.onShow?.(); + // } + }; + } + + return myClass; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormButton.js b/src/plugins/web_view_form/properties/FNAbviewFormButton.js new file mode 100644 index 0000000..087d34b --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormButton.js @@ -0,0 +1,282 @@ +/* + * ABViewButton + * A Property manager for our ABViewButton definitions + */ + +export default function FNAbviewFormButtonProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const BASE_ID = "properties_abview_button"; + + const L = AB.Label(); + + class ABViewButtonProperty extends ABViewPropertiesPlugin { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + includeSave: "", + saveLabel: "", + includeCancel: "", + cancelLabel: "", + includeReset: "", + resetLabel: "", + includeDelete: "", + deleteLabel: "", + afterCancel: "", + alignment: "", + }); + + this.AB = AB; + } + + static get key() { + return "button"; + } + + ui() { + const ids = this.ids; + const uiConfig = this.AB.UISettings.config(); + + return super.ui([ + { + id: ids.includeSave, + name: "includeSave", + view: "checkbox", + label: L("Save"), + click: () => this.onChange(), + }, + { + id: ids.saveLabel, + name: "saveLabel", + view: "text", + labelWidth: uiConfig.labelWidthLarge, + label: L("Save Label"), + placeholder: L("Save Placeholder"), + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.includeCancel, + name: "includeCancel", + view: "checkbox", + label: L("Cancel"), + click: () => this.onChange(), + }, + { + id: ids.cancelLabel, + name: "cancelLabel", + view: "text", + labelWidth: uiConfig.labelWidthLarge, + label: L("Cancel Label"), + placeholder: L("Cancel Placeholder"), + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.includeReset, + name: "includeReset", + view: "checkbox", + label: L("Reset"), + click: () => this.onChange(), + }, + { + id: ids.resetLabel, + name: "resetLabel", + view: "text", + labelWidth: uiConfig.labelWidthLarge, + label: L("Reset Label"), + placeholder: L("Reset Placeholder"), + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.includeDelete, + name: "includeDelete", + view: "checkbox", + label: L("Delete"), + click: () => this.onChange(), + }, + { + id: ids.deleteLabel, + name: "deleteLabel", + view: "text", + labelWidth: uiConfig.labelWidthLarge, + label: L("Delete Label"), + placeholder: L("Delete Placeholder"), + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.afterCancel, + name: "afterCancel", + view: "richselect", + labelWidth: uiConfig.labelWidthLarge, + label: L("After Cancel"), + on: { + onChange: () => this.onChange(), + }, + // options: [] + }, + { + id: ids.alignment, + name: "alignment", + view: "richselect", + labelWidth: uiConfig.labelWidthLarge, + label: L("Alignment"), + options: [ + { + id: "left", + value: L("Left"), + }, + { + id: "center", + value: L("Center"), + }, + { + id: "right", + value: L("Right"), + }, + ], + on: { + onChange: () => this.onChange(), + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormButtonPropertyComponentDefaults = this.defaultValues(); + + const pagesList = []; + this.addPagesToList(pagesList, view.application, view.pageRoot().id); + + const opts = pagesList.map((opt) => { + return { + id: opt.id, + value: opt.value, + }; + }); + $$(ids.afterCancel).define("options", opts); + + $$(ids.includeSave).setValue( + view.settings.includeSave != null + ? view.settings.includeSave + : ABViewFormButtonPropertyComponentDefaults.includeSave + ); + $$(ids.includeCancel).setValue( + view.settings.includeCancel != null + ? view.settings.includeCancel + : ABViewFormButtonPropertyComponentDefaults.includeCancel + ); + $$(ids.includeReset).setValue( + view.settings.includeReset != null + ? view.settings.includeReset + : ABViewFormButtonPropertyComponentDefaults.includeReset + ); + $$(ids.includeDelete).setValue( + view.settings.includeDelete != null + ? view.settings.includeDelete + : ABViewFormButtonPropertyComponentDefaults.includeDelete + ); + + $$(ids.saveLabel).setValue(view.settings.saveLabel ?? ""); + $$(ids.cancelLabel).setValue(view.settings.cancelLabel ?? ""); + $$(ids.resetLabel).setValue(view.settings.resetLabel ?? ""); + $$(ids.deleteLabel).setValue(view.settings.deleteLabel ?? ""); + + $$(ids.afterCancel).setValue( + view.settings.afterCancel ?? + ABViewFormButtonPropertyComponentDefaults.afterCancel + ); + $$(ids.alignment).setValue( + view.settings.alignment ?? + ABViewFormButtonPropertyComponentDefaults.alignment + ); + } + + defaultValues() { + const ViewClass = this.ViewClass(); + + let values = null; + + if (ViewClass) { + values = ViewClass.defaultValues(); + } + + return values; + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.includeSave = $$(ids.includeSave).getValue(); + values.settings.saveLabel = $$(ids.saveLabel).getValue(); + values.settings.includeCancel = $$(ids.includeCancel).getValue(); + values.settings.cancelLabel = $$(ids.cancelLabel).getValue(); + values.settings.includeReset = $$(ids.includeReset).getValue(); + values.settings.resetLabel = $$(ids.resetLabel).getValue(); + values.settings.includeDelete = $$(ids.includeDelete).getValue(); + values.settings.deleteLabel = $$(ids.deleteLabel).getValue(); + values.settings.afterCancel = $$(ids.afterCancel).getValue(); + values.settings.alignment = $$(ids.alignment).getValue(); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("button"); + } + + addPagesToList(pagesList, parent, rootPageId) { + if (!parent || !parent.pages || !pagesList) return; + + (parent.pages() ?? []).forEach((page) => { + if (page.parent != null || page.id == rootPageId) { + pagesList.push({ + id: page.id, + value: page.label, + }); + + this.addPagesToList(pagesList, page, page.id); + } + }); + } + } + + return ABViewButtonProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormCheckbox.js b/src/plugins/web_view_form/properties/FNAbviewFormCheckbox.js new file mode 100644 index 0000000..0a07b5e --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormCheckbox.js @@ -0,0 +1,36 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormCheckbox + * A Property manager for our ABViewFormCheckbox definitions + */ + +export default function FNAbviewFormCheckboxProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_checkbox"; + + class ABViewFormCheckboxProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, {}); + + this.AB = AB; + } + + static get key() { + return "checkbox"; + } + } + + return ABViewFormCheckboxProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormConnect.js b/src/plugins/web_view_form/properties/FNAbviewFormConnect.js new file mode 100644 index 0000000..d0c4b1d --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormConnect.js @@ -0,0 +1,527 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; +import ABPopupSort from "../../../rootPages/Designer/ui_work_object_workspace_popupSortFields"; +import ABViewPropertyAddPage from "../../../rootPages/Designer/properties/views/viewProperties/ABViewPropertyAddPage"; +import ABViewPropertyEditPage from "../../../rootPages/Designer/properties/views/viewProperties/ABViewPropertyEditPage"; + +/* + * ABViewConnect + * A Property manager for our ABViewConnect definitions + */ + +export default function FNAbviewFormConnectProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_connect"; + + const ABAddPage = ABViewPropertyAddPage(AB, BASE_ID); + const ABEditPage = ABViewPropertyEditPage(AB, BASE_ID); + const L = AB.Label(); + + let FilterComponent = null; + let SortComponent = null; + + class ABViewConnectProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + addNewSettings: "", + popupWidth: "", + popupHeight: "", + advancedOption: "", + buttonFilter: "", + filterConnectedValue: "", + buttonSort: "", + }); + + this.AB = AB; + FilterComponent = this.AB.filterComplexNew(`${BASE_ID}_filter`); + FilterComponent.on("save", () => this.onChange()); + SortComponent = ABPopupSort(this.AB, `${BASE_ID}_sort`); + SortComponent.on("changed", () => this.onChange()); + } + + static get key() { + return "connect"; + } + + ui() { + const self = this; + const ids = this.ids; + const uiConfig = this.AB.UISettings.config(); + + return super.ui([ + this.addPageProperty.ui(), + this.editPageProperty.ui(), + { + id: ids.addNewSettings, + view: "fieldset", + name: "addNewSettings", + label: L("Add New Popup Settings:"), + labelWidth: uiConfig.labelWidthLarge, + body: { + type: "clean", + padding: 10, + rows: [ + { + id: ids.popupWidth, + view: "text", + name: "popupWidth", + placeholder: L("Set popup width"), + label: L("Width:"), + labelWidth: uiConfig.labelWidthLarge, + validate: this.AB.Webix.rules.isNumber, + on: { + onChange: () => this.onChange(), + }, + }, + { + id: ids.popupHeight, + view: "text", + name: "popupHeight", + placeholder: L("Set popup height"), + label: L("Height:"), + labelWidth: uiConfig.labelWidthLarge, + validate: this.AB.Webix.rules.isNumber, + on: { + onChange: () => this.onChange(), + }, + }, + ], + }, + }, + { + id: ids.advancedOption, + view: "fieldset", + name: "advancedOption", + label: L("Advanced Options:"), + labelWidth: uiConfig.labelWidthLarge, + body: { + type: "clean", + padding: 10, + rows: [ + { + cols: [ + { + view: "label", + label: L("Filter Options:"), + width: uiConfig.labelWidthLarge, + }, + { + id: ids.buttonFilter, + view: "button", + name: "buttonFilter", + css: "webix_primary", + label: L("Settings"), + icon: "fa fa-gear", + type: "icon", + badge: 0, + click: function () { + self.showFilterPopup(this.$view); + }, + }, + ], + }, + { + rows: [ + { + view: "label", + label: L("Filter by Connected Field Value:"), + }, + { + id: ids.filterConnectedValue, + view: "combo", + name: "filterConnectedValue", + options: [], // we will add these in propertyEditorPopulate + on: { + onChange: () => this.onChange(), + }, + }, + ], + }, + { + height: 30, + }, + { + rows: [ + { + cols: [ + { + view: "label", + label: L("Sort Options:"), + width: uiConfig.labelWidthLarge, + }, + { + id: ids.buttonSort, + view: "button", + name: "buttonSort", + css: "webix_primary", + label: L("Settings"), + icon: "fa fa-gear", + type: "icon", + badge: 0, + click: function () { + self.showSortPopup(this.$view); + }, + }, + ], + }, + ], + }, + ], + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + + FilterComponent.init(); + // when we make a change in the popups we want to make sure we save the new workspace to the properties to do so just fire an onChange event + // FilterComponent.on("change", (val) => { + // this.onChange(); + // }); + + SortComponent.init(AB); + + this.addPageProperty.on("change", () => { + this.onChange(); + }); + + this.editPageProperty.on("change", () => { + this.onChange(); + }); + } + + populate(view) { + super.populate(view); + + this.populateFilterByConnectedFieldValue(view); + + const ids = this.ids; + const ABViewFormConnectPropertyComponentDefaults = + this.defaultValues(); + + // Default set of options for filter connected combo + const filterConnectedOptions = [{ id: null, value: "" }]; + + // get the definitions for the connected field + const fieldDefs = this.AB.definitionByID(view.settings.fieldId); + + // get the definition for the object that the field is related to + const objectDefs = this.AB.definitionByID( + fieldDefs.settings.linkObject + ); + + // we need these definitions later as we check to find out which field + // we are filtering by so push them into an array for later + const fieldsDefs = []; + objectDefs.fieldIDs.forEach((fld) => { + fieldsDefs.push(this.AB.definitionByID(fld)); + }); + + // find out what connected objects this field has + const connectedObjs = view.application.connectedObjects( + fieldDefs.settings.linkObject + ); + + // loop through the form's elements (need to ensure that just looking at parent is okay in all cases) + view.parent.views().forEach((element) => { + // identify if element is a connected field + if (element.key == "connect") { + // we need to get the fields defs to find out what it is connected to + const formElementsDefs = this.AB.definitionByID( + element.settings.fieldId + ); + + // loop through the connected objects discovered above + connectedObjs.forEach((connObj) => { + // see if the connected object matches the connected object of the form element + if (connObj.id == formElementsDefs.settings.linkObject) { + // get the ui id of this component that matches the link Object + let fieldToCheck; + fieldsDefs.forEach((fdefs) => { + // if the field has a custom foreign key we need to store it + // so selectivity later can know what value to get, otherwise + // we just get the uuid of the record + if ( + fdefs.settings.isCustomFK && + fdefs.settings.indexField != "" && + fdefs.settings.linkObject && + fdefs.settings.linkType == "one" && + fdefs.settings.linkObject == + formElementsDefs.settings.linkObject + ) { + fieldToCheck = fdefs.id; + let customFK = this.AB.definitionByID( + fdefs.settings.indexField + ); + + // if the index definitions were found + if (customFK) { + fieldToCheck = `${fdefs.id}:${customFK.columnName}`; + } + } else if ( + fdefs.settings.linkObject && + fdefs.settings.linkType == "one" && + fdefs.settings.linkObject == + formElementsDefs.settings.linkObject + ) { + fieldToCheck = `${fdefs.id}:uuid`; + } + }); + + // only add optinos that have a fieldToCheck + if (fieldToCheck) { + // get the component we are referencing so we can display its label + const formComponent = + view.parent.viewComponents[element.id]; // need to ensure that just looking at parent is okay in all cases + + const uiComp = formComponent.ui(); + const uiInput = uiComp.rows[0] ?? uiComp; + + filterConnectedOptions.push({ + id: `${uiInput.name}:${fieldToCheck}`, // store the columnName name because the ui id changes on each load + value: uiInput.label, // should be the translated field label + }); + } + } + }); + } + }); + + // Set the options of the possible edit forms + this.addPageProperty.setSettings(view, { + formView: view.settings.formView, + }); + this.editPageProperty.setSettings(view, { + editForm: view.settings.editForm, + }); + $$(ids.filterConnectedValue).define("options", filterConnectedOptions); + $$(ids.filterConnectedValue).setValue( + view.settings.filterConnectedValue + ); + + $$(ids.popupWidth).setValue( + view.settings.popupWidth || + ABViewFormConnectPropertyComponentDefaults.popupWidth + ); + $$(ids.popupHeight).setValue( + view.settings.popupHeight || + ABViewFormConnectPropertyComponentDefaults.popupHeight + ); + + // initial populate of popups + this.populatePopupEditors(view); + + // inform the user that some advanced settings have been set + this.populateBadgeNumber(ids, view); + } + + _filterCondition(view) { + if (view?.options?.filters?.rules?.length) { + return view.options.filters; + } else if (view?.settings?.filterConditions?.rules?.length) { + return view.settings.filterConditions; + } else { + return null; + } + } + + populatePopupEditors(view) { + const filterConditions = + this._filterCondition(view) ?? + this.defaultValues().filterConditions; + + // Populate data to popups + // FilterComponent.objectLoad(objectCopy); + let linkedObj; + const field = view.field(); + if (field) { + linkedObj = field.datasourceLink; + if (linkedObj) + FilterComponent.fieldsLoad(linkedObj.fields(), linkedObj); + } + + FilterComponent.setValue(filterConditions); + + if (linkedObj) SortComponent.objectLoad(linkedObj); + SortComponent.setSettings(view.settings.sortFields); + } + + populateBadgeNumber(ids, view) { + const $buttonFilter = $$(ids.buttonFilter); + const filterCondition = this._filterCondition(view); + if (filterCondition?.rules) { + $buttonFilter.define("badge", filterCondition.rules.length || null); + $buttonFilter.refresh(); + } else { + $buttonFilter.define("badge", null); + $buttonFilter.refresh(); + } + + const $buttonSort = $$(ids.buttonSort); + if (view?.settings?.sortFields?.length) { + $buttonSort.define( + "badge", + view.settings.sortFields.length || null + ); + $buttonSort.refresh(); + } else { + $buttonSort.define("badge", null); + $buttonSort.refresh(); + } + } + + populateFilterByConnectedFieldValue(view) { + const fieldDef = this.AB.definitionByID(view.settings.fieldId); + + // Support only 1:M and 1:1 relation type of the connect field + if ( + // 1:M + (fieldDef.settings.linkType == "one" && + fieldDef.settings.linkViaType == "many") || + // 1:1 isSource = true + (fieldDef.settings.linkType == "one" && + fieldDef.settings.linkViaType == "one" && + fieldDef.settings.isSource) + ) { + // Pull link object + const linkObject = this.AB.objectByID(fieldDef.settings.linkObject); + if (!linkObject) return; + + let connectFields = linkObject.fields( + (f) => f.key == "connectObject" + ); + if (!connectFields || !connectFields.length) return; + + connectFields.forEach((f) => { + let connectFieldOptions = view.parent + .views((element) => { + let linkFieldDef = this.AB.definitionByID( + element.settings.fieldId + ); + + // Pull other connected field input elements + return ( + element.key == "connect" && + element.id != view.id && + f.settings.linkObject == + linkFieldDef.settings.linkObject + ); + }) + .map((element) => { + const formComponent = + view.parent.viewComponents[element.id]; + + const uiComp = formComponent.ui(); + const uiInput = uiComp.rows[0] ?? uiComp; + + return { + id: uiInput.name, + value: uiInput.label, + }; + }); + + if (connectFieldOptions && connectFieldOptions.length) { + FilterComponent.addCustomOption(f.id, { + conditions: [ + { + id: "filterByConnectValue", + value: L("Filter by Connected Field Value:"), + batch: "FilterByConnectedFieldValue", + handler: () => true, + }, + ], + values: [ + { + batch: "FilterByConnectedFieldValue", + view: "combo", + options: connectFieldOptions, + }, + ], + }); + } + }); + } + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + const view = this.CurrentView; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.popupWidth = $$(ids.popupWidth).getValue(); + values.settings.popupHeight = $$(ids.popupHeight).getValue(); + values.settings.filterConnectedValue = $$( + ids.filterConnectedValue + ).getValue(); + values.settings.filterConditions = FilterComponent.getValue(); + values.settings.sortFields = SortComponent.getSettings(); + + const settingsAddPage = this.addPageProperty.getSettings(view) ?? {}; + const settingsEditPage = this.editPageProperty.getSettings(view) ?? {}; + values.settings.formView = settingsAddPage.formView; + values.settings.editForm = settingsEditPage.editForm; + + // refresh settings of app page tool + // this.addPageProperty.setSettings(view, values.settingsAddPage); + // this.editPageProperty.setSettings(view, values.settingsEditPage); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("connect"); + } + + get addPageProperty() { + if (!this._addPage) this._addPage = new ABAddPage(); + + return this._addPage; + } + + get editPageProperty() { + if (!this._editPage) this._editPage = new ABEditPage(); + + return this._editPage; + } + + showFilterPopup($view) { + FilterComponent.popUp($view, null, { pos: "top" }); + } + + showSortPopup($button) { + SortComponent.show($button, null, { + pos: "top", + }); + } + } + + return ABViewConnectProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormCustom.js b/src/plugins/web_view_form/properties/FNAbviewFormCustom.js new file mode 100644 index 0000000..4e933fc --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormCustom.js @@ -0,0 +1,36 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormCustom + * A Property manager for our ABViewFormCustom definitions + */ + +export default function FNAbviewFormCustomProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_custom"; + + class ABViewFormCustomProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, {}); + + this.AB = AB; + } + + static get key() { + return "fieldcustom"; + } + } + + return ABViewFormCustomProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormDatepicker.js b/src/plugins/web_view_form/properties/FNAbviewFormDatepicker.js new file mode 100644 index 0000000..c3d666d --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormDatepicker.js @@ -0,0 +1,36 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormDatepicker + * A Property manager for our ABViewFormDatepicker definitions + */ + +export default function FNAbviewFormDatepickerProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_datepicker"; + + class ABViewFormDatepickerProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, {}); + + this.AB = AB; + } + + static get key() { + return "datepicker"; + } + } + + return ABViewFormDatepickerProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormItem.js b/src/plugins/web_view_form/properties/FNAbviewFormItem.js new file mode 100644 index 0000000..f1388fb --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormItem.js @@ -0,0 +1,120 @@ +/* + * ABViewFormItem + * A Property manager for our ABViewFormItem definitions + */ + +export default function FNAbviewFormItemProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const L = AB.Label(); + const DEFAULT_VALUES = { + required: 0, + disable: 0, + }; + + class ABViewFormItemProperty extends ABViewPropertiesPlugin { + constructor(BASE_ID, ids = {}) { + super( + BASE_ID, + Object.assign(ids, { + // Put our ids here + field: "", + required: "", + disable: "", + }) + ); + + this.AB = AB; + } + + ui(elements = [], rules = {}) { + const ids = this.ids; + const uiSettings = this.AB.UISettings.config(); + const _ui = [ + { + id: ids.field, + name: "fieldLabel", + view: "text", + disabled: true, + label: L("Field"), + }, + { + id: ids.required, + name: "required", + view: "checkbox", + labelWidth: uiSettings.labelWidthCheckbox, + labelRight: L("Required"), + click: () => this.onChange(), + }, + { + id: ids.disable, + name: "disable", + view: "checkbox", + labelWidth: uiSettings.labelWidthCheckbox, + labelRight: L("Disable"), + click: () => this.onChange(), + }, + ].concat(elements); + + return super.ui(_ui, rules); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormItemPropertyDefaults = this.defaultValues(); + const field = view.field(); + + $$(ids.field).setValue(field ? field.label : ""); + + if (field?.settings?.required == 1) { + $$(ids.required).setValue(field.settings.required); + $$(ids.required).disable(); + } else { + $$(ids.required).setValue( + view.settings?.required != null + ? view.settings.required + : ABViewFormItemPropertyDefaults.required + ); + } + + if (view.settings?.disable == 1) { + $$(ids.disable).setValue(view.settings.disable); + } else { + $$(ids.disable).setValue(ABViewFormItemPropertyDefaults.disable); + } + } + + defaultValues() { + const ViewClass = this.ViewClass(); + + let values = {}; + + if (ViewClass) { + values = ViewClass.defaultValues(); + } + + return Object.assign(DEFAULT_VALUES, values); + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const values = super.values() ?? {}; + values.settings = values.settings ?? {}; + values.settings.required = $$(ids.required).getValue(); + values.settings.disable = $$(ids.disable).getValue(); + + return values; + } + } + + return ABViewFormItemProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormJson.js b/src/plugins/web_view_form/properties/FNAbviewFormJson.js new file mode 100644 index 0000000..a10ddb0 --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormJson.js @@ -0,0 +1,157 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormJson + * A Property manager for our ABViewFormJson definitions + */ + +export default function FNAbviewFormJsonProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_json"; + + const L = AB.Label(); + + class ABViewFormJsonProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + type: "", + filterField: "", + }); + + this.AB = AB; + } + + static get key() { + return "json"; + } + + ui() { + const ids = this.ids; + + return super.ui([ + { + id: ids.type, + name: "type", + view: "radio", + label: L("Type"), + vertical: true, + options: [ + { + id: "string", + value: L("JSON String"), + }, + { + id: "systemObject", + value: L("System Object Chooser UI"), + }, + { + id: "filter", + value: L("Filter UI"), + }, + ], + on: { + onChange: (newValue) => { + if (newValue == "filter") { + $$(ids.filterField).show(); + } else { + $$(ids.filterField).hide(); + } + this.onChange(); + }, + }, + }, + { + id: ids.filterField, + name: "filterField", + view: "combo", + hidden: true, + label: L("Object Field to Filter"), + labelPosition: "top", + placeholder: L("Select a field to filter by"), + // options: look at populate + on: { + onChange: (/* newValue */) => { + this.onChange(); + }, + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormJsonPropertyComponentDefaults = this.defaultValues(); + + // set the options for the filterField + let filterFieldOptions = [{ id: "", value: "" }]; + view.parent.views().forEach((element) => { + if ( + element.key == "json" && + element.settings.type == "systemObject" + ) { + let formComponent = view.parent.viewComponents[element.id]; + filterFieldOptions.push({ + id: element.settings.fieldId, + value: formComponent.settings.fieldLabel, + }); + } + }); + $$(ids.filterField).define("options", filterFieldOptions); + + if (view.settings.filterField) + $$(ids.filterField).setValue(view.settings.filterField); + + $$(ids.type).setValue( + view.settings.type || ABViewFormJsonPropertyComponentDefaults.type + ); + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.type = $$(ids.type).getValue(); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("json"); + } + } + + return ABViewFormJsonProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormNumber.js b/src/plugins/web_view_form/properties/FNAbviewFormNumber.js new file mode 100644 index 0000000..da83114 --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormNumber.js @@ -0,0 +1,104 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormNumber + * A Property manager for our ABViewFormNumber definitions + */ + +export default function FNAbviewFormNumberProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_number"; + + const L = AB.Label(); + + class ABViewFormNumberProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + isStepper: "", + }); + + this.AB = AB; + } + + static get key() { + return "numberbox"; + } + + ui() { + const ids = this.ids; + const uiConfig = this.AB.UISettings.config(); + + return super.ui([ + { + id: ids.isStepper, + name: "isStepper", + view: "checkbox", + labelWidth: uiConfig.labelWidthCheckbox, + labelRight: L("Plus/Minus Buttons"), + on: { + onChange: () => this.onChange(), + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormNumberPropertyComponentDefaults = this.defaultValues(); + + $$(ids.isStepper).setValue( + view.settings.isStepper != null + ? view.settings.isStepper + : ABViewFormNumberPropertyComponentDefaults.isStepper + ); + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.isStepper = $$(ids.isStepper).getValue(); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("numberbox"); + } + } + + return ABViewFormNumberProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormSelectMultiple.js b/src/plugins/web_view_form/properties/FNAbviewFormSelectMultiple.js new file mode 100644 index 0000000..adc1e15 --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormSelectMultiple.js @@ -0,0 +1,112 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormSelectMultiple + * A Property manager for our ABViewFormSelectMultiple definitions + */ + +export default function FNAbviewFormSelectMultipleProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_select_multiple"; + + const L = AB.Label(); + + class ABViewFormSelectMultipleProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + type: "", + }); + + this.AB = AB; + } + + static get key() { + return "selectmultiple"; + } + + ui() { + const ids = this.ids; + + return super.ui([ + { + id: ids.type, + name: "type", + view: "richselect", + label: L("Type"), + options: [ + { + id: "multicombo", + value: L("Multi Combo"), + }, + { + id: "checkbox", + value: L("Checkboxes"), + }, + ], + on: { + onChange: () => this.onChange(), + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormSelectMultiplePropertyComponentDefaults = + this.defaultValues(); + + $$(ids.type).setValue( + view.settings.type || + ABViewFormSelectMultiplePropertyComponentDefaults.type + ); + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.type = $$(ids.type).getValue(); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("selectmultiple"); + } + } + + return ABViewFormSelectMultipleProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormSelectSingle.js b/src/plugins/web_view_form/properties/FNAbviewFormSelectSingle.js new file mode 100644 index 0000000..bd3a7f0 --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormSelectSingle.js @@ -0,0 +1,112 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormSelectSingle + * A Property manager for our ABViewFormSelectSingle definitions + */ + +export default function FNAbviewFormSelectSingleProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_select_single"; + + const L = AB.Label(); + + class ABViewFormSelectSingleProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + type: "", + }); + + this.AB = AB; + } + + static get key() { + return "selectsingle"; + } + + ui() { + const ids = this.ids; + + return super.ui([ + { + id: ids.type, + name: "type", + view: "richselect", + label: L("Type"), + options: [ + { + id: "richselect", + value: L("Select list"), + }, + { + id: "radio", + value: L("Radio"), + }, + ], + on: { + onChange: () => this.onChange(), + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormSelectSinglePropertyComponentDefaults = + this.defaultValues(); + + $$(ids.type).setValue( + view.settings.type || + ABViewFormSelectSinglePropertyComponentDefaults.type + ); + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.type = $$(ids.type).getValue(); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("selectsingle"); + } + } + + return ABViewFormSelectSingleProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormTextbox.js b/src/plugins/web_view_form/properties/FNAbviewFormTextbox.js new file mode 100644 index 0000000..5083da9 --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormTextbox.js @@ -0,0 +1,117 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormTextbox + * A Property manager for our ABViewFormTextbox definitions + */ + +export default function FNAbviewFormTextboxProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_textbox"; + + const L = AB.Label(); + + class ABViewFormTextboxProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, { + // Put our ids here + type: "", + }); + + this.AB = AB; + } + + static get key() { + return "textbox"; + } + + ui() { + const ids = this.ids; + + return super.ui([ + { + id: ids.type, + name: "type", + view: "radio", + label: L("Type"), + vertical: true, + options: [ + { + id: "single", + value: L("Single line"), + }, + { + id: "multiple", + value: L("Multiple lines"), + }, + { + id: "rich", + value: L("Rich editor"), + }, + ], + on: { + onChange: () => this.onChange(), + }, + }, + ]); + } + + async init(AB) { + this.AB = AB; + + await super.init(AB); + } + + populate(view) { + super.populate(view); + + const ids = this.ids; + const ABViewFormTextboxPropertyComponentDefaults = + this.defaultValues(); + + $$(ids.type).setValue( + view.settings.type || + ABViewFormTextboxPropertyComponentDefaults.type + ); + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + const ids = this.ids; + + const $component = $$(ids.component); + + const values = super.values() ?? {}; + values.settings = $component.getValues() ?? {}; + values.settings.type = $$(ids.type).getValue(); + + return values; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("textbox"); + } + } + + return ABViewFormTextboxProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormTree.js b/src/plugins/web_view_form/properties/FNAbviewFormTree.js new file mode 100644 index 0000000..3017e28 --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormTree.js @@ -0,0 +1,36 @@ +import FNAbviewformItem from "./FNAbviewFormItem.js"; + +/* + * ABViewFormTree + * A Property manager for our ABViewFormTree definitions + */ + +export default function FNAbviewFormTreeProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewFormItem = FNAbviewformItem({ AB, ABViewPropertiesPlugin }); + + const BASE_ID = "properties_abview_form_tree"; + + class ABViewFormTreeProperty extends ABViewFormItem { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(BASE_ID, {}); + + this.AB = AB; + } + + static get key() { + return "formtree"; + } + } + + return ABViewFormTreeProperty; +} diff --git a/src/plugins/web_view_form/properties/FNAbviewFormUrl.js b/src/plugins/web_view_form/properties/FNAbviewFormUrl.js new file mode 100644 index 0000000..a2666de --- /dev/null +++ b/src/plugins/web_view_form/properties/FNAbviewFormUrl.js @@ -0,0 +1,166 @@ +import FCommonKeyValue from "../../../rootPages/Designer/ui_common_key_value"; +import FNAbviewformProperties from "../FNAbviewform.js"; + +/* + * ABViewForm + * A Property manager for our ABViewForm definitions + */ + +export default function FNAbviewFormUrlProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewForm = FNAbviewformProperties({ AB, ABViewPropertiesPlugin }); + + const UIClassCommonKeyValue = FCommonKeyValue(AB); + const uiConfig = AB.Config.uiSettings(); + const L = AB.Label(); + + const base = "properties_abview_form_url"; + + class ABViewFormUrlProperty extends ABViewForm { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + constructor() { + super(base, { + method: "", + url: "", + headers: "", + }); + + this.AB = AB; + + this.UIKeyValues = new UIClassCommonKeyValue({ + title: L("Headers"), + keyTitle: L("Key"), + valueTitle: L("Value"), + // contextID: base || randomID(), + }); + } + + static get key() { + return "form-url"; + } + + ui() { + let ids = this.ids; + + return super.ui([ + { + view: "fieldset", + label: L("URL:"), + labelWidth: uiConfig.labelWidthLarge, + body: { + type: "clean", + padding: 10, + rows: [ + { + id: ids.method, + view: "richselect", + name: "urlMethod", + + label: L("Method"), + labelWidth: uiConfig.labelWidthLarge, + options: [ + { + id: "get", + value: L("GET"), + }, + { + id: "post", + value: L("POST"), + }, + + { + id: "put", + value: L("PUT"), + }, + { + id: "delete", + value: L("DELETE"), + }, + ], + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + { + id: ids.url, + view: "text", + label: L("URL"), + name: "url", + value: "", + on: { + onChange: () => { + this.onChange(); + }, + }, + }, + this.UIKeyValues.ui(), + ], + }, + }, + ]); + } + + populate(view) { + super.populate(view); + let ids = this.ids; + if (!view) return; + + var methodSelector = $$(ids.method); + methodSelector.define("value", view.settings?.method || "get"); + methodSelector.refresh(); + methodSelector.enable(); + + $$(ids.url).setValue(view.settings.url); + + this.UIKeyValues.populate(view.settings?.headers || []); + } + + defaultValues() { + let values = {}; + var ViewClass = this.ViewClass(); + if (ViewClass) { + values = ViewClass.defaultValues(); + } + return values; + } + + /** + * @method values + * return the values for this form. + * @return {obj} + */ + values() { + let ids = this.ids; + let vals = super.values(); + + vals.settings = vals.settings || {}; + + vals.settings.method = $$(ids.method).getValue(); + vals.settings.url = $$(ids.url).getValue(); + + vals.headers = this.UIKeyValues.getValues(); + return vals; + } + + /** + * @method FieldClass() + * A method to return the proper ABViewXXX Definition. + * NOTE: Must be overwritten by the Child Class + */ + ViewClass() { + return super._ViewClass("form-url"); + } + } + + return ABViewFormUrlProperty; +} diff --git a/src/rootPages/Designer/editors/EditorManager.js b/src/rootPages/Designer/editors/EditorManager.js index 5d02be7..d6f7460 100644 --- a/src/rootPages/Designer/editors/EditorManager.js +++ b/src/rootPages/Designer/editors/EditorManager.js @@ -25,8 +25,7 @@ export default function (AB) { // require("./views/ABViewDataview"), // require("./views/ABViewDetail"), // require("./views/ABViewDocxBuilder"), - require("./views/ABViewForm"), - require("./views/ABViewFormUrl"), + // require("./views/ABViewFormUrl"), // require("./views/ABViewGantt"), // require("./views/ABViewKanban"), // require("./views/ABViewGrid"), diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js index 27505aa..27cf058 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -90,19 +90,19 @@ export default function (AB) { require("./views/ABViewDetailText"), require("./views/ABViewDetailTree"), // require("./views/ABViewDocxBuilder"), - require("./views/ABViewForm"), - require("./views/ABViewFormButton"), - require("./views/ABViewFormCheckbox"), - require("./views/ABViewFormConnect"), - require("./views/ABViewFormCustom"), - require("./views/ABViewFormDatepicker"), - require("./views/ABViewFormJson"), - require("./views/ABViewFormNumber"), - require("./views/ABViewFormSelectMultiple"), - require("./views/ABViewFormSelectSingle"), - require("./views/ABViewFormTextbox"), - require("./views/ABViewFormTree"), - require("./views/ABViewFormUrl"), + // require("./views/ABViewForm"), + // require("./views/ABViewFormButton"), + // require("./views/ABViewFormCheckbox"), + // require("./views/ABViewFormConnect"), + // require("./views/ABViewFormCustom"), + // require("./views/ABViewFormDatepicker"), + // require("./views/ABViewFormJson"), + // require("./views/ABViewFormNumber"), + // require("./views/ABViewFormSelectMultiple"), + // require("./views/ABViewFormSelectSingle"), + // require("./views/ABViewFormTextbox"), + // require("./views/ABViewFormTree"), + // require("./views/ABViewFormUrl"), // require("./views/ABViewGantt"), // require("./views/ABViewGrid"), // require("./views/ABViewImage"),