From da1db72196cff57aeb75a72753427892eab36b5b Mon Sep 17 00:00:00 2001 From: BenWirachot Date: Fri, 3 Jul 2026 09:50:53 +0700 Subject: [PATCH 1/3] Decouple detail view properties from PropertyManager and expose as a list of plugin components in FNAbviewdetail --- src/plugins/web_view_detail/FNAbviewdetail.js | 25 +++++++++---- .../properties/FNAbviewDetailCheckbox.js} | 30 +++++++++------- .../properties/FNAbviewDetailCustom.js} | 30 +++++++++------- .../properties/FNAbviewDetailImage.js} | 35 +++++++++---------- .../properties/FNAbviewDetailItem.js} | 29 +++++++++------ .../properties/FNAbviewDetailText.js} | 35 +++++++++---------- .../properties/FNAbviewDetailTree.js} | 30 +++++++++------- .../Designer/properties/PropertyManager.js | 12 +++---- 8 files changed, 128 insertions(+), 98 deletions(-) rename src/{rootPages/Designer/properties/views/ABViewDetailCheckbox.js => plugins/web_view_detail/properties/FNAbviewDetailCheckbox.js} (51%) rename src/{rootPages/Designer/properties/views/ABViewDetailCustom.js => plugins/web_view_detail/properties/FNAbviewDetailCustom.js} (51%) rename src/{rootPages/Designer/properties/views/ABViewDetailImage.js => plugins/web_view_detail/properties/FNAbviewDetailImage.js} (78%) rename src/{rootPages/Designer/properties/views/ABViewDetailItem.js => plugins/web_view_detail/properties/FNAbviewDetailItem.js} (66%) rename src/{rootPages/Designer/properties/views/ABViewDetailText.js => plugins/web_view_detail/properties/FNAbviewDetailText.js} (73%) rename src/{rootPages/Designer/properties/views/ABViewDetailTree.js => plugins/web_view_detail/properties/FNAbviewDetailTree.js} (50%) diff --git a/src/plugins/web_view_detail/FNAbviewdetail.js b/src/plugins/web_view_detail/FNAbviewdetail.js index fc6be29b..5e839de6 100644 --- a/src/plugins/web_view_detail/FNAbviewdetail.js +++ b/src/plugins/web_view_detail/FNAbviewdetail.js @@ -1,24 +1,27 @@ -// FNAbviewdetail Properties -// A properties side import for an ABView. -// +import FNAbviewDetailCheckboxProperties from "./properties/FNAbviewDetailCheckbox.js"; +import FNAbviewDetailCustomProperties from "./properties/FNAbviewDetailCustom.js"; +import FNAbviewDetailImageProperties from "./properties/FNAbviewDetailImage.js"; +import FNAbviewDetailItemProperties from "./properties/FNAbviewDetailItem.js"; +import FNAbviewDetailTextProperties from "./properties/FNAbviewDetailText.js"; +import FNAbviewDetailTreeProperties from "./properties/FNAbviewDetailTree.js"; import FABViewContainer from "../../rootPages/Designer/properties/views/ABViewContainer"; -export default function FNAbviewdetailProperties({ AB }) { +export default function FNAbviewdetailProperties(API) { + const { AB } = API; const ABViewContainer = FABViewContainer(AB); const uiConfig = AB.Config.uiSettings(); const L = ABViewContainer.L(); let ABViewDetailPropertyComponentDefaults = {}; - return class ABAbviewdetailProperties extends ABViewContainer { + const ABAbviewdetailProperties = class ABAbviewdetailProperties extends ABViewContainer { static getPluginKey() { return this.key; } static getPluginType() { return "properties-view"; - // properties-view : will display in the properties panel of the ABDesigner } constructor(base, ids = {}) { @@ -371,4 +374,14 @@ export default function FNAbviewdetailProperties({ AB }) { } } }; + + return [ + ABAbviewdetailProperties, + FNAbviewDetailItemProperties(API), + FNAbviewDetailCheckboxProperties(API), + FNAbviewDetailCustomProperties(API), + FNAbviewDetailImageProperties(API), + FNAbviewDetailTextProperties(API), + FNAbviewDetailTreeProperties(API), + ]; } diff --git a/src/rootPages/Designer/properties/views/ABViewDetailCheckbox.js b/src/plugins/web_view_detail/properties/FNAbviewDetailCheckbox.js similarity index 51% rename from src/rootPages/Designer/properties/views/ABViewDetailCheckbox.js rename to src/plugins/web_view_detail/properties/FNAbviewDetailCheckbox.js index c4ce4452..c10acac4 100644 --- a/src/rootPages/Designer/properties/views/ABViewDetailCheckbox.js +++ b/src/plugins/web_view_detail/properties/FNAbviewDetailCheckbox.js @@ -1,15 +1,16 @@ -/** - * ABViewDetailCheckbox - * A Property manager for our ABViewDetailCheckbox definitions - */ +import FNAbviewDetailItemProperties from "./FNAbviewDetailItem.js"; -import FABViewDetailItem from "./ABViewDetailItem"; +export default function FNAbviewDetailCheckboxProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewDetailItem = FNAbviewDetailItemProperties({ + AB, + ABViewPropertiesPlugin, + }); -export default function (AB) { const BASE_ID = "properties_abview_detail_checkbox"; - const ABViewDetailItem = FABViewDetailItem(AB); - class ABViewDetailCheckboxProperty extends ABViewDetailItem { constructor() { super(BASE_ID, { @@ -19,15 +20,18 @@ export default function (AB) { this.AB = AB; } + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + static get key() { return "detailcheckbox"; } - /** - * @method FieldClass() - * A method to return the proper ABViewXXX Definition. - * NOTE: Must be overwritten by the Child Class - */ ViewClass() { return super._ViewClass("detailcheckbox"); } diff --git a/src/rootPages/Designer/properties/views/ABViewDetailCustom.js b/src/plugins/web_view_detail/properties/FNAbviewDetailCustom.js similarity index 51% rename from src/rootPages/Designer/properties/views/ABViewDetailCustom.js rename to src/plugins/web_view_detail/properties/FNAbviewDetailCustom.js index d65c906b..61064590 100644 --- a/src/rootPages/Designer/properties/views/ABViewDetailCustom.js +++ b/src/plugins/web_view_detail/properties/FNAbviewDetailCustom.js @@ -1,15 +1,16 @@ -/** - * ABViewDetailCustom - * A Property manager for our ABViewDetailCustom definitions - */ +import FNAbviewDetailItemProperties from "./FNAbviewDetailItem.js"; -import FABViewDetailItem from "./ABViewDetailItem"; +export default function FNAbviewDetailCustomProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewDetailItem = FNAbviewDetailItemProperties({ + AB, + ABViewPropertiesPlugin, + }); -export default function (AB) { const BASE_ID = "properties_abview_detail_custom"; - const ABViewDetailItem = FABViewDetailItem(AB); - class ABViewDetailCustomProperty extends ABViewDetailItem { constructor() { super(BASE_ID, { @@ -19,15 +20,18 @@ export default function (AB) { this.AB = AB; } + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + static get key() { return "detailcustom"; } - /** - * @method FieldClass() - * A method to return the proper ABViewXXX Definition. - * NOTE: Must be overwritten by the Child Class - */ ViewClass() { return super._ViewClass("detailcustom"); } diff --git a/src/rootPages/Designer/properties/views/ABViewDetailImage.js b/src/plugins/web_view_detail/properties/FNAbviewDetailImage.js similarity index 78% rename from src/rootPages/Designer/properties/views/ABViewDetailImage.js rename to src/plugins/web_view_detail/properties/FNAbviewDetailImage.js index a10cf4b8..8c25c035 100644 --- a/src/rootPages/Designer/properties/views/ABViewDetailImage.js +++ b/src/plugins/web_view_detail/properties/FNAbviewDetailImage.js @@ -1,19 +1,20 @@ -/** - * ABViewDetailImage - * A Property manager for our ABViewDetailImage definitions - */ +import FNAbviewDetailItemProperties from "./FNAbviewDetailItem.js"; -import FABViewDetailItem from "./ABViewDetailItem"; +export default function FNAbviewDetailImageProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewDetailItem = FNAbviewDetailItemProperties({ + AB, + ABViewPropertiesPlugin, + }); -export default function (AB) { const BASE_ID = "properties_abview_detail_image"; const DEFAULT_VALUES = { height: 0, width: 0, }; - const ABViewDetailItem = FABViewDetailItem(AB); - class ABViewDetailImageProperty extends ABViewDetailItem { constructor() { super(BASE_ID, { @@ -24,6 +25,14 @@ export default function (AB) { this.AB = AB; } + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + static get key() { return "detailimage"; } @@ -51,11 +60,6 @@ export default function (AB) { ]); } - /** - * @method FieldClass() - * A method to return the proper ABViewXXX Definition. - * NOTE: Must be overwritten by the Child Class - */ ViewClass() { return super._ViewClass("detailimage"); } @@ -74,11 +78,6 @@ export default function (AB) { return Object.assign(DEFAULT_VALUES, values); } - /** - * @method values - * return the values for this form. - * @return {obj} - */ values() { const values = super.values() ?? {}; values.settings = values.settings ?? {}; diff --git a/src/rootPages/Designer/properties/views/ABViewDetailItem.js b/src/plugins/web_view_detail/properties/FNAbviewDetailItem.js similarity index 66% rename from src/rootPages/Designer/properties/views/ABViewDetailItem.js rename to src/plugins/web_view_detail/properties/FNAbviewDetailItem.js index 88549142..d0701a80 100644 --- a/src/rootPages/Designer/properties/views/ABViewDetailItem.js +++ b/src/plugins/web_view_detail/properties/FNAbviewDetailItem.js @@ -1,18 +1,25 @@ -/* - * ABViewDetailItem - * A Property manager for our ABViewDetailItem definitions - */ +export default function FNAbviewDetailItemProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const L = AB.Label(); -import FABView from "./ABView"; + class ABViewDetailItemProperty extends ABViewPropertiesPlugin { + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } -export default function (AB) { - const ABView = FABView(AB); - const L = ABView.L(); + static get key() { + return "detailitem"; + } - class ABViewDetailItemProperty extends ABView { constructor(BASE_ID, ids = {}) { super( - BASE_ID, + BASE_ID ?? "properties_abview_detail_item", Object.assign(ids, { // Put our ids here field: "", @@ -44,7 +51,7 @@ export default function (AB) { (f) => f.id == view.settings.fieldId ); - $$(this.ids.field).setValue(field.label); + $$(this.ids.field).setValue(field ? field.label : ""); } defaultValues() { diff --git a/src/rootPages/Designer/properties/views/ABViewDetailText.js b/src/plugins/web_view_detail/properties/FNAbviewDetailText.js similarity index 73% rename from src/rootPages/Designer/properties/views/ABViewDetailText.js rename to src/plugins/web_view_detail/properties/FNAbviewDetailText.js index a2d8a396..4fcbcf9f 100644 --- a/src/rootPages/Designer/properties/views/ABViewDetailText.js +++ b/src/plugins/web_view_detail/properties/FNAbviewDetailText.js @@ -1,18 +1,19 @@ -/** - * ABViewDetailText - * A Property manager for our ABViewDetailText definitions - */ +import FNAbviewDetailItemProperties from "./FNAbviewDetailItem.js"; -import FABViewDetailItem from "./ABViewDetailItem"; +export default function FNAbviewDetailTextProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewDetailItem = FNAbviewDetailItemProperties({ + AB, + ABViewPropertiesPlugin, + }); -export default function (AB) { const BASE_ID = "properties_abview_detail_text"; const DEFAULT_VALUES = { height: 0, }; - const ABViewDetailItem = FABViewDetailItem(AB); - class ABViewDetailTextProperty extends ABViewDetailItem { constructor() { super(BASE_ID, { @@ -22,6 +23,14 @@ export default function (AB) { this.AB = AB; } + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + static get key() { return "detailtext"; } @@ -40,11 +49,6 @@ export default function (AB) { ]); } - /** - * @method FieldClass() - * A method to return the proper ABViewXXX Definition. - * NOTE: Must be overwritten by the Child Class - */ ViewClass() { return super._ViewClass("detailtext"); } @@ -61,11 +65,6 @@ export default function (AB) { return Object.assign(DEFAULT_VALUES, values); } - /** - * @method values - * return the values for this form. - * @return {obj} - */ values() { const values = super.values() ?? {}; values.settings = values.settings ?? {}; diff --git a/src/rootPages/Designer/properties/views/ABViewDetailTree.js b/src/plugins/web_view_detail/properties/FNAbviewDetailTree.js similarity index 50% rename from src/rootPages/Designer/properties/views/ABViewDetailTree.js rename to src/plugins/web_view_detail/properties/FNAbviewDetailTree.js index 92baac5c..8c5a5e9f 100644 --- a/src/rootPages/Designer/properties/views/ABViewDetailTree.js +++ b/src/plugins/web_view_detail/properties/FNAbviewDetailTree.js @@ -1,15 +1,16 @@ -/** - * ABViewDetailTree - * A Property manager for our ABViewDetailTree definitions - */ +import FNAbviewDetailItemProperties from "./FNAbviewDetailItem.js"; -import FABViewDetailItem from "./ABViewDetailItem"; +export default function FNAbviewDetailTreeProperties({ + AB, + ABViewPropertiesPlugin, +}) { + const ABViewDetailItem = FNAbviewDetailItemProperties({ + AB, + ABViewPropertiesPlugin, + }); -export default function (AB) { const BASE_ID = "properties_abview_detail_tree"; - const ABViewDetailItem = FABViewDetailItem(AB); - class ABViewDetailTreeProperty extends ABViewDetailItem { constructor() { super(BASE_ID, { @@ -19,15 +20,18 @@ export default function (AB) { this.AB = AB; } + static getPluginKey() { + return this.key; + } + + static getPluginType() { + return "properties-view"; + } + static get key() { return "detailtree"; } - /** - * @method FieldClass() - * A method to return the proper ABViewXXX Definition. - * NOTE: Must be overwritten by the Child Class - */ ViewClass() { return super._ViewClass("detailtree"); } diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js index 27cf0588..576f0274 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -83,12 +83,12 @@ export default function (AB) { // require("./views/ABViewDataSelect"), // require("./views/ABViewDataview"), // require("./views/ABViewDetail"), - require("./views/ABViewDetailCheckbox"), - require("./views/ABViewDetailCustom"), - require("./views/ABViewDetailImage"), - require("./views/ABViewDetailItem"), - require("./views/ABViewDetailText"), - require("./views/ABViewDetailTree"), + // require("./views/ABViewDetailCheckbox"), + // require("./views/ABViewDetailCustom"), + // require("./views/ABViewDetailImage"), + // require("./views/ABViewDetailItem"), + // require("./views/ABViewDetailText"), + // require("./views/ABViewDetailTree"), // require("./views/ABViewDocxBuilder"), // require("./views/ABViewForm"), // require("./views/ABViewFormButton"), From edd77bb30cfbd999aba81cb3eefa80eb10675237 Mon Sep 17 00:00:00 2001 From: BenWirachot Date: Thu, 23 Jul 2026 15:29:09 +0700 Subject: [PATCH 2/3] Update ABViewDetail import path and simplify signature in dataview properties while fixing indentation formatting --- src/plugins/web_view_dataview/FNAbviewdataview.js | 13 ++++--------- .../viewProperties/ABViewPropertyFilterData.js | 4 ++-- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/plugins/web_view_dataview/FNAbviewdataview.js b/src/plugins/web_view_dataview/FNAbviewdataview.js index e3ec26d8..e3d78752 100644 --- a/src/plugins/web_view_dataview/FNAbviewdataview.js +++ b/src/plugins/web_view_dataview/FNAbviewdataview.js @@ -2,18 +2,13 @@ // A properties side import for an ABView. // -import FABViewDetail from "../web_view_detail/FNAbviewdetail"; +import FABViewDetail from "../../rootPages/Designer/properties/views/ABViewDetail"; import ABViewPropertyLinkPage from "../../rootPages/Designer/properties/views/viewProperties/ABViewPropertyLinkPage"; -export default function FNAbviewdataviewProperties({ - AB, - // ABViewPropertiesPlugin, - // ABUIPlugin, -}) { +export default function FNAbviewdataviewProperties({ AB }) { const base = "properties_abview_dataview"; - const ABViewDetail = FABViewDetail({ AB }); - // NOTE: this is another plugin, so pass in { AB } + const ABViewDetail = FABViewDetail(AB); const LinkPageProperty = ABViewPropertyLinkPage(AB, base); const uiConfig = AB.Config.uiSettings(); @@ -87,7 +82,7 @@ export default function FNAbviewdataviewProperties({ $$(ids.xCount).setValue( view.settings.xCount || - ABViewDataviewPropertyComponentDefaults.xCount + ABViewDataviewPropertyComponentDefaults.xCount ); this.linkPageComponent.viewLoad(view); diff --git a/src/rootPages/Designer/properties/views/viewProperties/ABViewPropertyFilterData.js b/src/rootPages/Designer/properties/views/viewProperties/ABViewPropertyFilterData.js index 54b4a05d..8df75cdf 100644 --- a/src/rootPages/Designer/properties/views/viewProperties/ABViewPropertyFilterData.js +++ b/src/rootPages/Designer/properties/views/viewProperties/ABViewPropertyFilterData.js @@ -371,7 +371,7 @@ export default function (AB, idBase) { $$(ids.filterOptionRadio).setValue(option); $$(ids.filterUser).setValue( settings.userFilterPosition || - ABViewPropertyFilterData.default.userFilterPosition + ABViewPropertyFilterData.default.userFilterPosition ); $$(ids.globalToolbar).setValue( typeof settings.isGlobalToolbar != "undefined" @@ -381,7 +381,7 @@ export default function (AB, idBase) { $$(ids.filterGlobal).setValue( settings.globalFilterPosition || - ABViewPropertyFilterData.default.globalFilterPosition + ABViewPropertyFilterData.default.globalFilterPosition ); // clear any existing Rules: From 22fe2dcb2a728396c18e45943f16010c69f1de79 Mon Sep 17 00:00:00 2001 From: BenWirachot Date: Thu, 23 Jul 2026 17:30:50 +0700 Subject: [PATCH 3/3] Dynamically load view property editors and synchronize property panel state on re-selection --- src/plugins/web_view_grid/FNAbviewgrid.js | 43 ++++++++----------- .../Designer/properties/PropertyManager.js | 16 ++++++- ..._interface_workspace_details_properties.js | 7 ++- .../Designer/ui_work_pwa_properties.js | 1 + 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/plugins/web_view_grid/FNAbviewgrid.js b/src/plugins/web_view_grid/FNAbviewgrid.js index a7b41384..9cfea4fb 100644 --- a/src/plugins/web_view_grid/FNAbviewgrid.js +++ b/src/plugins/web_view_grid/FNAbviewgrid.js @@ -452,22 +452,6 @@ export default function FNAbviewgridProperties({ async init(AB) { super.init(AB); - // Load in all the Available Datacollections: - var listDC = this.CurrentApplication.datacollectionsIncluded().map( - (d) => { - return { - id: d.id, - value: d.label, - icon: - d.sourceType == "query" - ? "fa fa-filter" - : "fa fa-database", - }; - } - ); - $$(this.ids.datacollection).define("options", listDC); - $$(this.ids.datacollection).refresh(); - /// Filter Data Helper: this._handler_onCancel = () => { @@ -601,10 +585,26 @@ export default function FNAbviewgridProperties({ if (!view) return; + // Load in all the Available Datacollections (done here so view.application is used directly): + var listDC = view.application.datacollectionsIncluded().map( + (d) => { + return { + id: d.id, + value: d.label, + icon: + d.sourceType == "query" + ? "fa fa-filter" + : "fa fa-database", + }; + } + ); + $$(ids.datacollection).define("options", listDC); + $$(ids.datacollection).refresh(); + // this.viewEditing = view; let $dataCollection = $$(ids.datacollection); $dataCollection.blockEvent(); - $dataCollection.setValue(view.settings.dataviewID); + $dataCollection.setValue(view.settings.dataviewID || ""); $dataCollection.unblockEvent(); $$(ids.isEditable).setValue(view.settings.isEditable); $$(ids.massUpdate).setValue(view.settings.massUpdate); @@ -612,15 +612,6 @@ export default function FNAbviewgridProperties({ $$(ids.isSortable).setValue(view.settings.isSortable); $$(ids.isExportable).setValue(view.settings.isExportable); - // populate the Datacollection chooser - if (view.settings.datacollection != "") { - $$(ids.datacollection).setValue(view.settings.dataviewID); - // $$(ids.linkedObject).show(); - } else { - $$(ids.datacollection).setValue(""); - // $$(ids.linkedObject).hide(); - } - $$(ids.height).setValue(view.settings.height); $$(ids.hideHeader).setValue(view.settings.hideHeader); $$(ids.labelAsField).setValue(view.settings.labelAsField); diff --git a/src/rootPages/Designer/properties/PropertyManager.js b/src/rootPages/Designer/properties/PropertyManager.js index 576f0274..b74f45f4 100644 --- a/src/rootPages/Designer/properties/PropertyManager.js +++ b/src/rootPages/Designer/properties/PropertyManager.js @@ -176,11 +176,23 @@ export default function (AB) { }, processElements: function (f = () => true) { - return Plugins.concat(Processes).filter(f); + const dynamicPlugins = []; + if (AB.ClassManager && AB.ClassManager.viewPropertiesAll) { + AB.ClassManager.viewPropertiesAll().forEach((ViewPropertyClass) => { + dynamicPlugins.push(ViewPropertyClass); + }); + } + return dynamicPlugins.concat(Processes).filter(f); }, views: function (v = () => true) { - return Plugins.concat(Views).filter(v); + const dynamicPlugins = []; + if (AB.ClassManager && AB.ClassManager.viewPropertiesAll) { + AB.ClassManager.viewPropertiesAll().forEach((ViewPropertyClass) => { + dynamicPlugins.push(ViewPropertyClass); + }); + } + return dynamicPlugins.concat(Views).filter(v); }, mobileViews: function (v = () => true) { diff --git a/src/rootPages/Designer/ui_work_interface_workspace_details_properties.js b/src/rootPages/Designer/ui_work_interface_workspace_details_properties.js index d89bc0ed..9ca2f6e5 100644 --- a/src/rootPages/Designer/ui_work_interface_workspace_details_properties.js +++ b/src/rootPages/Designer/ui_work_interface_workspace_details_properties.js @@ -195,10 +195,11 @@ export default function (AB) { if (view.id != this.CurrentViewID) { super.viewLoad(view); - let _editor = this._editorsByType[view.key]; + let _editor = PropertyManager.views((V) => V.key == view.key)[0]; if (_editor) { let newPanel = new _editor(); + newPanel.AB = this.AB; newPanel.applicationLoad(this.CurrentApplication); let ui = [newPanel.ui()]; @@ -211,9 +212,13 @@ export default function (AB) { this.currentPanel = newPanel; // newPanel.show(); } + } else if (this.currentPanel) { + // Same view re-selected: re-populate so properties stay in sync + this.currentPanel.populate(view); } } + ready() { const $component = $$(this.ids.component); $component?.enable?.(); diff --git a/src/rootPages/Designer/ui_work_pwa_properties.js b/src/rootPages/Designer/ui_work_pwa_properties.js index d4b4ecbb..e79c8758 100644 --- a/src/rootPages/Designer/ui_work_pwa_properties.js +++ b/src/rootPages/Designer/ui_work_pwa_properties.js @@ -236,6 +236,7 @@ export default function (AB) { if (_editor) { let newPanel = new _editor(); + newPanel.AB = this.AB; newPanel.applicationLoad(this.CurrentApplication); let ui = [newPanel.ui()];