@siliconst/metaui 1.4.9 → 1.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js +10 -0
- package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.js +1 -1
- package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/controls/DynamicHost.ts +11 -0
- package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js +2 -0
- package/src/nz/co/siliconst/ui5/metaui/core/Engine-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts +2 -0
- package/src/nz/co/siliconst/ui5/metaui/core/Engine.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/core/Engine.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/core/Engine.ts +3 -0
- package/src/nz/co/siliconst/ui5/metaui/layouts/TableLayout-dbg.js +10 -0
- package/src/nz/co/siliconst/ui5/metaui/layouts/TableLayout-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/layouts/TableLayout.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/layouts/TableLayout.js +1 -1
- package/src/nz/co/siliconst/ui5/metaui/layouts/TableLayout.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/layouts/TableLayout.ts +10 -0
- package/src/nz/co/siliconst/ui5/metaui/library-preload.js +6 -6
- package/src/nz/co/siliconst/ui5/metaui/library-preload.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin-dbg.js +6 -0
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin.js +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin.ts +6 -0
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin-dbg.js +5 -2
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin.js +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin.ts +5 -2
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin-dbg.js +6 -0
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin.js +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin.ts +6 -0
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin-dbg.js +39 -3
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin-dbg.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.d.ts +4 -0
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.d.ts.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.js +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.js.map +1 -1
- package/src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.ts +40 -2
|
@@ -61,6 +61,12 @@ sap.ui.define(["./BasePlugin", "sap/m/Button"], function (___BasePlugin, Button)
|
|
|
61
61
|
host.attachSubmit(e => {
|
|
62
62
|
const payload = e.getParameter("payload");
|
|
63
63
|
parentModel.setProperty(updatePath, payload);
|
|
64
|
+
|
|
65
|
+
// CRITICAL: Notify the parent Engine that this field mutated
|
|
66
|
+
// so it can trigger LiveUpdate syncs and validate!
|
|
67
|
+
if (this.onChange) {
|
|
68
|
+
this.onChange(true, propKey);
|
|
69
|
+
}
|
|
64
70
|
});
|
|
65
71
|
}
|
|
66
72
|
const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? "Close" : "OK");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrayPlugin-dbg.js","names":["BasePlugin","___BasePlugin","ArrayPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","items","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","getValue","applyState","__exports","__esModule"],"sources":["ArrayPlugin.ts"],"sourcesContent":["/**\n * @file ArrayPlugin.ts\n * @description Renders a button that drills down into a nested table (array) via a recursive Dialog using v2 schema.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ArrayPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested array form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"array\",\n title: field.ui?.label || propKey,\n items: field.items || {\n type: \"object\",\n properties: {} // inference will handle it if empty\n }\n };\n\n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Records\" : \"Edit Records\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://list\",\n press: (oEvent: sap.ui.base.Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || []));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable // Pass the display mode down to the child Engine!\n });\n\n // Only attach submit event if we are not in display mode\n if (!!this.isEditable) {\n host.attachSubmit((e: sap.ui.base.Event) => {\n const payload = e.getParameter(\"payload\");\n parentModel.setProperty(updatePath, payload);\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Records: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n \n return this.control as Control;\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): unknown {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // dynamic state changes\n }\n}\n"],"mappings":";;;EAAA;AACA;AACA;AACA;EAHA,MAKSA,UAAU,GAAAC,aAAA;EAMZ,MAAMC,WAAW,SAASF,UAAU,CAAC;IACxC;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IACWG,MAAMA,CAACC,KAAwB,EAAGC,WAAmB,EAAGC,SAAiB,GAAG,MAAM,EAAEC,aAAsB,EAAEC,QAAwD,EAAW;MAClL,IAAI,CAACA,QAAQ,GAAGA,QAAQ;MACxB,IAAI,CAACC,QAAQ,GAAGL,KAAK;MACrB,MAAMM,OAAO,GAAGL,WAAW,CAACM,UAAU,CAAC,GAAG,CAAC,GAAGN,WAAW,CAACO,SAAS,CAAC,CAAC,CAAC,GAAGP,WAAW;MAEpF,MAAMQ,SAAkB,GAAG;QACvBC,IAAI,EAAE,OAAO;QACbC,KAAK,EAAEX,KAAK,CAACY,EAAE,EAAEC,KAAK,IAAIP,OAAO;QACjCQ,KAAK,EAAEd,KAAK,CAACc,KAAK,IAAI;UAClBJ,IAAI,EAAE,QAAQ;UACdK,UAAU,EAAE,CAAC,CAAC,CAAC;QACnB;MACJ,CAAC;MAED,IAAIf,KAAK,CAACgB,QAAQ,EAAE;QAChBP,SAAS,CAACO,QAAQ,GAAGhB,KAAK,CAACgB,QAAQ;MACvC;MAEA,IAAI,CAACC,OAAO,GAAG,IAAIC,MAAM,CAAC;QACtBC,EAAE,EAAE,IAAI,CAACC,gBAAgB,CAACjB,aAAa,EAAEF,WAAW,CAAC;QACrDoB,IAAI,EAAE,CAAC,IAAI,CAACC,UAAU,GAAG,cAAc,GAAG,cAAc;QACxDC,IAAI,EAAE,CAAC,IAAI,CAACD,UAAU,GAAG,oBAAoB,GAAG,iBAAiB;QACjEE,KAAK,EAAGC,MAAyB,IAAK;UAClC,MAAMC,GAAG,GAAGD,MAAM,CAACE,SAAS,CAAC,CAAW;UACxC,MAAMC,WAAW,GAAGF,GAAG,CAACG,QAAQ,CAAC3B,SAAS,CAAc;UACxD,IAAI,CAAC0B,WAAW,EAAE;UAElB,MAAME,cAAc,GAAGJ,GAAG,CAACK,iBAAiB,CAAC7B,SAAS,CAAC;UACvD,IAAI8B,UAAU,GAAG/B,WAAW;UAC5B,IAAI6B,cAAc,IAAI,CAAC7B,WAAW,CAACM,UAAU,CAAC,GAAG,CAAC,EAAE;YAChD,MAAM0B,OAAO,GAAGH,cAAc,CAACI,OAAO,CAAC,CAAC;YACxCF,UAAU,GAAGC,OAAO,CAACE,QAAQ,CAAC,GAAG,CAAC,GAAGF,OAAO,GAAGhC,WAAW,GAAIgC,OAAO,KAAK,GAAG,GAAG,GAAG,GAAGhC,WAAW,GAAGgC,OAAO,GAAG,GAAG,GAAGhC,WAAY;UACpI;;UAEA;UACA,MAAMmC,UAAU,GAAGC,IAAI,CAACC,KAAK,CAACD,IAAI,CAACE,SAAS,CAACX,WAAW,CAACY,WAAW,CAACR,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;UAExFS,GAAG,CAAC7B,EAAE,CAAC8B,OAAO,CAAC,CAAC,iDAAiD,CAAC,EAAGC,WAAgE,IAAK;YACtI,MAAMC,IAAI,GAAG,IAAID,WAAW,CAAC;cACzBE,gBAAgB,EAAEpC,SAAS;cAC3BqC,IAAI,EAAEV,UAAU;cAChBW,QAAQ,EAAE,IAAI,CAACzB,UAAU,CAAC;YAC9B,CAAC,CAAC;;YAEF;YACA,IAAI,CAAC,CAAC,IAAI,CAACA,UAAU,EAAE;cACnBsB,IAAI,CAACI,YAAY,CAAEC,CAAoB,IAAK;gBACxC,MAAMC,OAAO,GAAGD,CAAC,CAACE,YAAY,CAAC,SAAS,CAAC;gBACzCvB,WAAW,CAACwB,WAAW,CAACpB,UAAU,EAAEkB,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ArrayPlugin-dbg.js","names":["BasePlugin","___BasePlugin","ArrayPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","items","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","getValue","applyState","__exports","__esModule"],"sources":["ArrayPlugin.ts"],"sourcesContent":["/**\n * @file ArrayPlugin.ts\n * @description Renders a button that drills down into a nested table (array) via a recursive Dialog using v2 schema.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ArrayPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested array form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"array\",\n title: field.ui?.label || propKey,\n items: field.items || {\n type: \"object\",\n properties: {} // inference will handle it if empty\n }\n };\n\n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Records\" : \"Edit Records\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://list\",\n press: (oEvent: sap.ui.base.Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || []));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable // Pass the display mode down to the child Engine!\n });\n\n // Only attach submit event if we are not in display mode\n if (!!this.isEditable) {\n host.attachSubmit((e: sap.ui.base.Event) => {\n const payload = e.getParameter(\"payload\");\n parentModel.setProperty(updatePath, payload);\n\n // CRITICAL: Notify the parent Engine that this field mutated\n // so it can trigger LiveUpdate syncs and validate!\n if (this.onChange) {\n this.onChange(true, propKey);\n }\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Records: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n \n return this.control as Control;\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): unknown {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // dynamic state changes\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrayPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,yDAAyD,CAAC;IACzE;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAClF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAI1C,MAAa,WAAY,SAAQ,UAAU;QACvC;;;;;;;;;WASG;QACI,MAAM,CAAC,KAAK,EAAE,iBAAiB,EAAG,WAAW,EAAE,MAAM,EAAG,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"ArrayPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/ArrayPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,yDAAyD,CAAC;IACzE;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAClF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAI1C,MAAa,WAAY,SAAQ,UAAU;QACvC;;;;;;;;;WASG;QACI,MAAM,CAAC,KAAK,EAAE,iBAAiB,EAAG,WAAW,EAAE,MAAM,EAAG,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QAmErL;;WAEG;QACH,SAAS,CAAC,QAAQ,IAAI,OAAO;QAI7B;;WAEG;QACH,SAAS,CAAC,UAAU,IAAI,IAAI;KAG/B;CAEA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
sap.ui.define(["./BasePlugin","sap/m/Button"],function(t,e){"use strict";const i=t["BasePlugin"];class s extends i{render(t,i,s="meta",a
|
|
1
|
+
sap.ui.define(["./BasePlugin","sap/m/Button"],function(t,e){"use strict";const i=t["BasePlugin"];class s extends i{render(t,i,s="meta",n,a){this.onChange=a;this.metadata=t;const o=i.startsWith("/")?i.substring(1):i;const r={type:"array",title:t.ui?.label||o,items:t.items||{type:"object",properties:{}}};if(t.uiLayout){r.uiLayout=t.uiLayout}this.control=new e({id:this.generateStableId(n,i),text:!this.isEditable?"View Records":"Edit Records",icon:!this.isEditable?"sap-icon://display":"sap-icon://list",press:e=>{const n=e.getSource();const a=n.getModel(s);if(!a)return;const l=n.getBindingContext(s);let u=i;if(l&&!i.startsWith("/")){const t=l.getPath();u=t.endsWith("/")?t+i:t==="/"?"/"+i:t+"/"+i}const c=JSON.parse(JSON.stringify(a.getProperty(u)||[]));sap.ui.require(["nz/co/siliconst/ui5/metaui/controls/DynamicHost"],e=>{const i=new e({schemaDefinition:r,data:c,editable:this.isEditable});if(!!this.isEditable){i.attachSubmit(t=>{const e=t.getParameter("payload");a.setProperty(u,e);if(this.onChange){this.onChange(true,o)}})}const s=t.ui?.dialogButtonText||(!this.isEditable?"Close":"OK");i.openInDialog(`Nested Records: ${t.ui?.label||o}`,s)})}});return this.control}getValue(){return null}applyState(){}}var n={__esModule:true};n.ArrayPlugin=s;return n});
|
|
2
2
|
//# sourceMappingURL=ArrayPlugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrayPlugin.js","names":["BasePlugin","___BasePlugin","ArrayPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","this","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","items","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","getValue","applyState","__exports","__esModule"],"sources":["ArrayPlugin.ts"],"sourcesContent":["/**\n * @file ArrayPlugin.ts\n * @description Renders a button that drills down into a nested table (array) via a recursive Dialog using v2 schema.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ArrayPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested array form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"array\",\n title: field.ui?.label || propKey,\n items: field.items || {\n type: \"object\",\n properties: {} // inference will handle it if empty\n }\n };\n\n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Records\" : \"Edit Records\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://list\",\n press: (oEvent: sap.ui.base.Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || []));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable // Pass the display mode down to the child Engine!\n });\n\n // Only attach submit event if we are not in display mode\n if (!!this.isEditable) {\n host.attachSubmit((e: sap.ui.base.Event) => {\n const payload = e.getParameter(\"payload\");\n parentModel.setProperty(updatePath, payload);\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Records: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n \n return this.control as Control;\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): unknown {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // dynamic state changes\n }\n}\n"],"mappings":"yEAAA,MAKSA,EAAUC,EAAA,cAMZ,MAAMC,UAAoBF,EAWtBG,OAAOC,EAA2BC,EAAsBC,EAAoB,OAAQC,EAAwBC,GAC/GC,KAAKD,SAAWA,EAChBC,KAAKC,SAAWN,EAChB,MAAMO,EAAUN,EAAYO,WAAW,KAAOP,EAAYQ,UAAU,GAAKR,EAEzE,MAAMS,EAAqB,CACvBC,KAAM,QACNC,MAAOZ,EAAMa,IAAIC,OAASP,EAC1BQ,MAAOf,EAAMe,OAAS,CAClBJ,KAAM,SACNK,WAAY,CAAC,IAIrB,GAAIhB,EAAMiB,SAAU,CAChBP,EAAUO,SAAWjB,EAAMiB,QAC/B,CAEAZ,KAAKa,QAAU,IAAIC,EAAO,CACtBC,GAAIf,KAAKgB,iBAAiBlB,EAAeF,GACzCqB,MAAOjB,KAAKkB,WAAa,eAAiB,eAC1CC,MAAOnB,KAAKkB,WAAa,qBAAuB,kBAChDE,MAAQC,IACJ,MAAMC,EAAMD,EAAOE,YACnB,MAAMC,EAAcF,EAAIG,SAAS5B,GACjC,IAAK2B,EAAa,OAElB,MAAME,EAAiBJ,EAAIK,kBAAkB9B,GAC7C,IAAI+B,EAAahC,EACjB,GAAI8B,IAAmB9B,EAAYO,WAAW,KAAM,CAChD,MAAM0B,EAAUH,EAAeI,UAC/BF,EAAaC,EAAQE,SAAS,KAAOF,EAAUjC,EAAeiC,IAAY,IAAM,IAAMjC,EAAciC,EAAU,IAAMjC,CACxH,CAGA,MAAMoC,EAAaC,KAAKC,MAAMD,KAAKE,UAAUX,EAAYY,YAAYR,IAAe,KAEpFS,IAAI7B,GAAG8B,QAAQ,CAAC,mDAAqDC,IACjE,MAAMC,EAAO,IAAID,EAAY,CACzBE,iBAAkBpC,EAClBqC,KAAMV,EACNW,SAAU3C,KAAKkB,aAInB,KAAMlB,KAAKkB,WAAY,CACnBsB,EAAKI,aAAcC,IACf,MAAMC,EAAUD,EAAEE,aAAa,WAC/BvB,EAAYwB,YAAYpB,EAAYkB,
|
|
1
|
+
{"version":3,"file":"ArrayPlugin.js","names":["BasePlugin","___BasePlugin","ArrayPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","this","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","items","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","getValue","applyState","__exports","__esModule"],"sources":["ArrayPlugin.ts"],"sourcesContent":["/**\n * @file ArrayPlugin.ts\n * @description Renders a button that drills down into a nested table (array) via a recursive Dialog using v2 schema.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ArrayPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested array form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"array\",\n title: field.ui?.label || propKey,\n items: field.items || {\n type: \"object\",\n properties: {} // inference will handle it if empty\n }\n };\n\n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Records\" : \"Edit Records\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://list\",\n press: (oEvent: sap.ui.base.Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || []));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable // Pass the display mode down to the child Engine!\n });\n\n // Only attach submit event if we are not in display mode\n if (!!this.isEditable) {\n host.attachSubmit((e: sap.ui.base.Event) => {\n const payload = e.getParameter(\"payload\");\n parentModel.setProperty(updatePath, payload);\n\n // CRITICAL: Notify the parent Engine that this field mutated\n // so it can trigger LiveUpdate syncs and validate!\n if (this.onChange) {\n this.onChange(true, propKey);\n }\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Records: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n \n return this.control as Control;\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): unknown {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // dynamic state changes\n }\n}\n"],"mappings":"yEAAA,MAKSA,EAAUC,EAAA,cAMZ,MAAMC,UAAoBF,EAWtBG,OAAOC,EAA2BC,EAAsBC,EAAoB,OAAQC,EAAwBC,GAC/GC,KAAKD,SAAWA,EAChBC,KAAKC,SAAWN,EAChB,MAAMO,EAAUN,EAAYO,WAAW,KAAOP,EAAYQ,UAAU,GAAKR,EAEzE,MAAMS,EAAqB,CACvBC,KAAM,QACNC,MAAOZ,EAAMa,IAAIC,OAASP,EAC1BQ,MAAOf,EAAMe,OAAS,CAClBJ,KAAM,SACNK,WAAY,CAAC,IAIrB,GAAIhB,EAAMiB,SAAU,CAChBP,EAAUO,SAAWjB,EAAMiB,QAC/B,CAEAZ,KAAKa,QAAU,IAAIC,EAAO,CACtBC,GAAIf,KAAKgB,iBAAiBlB,EAAeF,GACzCqB,MAAOjB,KAAKkB,WAAa,eAAiB,eAC1CC,MAAOnB,KAAKkB,WAAa,qBAAuB,kBAChDE,MAAQC,IACJ,MAAMC,EAAMD,EAAOE,YACnB,MAAMC,EAAcF,EAAIG,SAAS5B,GACjC,IAAK2B,EAAa,OAElB,MAAME,EAAiBJ,EAAIK,kBAAkB9B,GAC7C,IAAI+B,EAAahC,EACjB,GAAI8B,IAAmB9B,EAAYO,WAAW,KAAM,CAChD,MAAM0B,EAAUH,EAAeI,UAC/BF,EAAaC,EAAQE,SAAS,KAAOF,EAAUjC,EAAeiC,IAAY,IAAM,IAAMjC,EAAciC,EAAU,IAAMjC,CACxH,CAGA,MAAMoC,EAAaC,KAAKC,MAAMD,KAAKE,UAAUX,EAAYY,YAAYR,IAAe,KAEpFS,IAAI7B,GAAG8B,QAAQ,CAAC,mDAAqDC,IACjE,MAAMC,EAAO,IAAID,EAAY,CACzBE,iBAAkBpC,EAClBqC,KAAMV,EACNW,SAAU3C,KAAKkB,aAInB,KAAMlB,KAAKkB,WAAY,CACnBsB,EAAKI,aAAcC,IACf,MAAMC,EAAUD,EAAEE,aAAa,WAC/BvB,EAAYwB,YAAYpB,EAAYkB,GAIpC,GAAI9C,KAAKD,SAAU,CACfC,KAAKD,SAAS,KAAMG,EACxB,GAER,CAEA,MAAM+C,EAAatD,EAAMa,IAAI0C,oBAAsBlD,KAAKkB,WAAa,QAAU,MAC/EsB,EAAKW,aAAa,mBAAmBxD,EAAMa,IAAIC,OAASP,IAAW+C,QAK/E,OAAOjD,KAAKa,OAChB,CAKUuC,WACN,OAAO,IACX,CAKUC,aACN,EAEP,IAAAC,EAAA,CAAAC,WAAA,MAAAD,EAAA7D,cAAA,OAAA6D,CAAA","ignoreList":[]}
|
|
@@ -69,6 +69,12 @@ export class ArrayPlugin extends BasePlugin {
|
|
|
69
69
|
host.attachSubmit((e: sap.ui.base.Event) => {
|
|
70
70
|
const payload = e.getParameter("payload");
|
|
71
71
|
parentModel.setProperty(updatePath, payload);
|
|
72
|
+
|
|
73
|
+
// CRITICAL: Notify the parent Engine that this field mutated
|
|
74
|
+
// so it can trigger LiveUpdate syncs and validate!
|
|
75
|
+
if (this.onChange) {
|
|
76
|
+
this.onChange(true, propKey);
|
|
77
|
+
}
|
|
72
78
|
});
|
|
73
79
|
}
|
|
74
80
|
|
|
@@ -135,8 +135,11 @@ sap.ui.define(["./BasePlugin", "sap/ui/codeeditor/CodeEditor"], function (___Bas
|
|
|
135
135
|
*/
|
|
136
136
|
applyState() {
|
|
137
137
|
if (this.control && this.metadata) {
|
|
138
|
-
if (!this.isEditable)
|
|
139
|
-
|
|
138
|
+
if (!this.isEditable) {
|
|
139
|
+
this.control.setEditable(false);
|
|
140
|
+
} else {
|
|
141
|
+
this.control.setEditable(!this.metadata.ui?.readOnly);
|
|
142
|
+
}
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
145
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeEditorPlugin-dbg.js","names":["BasePlugin","___BasePlugin","CodeEditorPlugin","detectLanguage","value","trimmed","trim","startsWith","JSON","parse","e","test","adjustHeight","control","val","getValue","lines","split","length","newHeight","Math","max","setHeight","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","metadata","fieldKey","replace","CodeEditor","id","generateStableId","type","ui","args","editable","isEditable","readOnly","height","width","change","result","validate","isValid","currentVal","detectedType","getType","setType","attachEventOnce","oBinding","getBinding","initLogic","attachChange","applyCommonDirectives","applyState","setEditable","__exports","__esModule"],"sources":["CodeEditorPlugin.ts"],"sourcesContent":["/**\n * @file CodeEditorPlugin.ts\n * @description Renders a sap.ui.codeeditor.CodeEditor for editing source code/JSON.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport CodeEditor from \"sap/ui/codeeditor/CodeEditor\";\n\n/**\n * Handles rendering logic for code editing.\n * Requires the `sap.ui.codeeditor` library to be loaded.\n * \n * @namespace nz.co.siliconst.ui5.metaui.plugins.controls\n * @public\n */\nexport class CodeEditorPlugin extends BasePlugin {\n /**\n * Infers the language type from the content.\n * @param value The raw string.\n * @returns The language string.\n */\n private detectLanguage(value: string): string {\n if (!value || typeof value !== \"string\") return \"javascript\";\n \n const trimmed = value.trim();\n if (trimmed === \"\") return \"javascript\";\n\n // 1. JSON\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n JSON.parse(trimmed);\n return \"json\";\n } catch (e) {\n // Not valid JSON, continue testing\n }\n }\n\n // 2. XML / HTML\n if (/^\\s*<[\\s\\S]*>\\s*$/.test(trimmed)) {\n return \"xml\";\n }\n\n // 3. Fallback to JavaScript\n return \"javascript\";\n }\n\n /**\n * Dynamically adjusts the height of the editor based on content lines.\n */\n private adjustHeight(): void {\n if (!this.control) return;\n const val = (this.control as CodeEditor).getValue() || \"\";\n const lines = val.split(/\\r\\n|\\r|\\n/).length;\n // 18px per line + 20px padding, minimum 100px\n const newHeight = Math.max(100, (lines * 18) + 20);\n (this.control as CodeEditor).setHeight(newHeight + \"px\");\n }\n\n /**\n * Renders a `sap.ui.codeeditor.CodeEditor` component.\n * \n * @param fieldMetadata The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured CodeEditor control.\n */\n public render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = fieldMetadata;\n this.fieldKey = bindingPath.replace(\"/\", \"\"); // For EventBus\n \n \n \n this.control = new CodeEditor({\n id: this.generateStableId(engineScopeId, bindingPath),\n value: `{${modelName}>${bindingPath}}`,\n type: fieldMetadata.ui?.args || \"javascript\", // will be dynamically overridden if args is missing\n editable: !this.isEditable ? false : !fieldMetadata.ui?.readOnly,\n height: \"100px\", // Initial minimum height\n width: \"100%\",\n change: () => {\n const result = this.validate();\n if (this.onChange) {\n this.onChange(result.isValid, this.fieldKey);\n }\n \n // If language isn't explicitly defined, try to guess it dynamically\n if (!fieldMetadata.ui?.args) {\n const currentVal = (this.control as CodeEditor).getValue();\n const detectedType = this.detectLanguage(currentVal);\n if ((this.control as CodeEditor).getType() !== detectedType) {\n (this.control as CodeEditor).setType(detectedType);\n }\n }\n \n this.adjustHeight();\n }\n });\n\n // Clean architecture: Wait for the model context, then attach safely to the binding itself.\n // No timeouts, no DOM hacks, pure UI5 Eventing.\n (this.control as CodeEditor).attachEventOnce(\"modelContextChange\", () => {\n const oBinding = (this.control as CodeEditor).getBinding(\"value\");\n \n const initLogic = () => {\n if (this.control) {\n const currentVal = (this.control as CodeEditor).getValue();\n if (!fieldMetadata.ui?.args) {\n (this.control as CodeEditor).setType(this.detectLanguage(currentVal));\n }\n this.adjustHeight();\n }\n };\n\n if (oBinding) {\n // Attach for future model changes\n oBinding.attachChange(initLogic);\n }\n \n // Execute immediately in case the model is synchronous (JSONModel)\n initLogic();\n });\n\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n\n return this.control as Control;\n }\n\n /**\n * Retrieves the current code string.\n * @returns {unknown} The code value.\n */\n protected getValue(): unknown {\n return this.control ? (this.control as CodeEditor).getValue() : null;\n }\n\n /**\n * Applies dynamic read-only state.\n */\n protected applyState(): void {\n if (this.control && this.metadata) {\n if (!this.isEditable)
|
|
1
|
+
{"version":3,"file":"CodeEditorPlugin-dbg.js","names":["BasePlugin","___BasePlugin","CodeEditorPlugin","detectLanguage","value","trimmed","trim","startsWith","JSON","parse","e","test","adjustHeight","control","val","getValue","lines","split","length","newHeight","Math","max","setHeight","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","metadata","fieldKey","replace","CodeEditor","id","generateStableId","type","ui","args","editable","isEditable","readOnly","height","width","change","result","validate","isValid","currentVal","detectedType","getType","setType","attachEventOnce","oBinding","getBinding","initLogic","attachChange","applyCommonDirectives","applyState","setEditable","__exports","__esModule"],"sources":["CodeEditorPlugin.ts"],"sourcesContent":["/**\n * @file CodeEditorPlugin.ts\n * @description Renders a sap.ui.codeeditor.CodeEditor for editing source code/JSON.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport CodeEditor from \"sap/ui/codeeditor/CodeEditor\";\n\n/**\n * Handles rendering logic for code editing.\n * Requires the `sap.ui.codeeditor` library to be loaded.\n * \n * @namespace nz.co.siliconst.ui5.metaui.plugins.controls\n * @public\n */\nexport class CodeEditorPlugin extends BasePlugin {\n /**\n * Infers the language type from the content.\n * @param value The raw string.\n * @returns The language string.\n */\n private detectLanguage(value: string): string {\n if (!value || typeof value !== \"string\") return \"javascript\";\n \n const trimmed = value.trim();\n if (trimmed === \"\") return \"javascript\";\n\n // 1. JSON\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n JSON.parse(trimmed);\n return \"json\";\n } catch (e) {\n // Not valid JSON, continue testing\n }\n }\n\n // 2. XML / HTML\n if (/^\\s*<[\\s\\S]*>\\s*$/.test(trimmed)) {\n return \"xml\";\n }\n\n // 3. Fallback to JavaScript\n return \"javascript\";\n }\n\n /**\n * Dynamically adjusts the height of the editor based on content lines.\n */\n private adjustHeight(): void {\n if (!this.control) return;\n const val = (this.control as CodeEditor).getValue() || \"\";\n const lines = val.split(/\\r\\n|\\r|\\n/).length;\n // 18px per line + 20px padding, minimum 100px\n const newHeight = Math.max(100, (lines * 18) + 20);\n (this.control as CodeEditor).setHeight(newHeight + \"px\");\n }\n\n /**\n * Renders a `sap.ui.codeeditor.CodeEditor` component.\n * \n * @param fieldMetadata The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured CodeEditor control.\n */\n public render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = fieldMetadata;\n this.fieldKey = bindingPath.replace(\"/\", \"\"); // For EventBus\n \n \n \n this.control = new CodeEditor({\n id: this.generateStableId(engineScopeId, bindingPath),\n value: `{${modelName}>${bindingPath}}`,\n type: fieldMetadata.ui?.args || \"javascript\", // will be dynamically overridden if args is missing\n editable: !this.isEditable ? false : !fieldMetadata.ui?.readOnly,\n height: \"100px\", // Initial minimum height\n width: \"100%\",\n change: () => {\n const result = this.validate();\n if (this.onChange) {\n this.onChange(result.isValid, this.fieldKey);\n }\n \n // If language isn't explicitly defined, try to guess it dynamically\n if (!fieldMetadata.ui?.args) {\n const currentVal = (this.control as CodeEditor).getValue();\n const detectedType = this.detectLanguage(currentVal);\n if ((this.control as CodeEditor).getType() !== detectedType) {\n (this.control as CodeEditor).setType(detectedType);\n }\n }\n \n this.adjustHeight();\n }\n });\n\n // Clean architecture: Wait for the model context, then attach safely to the binding itself.\n // No timeouts, no DOM hacks, pure UI5 Eventing.\n (this.control as CodeEditor).attachEventOnce(\"modelContextChange\", () => {\n const oBinding = (this.control as CodeEditor).getBinding(\"value\");\n \n const initLogic = () => {\n if (this.control) {\n const currentVal = (this.control as CodeEditor).getValue();\n if (!fieldMetadata.ui?.args) {\n (this.control as CodeEditor).setType(this.detectLanguage(currentVal));\n }\n this.adjustHeight();\n }\n };\n\n if (oBinding) {\n // Attach for future model changes\n oBinding.attachChange(initLogic);\n }\n \n // Execute immediately in case the model is synchronous (JSONModel)\n initLogic();\n });\n\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n\n return this.control as Control;\n }\n\n /**\n * Retrieves the current code string.\n * @returns {unknown} The code value.\n */\n protected getValue(): unknown {\n return this.control ? (this.control as CodeEditor).getValue() : null;\n }\n\n /**\n * Applies dynamic read-only state.\n */\n protected applyState(): void {\n if (this.control && this.metadata) {\n if (!this.isEditable) {\n (this.control as CodeEditor).setEditable(false);\n } else {\n (this.control as CodeEditor).setEditable(!this.metadata.ui?.readOnly);\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeEditorPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,8DAA8D,CAAC;IAC9E;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAClF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAG1C;;;;;;OAMG;IACH,MAAa,gBAAiB,SAAQ,UAAU;QAC5C;;;;WAIG;QACH,OAAO,CAAC,cAAc;QAyBtB;;WAEG;QACH,OAAO,CAAC,YAAY;QASpB;;;;;;;;;WASG;QACI,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QA8D3L;;;WAGG;QACH,SAAS,CAAC,QAAQ,IAAI,OAAO;QAI7B;;WAEG;QACH,SAAS,CAAC,UAAU,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"CodeEditorPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/CodeEditorPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,8DAA8D,CAAC;IAC9E;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAClF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAG1C;;;;;;OAMG;IACH,MAAa,gBAAiB,SAAQ,UAAU;QAC5C;;;;WAIG;QACH,OAAO,CAAC,cAAc;QAyBtB;;WAEG;QACH,OAAO,CAAC,YAAY;QASpB;;;;;;;;;WASG;QACI,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QA8D3L;;;WAGG;QACH,SAAS,CAAC,QAAQ,IAAI,OAAO;QAI7B;;WAEG;QACH,SAAS,CAAC,UAAU,IAAI,IAAI;KAS/B;CAEA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
sap.ui.define(["./BasePlugin","sap/ui/codeeditor/CodeEditor"],function(t,e){"use strict";const i=t["BasePlugin"];class s extends i{detectLanguage(t){if(!t||typeof t!=="string")return"javascript";const e=t.trim();if(e==="")return"javascript";if(e.startsWith("{")||e.startsWith("[")){try{JSON.parse(e);return"json"}catch(t){}}if(/^\s*<[\s\S]*>\s*$/.test(e)){return"xml"}return"javascript"}adjustHeight(){if(!this.control)return;const t=this.control.getValue()||"";const e=t.split(/\r\n|\r|\n/).length;const i=Math.max(100,e*18+20);this.control.setHeight(i+"px")}render(t,i,s="meta",a,n){this.onChange=n;this.metadata=t;this.fieldKey=i.replace("/","");this.control=new e({id:this.generateStableId(a,i),value:`{${s}>${i}}`,type:t.ui?.args||"javascript",editable:!this.isEditable?false:!t.ui?.readOnly,height:"100px",width:"100%",change:()=>{const e=this.validate();if(this.onChange){this.onChange(e.isValid,this.fieldKey)}if(!t.ui?.args){const t=this.control.getValue();const e=this.detectLanguage(t);if(this.control.getType()!==e){this.control.setType(e)}}this.adjustHeight()}});this.control.attachEventOnce("modelContextChange",()=>{const e=this.control.getBinding("value");const i=()=>{if(this.control){const e=this.control.getValue();if(!t.ui?.args){this.control.setType(this.detectLanguage(e))}this.adjustHeight()}};if(e){e.attachChange(i)}i()});this.applyCommonDirectives(this.control,t,s);return this.control}getValue(){return this.control?this.control.getValue():null}applyState(){if(this.control&&this.metadata){if(!this.isEditable)
|
|
1
|
+
sap.ui.define(["./BasePlugin","sap/ui/codeeditor/CodeEditor"],function(t,e){"use strict";const i=t["BasePlugin"];class s extends i{detectLanguage(t){if(!t||typeof t!=="string")return"javascript";const e=t.trim();if(e==="")return"javascript";if(e.startsWith("{")||e.startsWith("[")){try{JSON.parse(e);return"json"}catch(t){}}if(/^\s*<[\s\S]*>\s*$/.test(e)){return"xml"}return"javascript"}adjustHeight(){if(!this.control)return;const t=this.control.getValue()||"";const e=t.split(/\r\n|\r|\n/).length;const i=Math.max(100,e*18+20);this.control.setHeight(i+"px")}render(t,i,s="meta",a,n){this.onChange=n;this.metadata=t;this.fieldKey=i.replace("/","");this.control=new e({id:this.generateStableId(a,i),value:`{${s}>${i}}`,type:t.ui?.args||"javascript",editable:!this.isEditable?false:!t.ui?.readOnly,height:"100px",width:"100%",change:()=>{const e=this.validate();if(this.onChange){this.onChange(e.isValid,this.fieldKey)}if(!t.ui?.args){const t=this.control.getValue();const e=this.detectLanguage(t);if(this.control.getType()!==e){this.control.setType(e)}}this.adjustHeight()}});this.control.attachEventOnce("modelContextChange",()=>{const e=this.control.getBinding("value");const i=()=>{if(this.control){const e=this.control.getValue();if(!t.ui?.args){this.control.setType(this.detectLanguage(e))}this.adjustHeight()}};if(e){e.attachChange(i)}i()});this.applyCommonDirectives(this.control,t,s);return this.control}getValue(){return this.control?this.control.getValue():null}applyState(){if(this.control&&this.metadata){if(!this.isEditable){this.control.setEditable(false)}else{this.control.setEditable(!this.metadata.ui?.readOnly)}}}}var a={__esModule:true};a.CodeEditorPlugin=s;return a});
|
|
2
2
|
//# sourceMappingURL=CodeEditorPlugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeEditorPlugin.js","names":["BasePlugin","___BasePlugin","CodeEditorPlugin","detectLanguage","value","trimmed","trim","startsWith","JSON","parse","e","test","adjustHeight","this","control","val","getValue","lines","split","length","newHeight","Math","max","setHeight","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","metadata","fieldKey","replace","CodeEditor","id","generateStableId","type","ui","args","editable","isEditable","readOnly","height","width","change","result","validate","isValid","currentVal","detectedType","getType","setType","attachEventOnce","oBinding","getBinding","initLogic","attachChange","applyCommonDirectives","applyState","setEditable","__exports","__esModule"],"sources":["CodeEditorPlugin.ts"],"sourcesContent":["/**\n * @file CodeEditorPlugin.ts\n * @description Renders a sap.ui.codeeditor.CodeEditor for editing source code/JSON.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport CodeEditor from \"sap/ui/codeeditor/CodeEditor\";\n\n/**\n * Handles rendering logic for code editing.\n * Requires the `sap.ui.codeeditor` library to be loaded.\n * \n * @namespace nz.co.siliconst.ui5.metaui.plugins.controls\n * @public\n */\nexport class CodeEditorPlugin extends BasePlugin {\n /**\n * Infers the language type from the content.\n * @param value The raw string.\n * @returns The language string.\n */\n private detectLanguage(value: string): string {\n if (!value || typeof value !== \"string\") return \"javascript\";\n \n const trimmed = value.trim();\n if (trimmed === \"\") return \"javascript\";\n\n // 1. JSON\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n JSON.parse(trimmed);\n return \"json\";\n } catch (e) {\n // Not valid JSON, continue testing\n }\n }\n\n // 2. XML / HTML\n if (/^\\s*<[\\s\\S]*>\\s*$/.test(trimmed)) {\n return \"xml\";\n }\n\n // 3. Fallback to JavaScript\n return \"javascript\";\n }\n\n /**\n * Dynamically adjusts the height of the editor based on content lines.\n */\n private adjustHeight(): void {\n if (!this.control) return;\n const val = (this.control as CodeEditor).getValue() || \"\";\n const lines = val.split(/\\r\\n|\\r|\\n/).length;\n // 18px per line + 20px padding, minimum 100px\n const newHeight = Math.max(100, (lines * 18) + 20);\n (this.control as CodeEditor).setHeight(newHeight + \"px\");\n }\n\n /**\n * Renders a `sap.ui.codeeditor.CodeEditor` component.\n * \n * @param fieldMetadata The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured CodeEditor control.\n */\n public render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = fieldMetadata;\n this.fieldKey = bindingPath.replace(\"/\", \"\"); // For EventBus\n \n \n \n this.control = new CodeEditor({\n id: this.generateStableId(engineScopeId, bindingPath),\n value: `{${modelName}>${bindingPath}}`,\n type: fieldMetadata.ui?.args || \"javascript\", // will be dynamically overridden if args is missing\n editable: !this.isEditable ? false : !fieldMetadata.ui?.readOnly,\n height: \"100px\", // Initial minimum height\n width: \"100%\",\n change: () => {\n const result = this.validate();\n if (this.onChange) {\n this.onChange(result.isValid, this.fieldKey);\n }\n \n // If language isn't explicitly defined, try to guess it dynamically\n if (!fieldMetadata.ui?.args) {\n const currentVal = (this.control as CodeEditor).getValue();\n const detectedType = this.detectLanguage(currentVal);\n if ((this.control as CodeEditor).getType() !== detectedType) {\n (this.control as CodeEditor).setType(detectedType);\n }\n }\n \n this.adjustHeight();\n }\n });\n\n // Clean architecture: Wait for the model context, then attach safely to the binding itself.\n // No timeouts, no DOM hacks, pure UI5 Eventing.\n (this.control as CodeEditor).attachEventOnce(\"modelContextChange\", () => {\n const oBinding = (this.control as CodeEditor).getBinding(\"value\");\n \n const initLogic = () => {\n if (this.control) {\n const currentVal = (this.control as CodeEditor).getValue();\n if (!fieldMetadata.ui?.args) {\n (this.control as CodeEditor).setType(this.detectLanguage(currentVal));\n }\n this.adjustHeight();\n }\n };\n\n if (oBinding) {\n // Attach for future model changes\n oBinding.attachChange(initLogic);\n }\n \n // Execute immediately in case the model is synchronous (JSONModel)\n initLogic();\n });\n\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n\n return this.control as Control;\n }\n\n /**\n * Retrieves the current code string.\n * @returns {unknown} The code value.\n */\n protected getValue(): unknown {\n return this.control ? (this.control as CodeEditor).getValue() : null;\n }\n\n /**\n * Applies dynamic read-only state.\n */\n protected applyState(): void {\n if (this.control && this.metadata) {\n if (!this.isEditable)
|
|
1
|
+
{"version":3,"file":"CodeEditorPlugin.js","names":["BasePlugin","___BasePlugin","CodeEditorPlugin","detectLanguage","value","trimmed","trim","startsWith","JSON","parse","e","test","adjustHeight","this","control","val","getValue","lines","split","length","newHeight","Math","max","setHeight","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","metadata","fieldKey","replace","CodeEditor","id","generateStableId","type","ui","args","editable","isEditable","readOnly","height","width","change","result","validate","isValid","currentVal","detectedType","getType","setType","attachEventOnce","oBinding","getBinding","initLogic","attachChange","applyCommonDirectives","applyState","setEditable","__exports","__esModule"],"sources":["CodeEditorPlugin.ts"],"sourcesContent":["/**\n * @file CodeEditorPlugin.ts\n * @description Renders a sap.ui.codeeditor.CodeEditor for editing source code/JSON.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport CodeEditor from \"sap/ui/codeeditor/CodeEditor\";\n\n/**\n * Handles rendering logic for code editing.\n * Requires the `sap.ui.codeeditor` library to be loaded.\n * \n * @namespace nz.co.siliconst.ui5.metaui.plugins.controls\n * @public\n */\nexport class CodeEditorPlugin extends BasePlugin {\n /**\n * Infers the language type from the content.\n * @param value The raw string.\n * @returns The language string.\n */\n private detectLanguage(value: string): string {\n if (!value || typeof value !== \"string\") return \"javascript\";\n \n const trimmed = value.trim();\n if (trimmed === \"\") return \"javascript\";\n\n // 1. JSON\n if (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n try {\n JSON.parse(trimmed);\n return \"json\";\n } catch (e) {\n // Not valid JSON, continue testing\n }\n }\n\n // 2. XML / HTML\n if (/^\\s*<[\\s\\S]*>\\s*$/.test(trimmed)) {\n return \"xml\";\n }\n\n // 3. Fallback to JavaScript\n return \"javascript\";\n }\n\n /**\n * Dynamically adjusts the height of the editor based on content lines.\n */\n private adjustHeight(): void {\n if (!this.control) return;\n const val = (this.control as CodeEditor).getValue() || \"\";\n const lines = val.split(/\\r\\n|\\r|\\n/).length;\n // 18px per line + 20px padding, minimum 100px\n const newHeight = Math.max(100, (lines * 18) + 20);\n (this.control as CodeEditor).setHeight(newHeight + \"px\");\n }\n\n /**\n * Renders a `sap.ui.codeeditor.CodeEditor` component.\n * \n * @param fieldMetadata The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured CodeEditor control.\n */\n public render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = fieldMetadata;\n this.fieldKey = bindingPath.replace(\"/\", \"\"); // For EventBus\n \n \n \n this.control = new CodeEditor({\n id: this.generateStableId(engineScopeId, bindingPath),\n value: `{${modelName}>${bindingPath}}`,\n type: fieldMetadata.ui?.args || \"javascript\", // will be dynamically overridden if args is missing\n editable: !this.isEditable ? false : !fieldMetadata.ui?.readOnly,\n height: \"100px\", // Initial minimum height\n width: \"100%\",\n change: () => {\n const result = this.validate();\n if (this.onChange) {\n this.onChange(result.isValid, this.fieldKey);\n }\n \n // If language isn't explicitly defined, try to guess it dynamically\n if (!fieldMetadata.ui?.args) {\n const currentVal = (this.control as CodeEditor).getValue();\n const detectedType = this.detectLanguage(currentVal);\n if ((this.control as CodeEditor).getType() !== detectedType) {\n (this.control as CodeEditor).setType(detectedType);\n }\n }\n \n this.adjustHeight();\n }\n });\n\n // Clean architecture: Wait for the model context, then attach safely to the binding itself.\n // No timeouts, no DOM hacks, pure UI5 Eventing.\n (this.control as CodeEditor).attachEventOnce(\"modelContextChange\", () => {\n const oBinding = (this.control as CodeEditor).getBinding(\"value\");\n \n const initLogic = () => {\n if (this.control) {\n const currentVal = (this.control as CodeEditor).getValue();\n if (!fieldMetadata.ui?.args) {\n (this.control as CodeEditor).setType(this.detectLanguage(currentVal));\n }\n this.adjustHeight();\n }\n };\n\n if (oBinding) {\n // Attach for future model changes\n oBinding.attachChange(initLogic);\n }\n \n // Execute immediately in case the model is synchronous (JSONModel)\n initLogic();\n });\n\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n\n return this.control as Control;\n }\n\n /**\n * Retrieves the current code string.\n * @returns {unknown} The code value.\n */\n protected getValue(): unknown {\n return this.control ? (this.control as CodeEditor).getValue() : null;\n }\n\n /**\n * Applies dynamic read-only state.\n */\n protected applyState(): void {\n if (this.control && this.metadata) {\n if (!this.isEditable) {\n (this.control as CodeEditor).setEditable(false);\n } else {\n (this.control as CodeEditor).setEditable(!this.metadata.ui?.readOnly);\n }\n }\n }\n}\n"],"mappings":"yFAAA,MAKSA,EAAUC,EAAA,cAYZ,MAAMC,UAAyBF,EAM1BG,eAAeC,GACnB,IAAKA,UAAgBA,IAAU,SAAU,MAAO,aAEhD,MAAMC,EAAUD,EAAME,OACtB,GAAID,IAAY,GAAI,MAAO,aAG3B,GAAIA,EAAQE,WAAW,MAAQF,EAAQE,WAAW,KAAM,CACpD,IACIC,KAAKC,MAAMJ,GACX,MAAO,MACX,CAAE,MAAOK,GACL,CAER,CAGA,GAAI,oBAAoBC,KAAKN,GAAU,CACnC,MAAO,KACX,CAGA,MAAO,YACX,CAKQO,eACJ,IAAKC,KAAKC,QAAS,OACnB,MAAMC,EAAOF,KAAKC,QAAuBE,YAAc,GACvD,MAAMC,EAAQF,EAAIG,MAAM,cAAcC,OAEtC,MAAMC,EAAYC,KAAKC,IAAI,IAAML,EAAQ,GAAM,IAC9CJ,KAAKC,QAAuBS,UAAUH,EAAY,KACvD,CAYOI,OAAOC,EAAkCC,EAAqBC,EAAoB,OAAQC,EAAwBC,GACrHhB,KAAKgB,SAAWA,EAChBhB,KAAKiB,SAAWL,EAChBZ,KAAKkB,SAAWL,EAAYM,QAAQ,IAAK,IAIzCnB,KAAKC,QAAU,IAAImB,EAAW,CAC1BC,GAAIrB,KAAKsB,iBAAiBP,EAAeF,GACzCtB,MAAO,IAAIuB,KAAaD,KACxBU,KAAMX,EAAcY,IAAIC,MAAQ,aAChCC,UAAW1B,KAAK2B,WAAa,OAASf,EAAcY,IAAII,SACxDC,OAAQ,QACRC,MAAO,OACPC,OAAQA,KACJ,MAAMC,EAAShC,KAAKiC,WACpB,GAAIjC,KAAKgB,SAAU,CACfhB,KAAKgB,SAASgB,EAAOE,QAASlC,KAAKkB,SACvC,CAGA,IAAKN,EAAcY,IAAIC,KAAM,CACzB,MAAMU,EAAcnC,KAAKC,QAAuBE,WAChD,MAAMiC,EAAepC,KAAKV,eAAe6C,GACzC,GAAKnC,KAAKC,QAAuBoC,YAAcD,EAAc,CACxDpC,KAAKC,QAAuBqC,QAAQF,EACzC,CACJ,CAEApC,KAAKD,kBAMZC,KAAKC,QAAuBsC,gBAAgB,qBAAsB,KAC/D,MAAMC,EAAYxC,KAAKC,QAAuBwC,WAAW,SAEzD,MAAMC,EAAYA,KACd,GAAI1C,KAAKC,QAAS,CACd,MAAMkC,EAAcnC,KAAKC,QAAuBE,WAChD,IAAKS,EAAcY,IAAIC,KAAM,CACxBzB,KAAKC,QAAuBqC,QAAQtC,KAAKV,eAAe6C,GAC7D,CACAnC,KAAKD,cACT,GAGJ,GAAIyC,EAAU,CAEVA,EAASG,aAAaD,EAC1B,CAGAA,MAGJ1C,KAAK4C,sBAAsB5C,KAAKC,QAASW,EAAeE,GAExD,OAAOd,KAAKC,OAChB,CAMUE,WACN,OAAOH,KAAKC,QAAWD,KAAKC,QAAuBE,WAAa,IACpE,CAKU0C,aACN,GAAI7C,KAAKC,SAAWD,KAAKiB,SAAU,CAC/B,IAAKjB,KAAK2B,WAAY,CACjB3B,KAAKC,QAAuB6C,YAAY,MAC7C,KAAO,CACF9C,KAAKC,QAAuB6C,aAAa9C,KAAKiB,SAASO,IAAII,SAChE,CACJ,CACJ,EACH,IAAAmB,EAAA,CAAAC,WAAA,MAAAD,EAAA1D,mBAAA,OAAA0D,CAAA","ignoreList":[]}
|
|
@@ -143,8 +143,11 @@ export class CodeEditorPlugin extends BasePlugin {
|
|
|
143
143
|
*/
|
|
144
144
|
protected applyState(): void {
|
|
145
145
|
if (this.control && this.metadata) {
|
|
146
|
-
if (!this.isEditable)
|
|
147
|
-
|
|
146
|
+
if (!this.isEditable) {
|
|
147
|
+
(this.control as CodeEditor).setEditable(false);
|
|
148
|
+
} else {
|
|
149
|
+
(this.control as CodeEditor).setEditable(!this.metadata.ui?.readOnly);
|
|
150
|
+
}
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
}
|
|
@@ -56,6 +56,12 @@ sap.ui.define(["./BasePlugin", "sap/m/Button"], function (___BasePlugin, Button)
|
|
|
56
56
|
host.attachSubmit(e => {
|
|
57
57
|
const payload = e.getParameter("payload");
|
|
58
58
|
parentModel.setProperty(updatePath, payload);
|
|
59
|
+
|
|
60
|
+
// CRITICAL: Notify the parent Engine that this field mutated
|
|
61
|
+
// so it can trigger LiveUpdate syncs and validate!
|
|
62
|
+
if (this.onChange) {
|
|
63
|
+
this.onChange(true, propKey);
|
|
64
|
+
}
|
|
59
65
|
});
|
|
60
66
|
}
|
|
61
67
|
const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? "Close" : "OK");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectPlugin-dbg.js","names":["BasePlugin","___BasePlugin","ObjectPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","validate","isValid","getValue","applyState","__exports","__esModule"],"sources":["ObjectPlugin.ts"],"sourcesContent":["/**\n * @file ObjectPlugin.ts\n * @description Renders a button that opens a dialog to edit a nested object structure.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPluginValidationResult } from \"../../interfaces/IPlugin\";\nimport { ISchema, IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Event from \"sap/ui/base/Event\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ObjectPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested Object form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"object\",\n title: field.ui?.label || propKey,\n properties: field.properties || {}\n };\n \n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Details\" : \"Edit Details\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://form\",\n press: (oEvent: Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || {}));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable\n });\n\n if (!!this.isEditable) {\n host.attachSubmit((e: Event) => {\n const payload = (e.getParameter(\"payload\") as unknown);\n parentModel.setProperty(updatePath, payload);\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Details: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n\n return this.control as Control;\n }\n\n /**\n * Validates the object plugin (always true as validation is deferred to the dialog host).\n * @returns {IPluginValidationResult} The validation result.\n */\n public validate(): IPluginValidationResult {\n return { isValid: true };\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): null {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // No dynamic state handling needed for the button\n }\n}\n"],"mappings":";;;EAAA;AACA;AACA;AACA;EAHA,MAKSA,UAAU,GAAAC,aAAA;EAQZ,MAAMC,YAAY,SAASF,UAAU,CAAC;IACzC;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IACWG,MAAMA,CAACC,KAAwB,EAAGC,WAAmB,EAAGC,SAAiB,GAAG,MAAM,EAAEC,aAAsB,EAAEC,QAAwD,EAAW;MAClL,IAAI,CAACA,QAAQ,GAAGA,QAAQ;MACxB,IAAI,CAACC,QAAQ,GAAGL,KAAK;MACrB,MAAMM,OAAO,GAAGL,WAAW,CAACM,UAAU,CAAC,GAAG,CAAC,GAAGN,WAAW,CAACO,SAAS,CAAC,CAAC,CAAC,GAAGP,WAAW;MAEpF,MAAMQ,SAAkB,GAAG;QACvBC,IAAI,EAAE,QAAQ;QACdC,KAAK,EAAEX,KAAK,CAACY,EAAE,EAAEC,KAAK,IAAIP,OAAO;QACjCQ,UAAU,EAAEd,KAAK,CAACc,UAAU,IAAI,CAAC;MACrC,CAAC;MAED,IAAId,KAAK,CAACe,QAAQ,EAAE;QAChBN,SAAS,CAACM,QAAQ,GAAGf,KAAK,CAACe,QAAQ;MACvC;MAEA,IAAI,CAACC,OAAO,GAAG,IAAIC,MAAM,CAAC;QACtBC,EAAE,EAAE,IAAI,CAACC,gBAAgB,CAAChB,aAAa,EAAEF,WAAW,CAAC;QACrDmB,IAAI,EAAE,CAAC,IAAI,CAACC,UAAU,GAAG,cAAc,GAAG,cAAc;QACxDC,IAAI,EAAE,CAAC,IAAI,CAACD,UAAU,GAAG,oBAAoB,GAAG,iBAAiB;QACjEE,KAAK,EAAGC,MAAa,IAAK;UACtB,MAAMC,GAAG,GAAGD,MAAM,CAACE,SAAS,CAAC,CAAW;UACxC,MAAMC,WAAW,GAAGF,GAAG,CAACG,QAAQ,CAAC1B,SAAS,CAAc;UACxD,IAAI,CAACyB,WAAW,EAAE;UAElB,MAAME,cAAc,GAAGJ,GAAG,CAACK,iBAAiB,CAAC5B,SAAS,CAAC;UACvD,IAAI6B,UAAU,GAAG9B,WAAW;UAC5B,IAAI4B,cAAc,IAAI,CAAC5B,WAAW,CAACM,UAAU,CAAC,GAAG,CAAC,EAAE;YAChD,MAAMyB,OAAO,GAAGH,cAAc,CAACI,OAAO,CAAC,CAAC;YACxCF,UAAU,GAAGC,OAAO,CAACE,QAAQ,CAAC,GAAG,CAAC,GAAGF,OAAO,GAAG/B,WAAW,GAAI+B,OAAO,KAAK,GAAG,GAAG,GAAG,GAAG/B,WAAW,GAAG+B,OAAO,GAAG,GAAG,GAAG/B,WAAY;UACpI;;UAEA;UACA,MAAMkC,UAAU,GAAGC,IAAI,CAACC,KAAK,CAACD,IAAI,CAACE,SAAS,CAACX,WAAW,CAACY,WAAW,CAACR,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;UAExFS,GAAG,CAAC5B,EAAE,CAAC6B,OAAO,CAAC,CAAC,iDAAiD,CAAC,EAAGC,WAAgE,IAAK;YACtI,MAAMC,IAAI,GAAG,IAAID,WAAW,CAAC;cACzBE,gBAAgB,EAAEnC,SAAS;cAC3BoC,IAAI,EAAEV,UAAU;cAChBW,QAAQ,EAAE,IAAI,CAACzB;YACnB,CAAC,CAAC;YAEF,IAAI,CAAC,CAAC,IAAI,CAACA,UAAU,EAAE;cACnBsB,IAAI,CAACI,YAAY,CAAEC,CAAQ,IAAK;gBAC5B,MAAMC,OAAO,GAAID,CAAC,CAACE,YAAY,CAAC,SAAS,CAAa;gBACtDvB,WAAW,CAACwB,WAAW,CAACpB,UAAU,EAAEkB,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ObjectPlugin-dbg.js","names":["BasePlugin","___BasePlugin","ObjectPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","validate","isValid","getValue","applyState","__exports","__esModule"],"sources":["ObjectPlugin.ts"],"sourcesContent":["/**\n * @file ObjectPlugin.ts\n * @description Renders a button that opens a dialog to edit a nested object structure.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPluginValidationResult } from \"../../interfaces/IPlugin\";\nimport { ISchema, IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Event from \"sap/ui/base/Event\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ObjectPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested Object form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"object\",\n title: field.ui?.label || propKey,\n properties: field.properties || {}\n };\n \n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Details\" : \"Edit Details\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://form\",\n press: (oEvent: Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || {}));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable\n });\n\n if (!!this.isEditable) {\n host.attachSubmit((e: Event) => {\n const payload = (e.getParameter(\"payload\") as unknown);\n parentModel.setProperty(updatePath, payload);\n \n // CRITICAL: Notify the parent Engine that this field mutated\n // so it can trigger LiveUpdate syncs and validate!\n if (this.onChange) {\n this.onChange(true, propKey);\n }\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Details: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n\n return this.control as Control;\n }\n\n /**\n * Validates the object plugin (always true as validation is deferred to the dialog host).\n * @returns {IPluginValidationResult} The validation result.\n */\n public validate(): IPluginValidationResult {\n return { isValid: true };\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): null {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // No dynamic state handling needed for the button\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,0DAA0D,CAAC;IAC1E;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;IACxF,OAAO,EAAW,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAC3F,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAK1C,MAAa,YAAa,SAAQ,UAAU;QACxC;;;;;;;;;WASG;QACI,MAAM,CAAC,KAAK,EAAE,iBAAiB,EAAG,WAAW,EAAE,MAAM,EAAG,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"ObjectPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/ObjectPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,0DAA0D,CAAC;IAC1E;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,+CAA+C,CAAC;IACxF,OAAO,EAAW,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAC3F,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAK1C,MAAa,YAAa,SAAQ,UAAU;QACxC;;;;;;;;;WASG;QACI,MAAM,CAAC,KAAK,EAAE,iBAAiB,EAAG,WAAW,EAAE,MAAM,EAAG,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QA+DrL;;;WAGG;QACI,QAAQ,IAAI,uBAAuB;QAI1C;;WAEG;QACH,SAAS,CAAC,QAAQ,IAAI,IAAI;QAI1B;;WAEG;QACH,SAAS,CAAC,UAAU,IAAI,IAAI;KAG/B;CAEA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
sap.ui.define(["./BasePlugin","sap/m/Button"],function(t,e){"use strict";const i=t["BasePlugin"];class s extends i{render(t,i,s="meta",a,n){this.onChange=n;this.metadata=t;const o=i.startsWith("/")?i.substring(1):i;const r={type:"object",title:t.ui?.label||o,properties:t.properties||{}};if(t.uiLayout){r.uiLayout=t.uiLayout}this.control=new e({id:this.generateStableId(a,i),text:!this.isEditable?"View Details":"Edit Details",icon:!this.isEditable?"sap-icon://display":"sap-icon://form",press:e=>{const a=e.getSource();const n=a.getModel(s);if(!n)return;const l=a.getBindingContext(s);let u=i;if(l&&!i.startsWith("/")){const t=l.getPath();u=t.endsWith("/")?t+i:t==="/"?"/"+i:t+"/"+i}const c=JSON.parse(JSON.stringify(n.getProperty(u)||{}));sap.ui.require(["nz/co/siliconst/ui5/metaui/controls/DynamicHost"],e=>{const i=new e({schemaDefinition:r,data:c,editable:this.isEditable});if(!!this.isEditable){i.attachSubmit(t=>{const e=t.getParameter("payload");n.setProperty(u,e)})}const s=t.ui?.dialogButtonText||(!this.isEditable?"Close":"OK");i.openInDialog(`Nested Details: ${t.ui?.label||o}`,s)})}});return this.control}validate(){return{isValid:true}}getValue(){return null}applyState(){}}var a={__esModule:true};a.ObjectPlugin=s;return a});
|
|
1
|
+
sap.ui.define(["./BasePlugin","sap/m/Button"],function(t,e){"use strict";const i=t["BasePlugin"];class s extends i{render(t,i,s="meta",a,n){this.onChange=n;this.metadata=t;const o=i.startsWith("/")?i.substring(1):i;const r={type:"object",title:t.ui?.label||o,properties:t.properties||{}};if(t.uiLayout){r.uiLayout=t.uiLayout}this.control=new e({id:this.generateStableId(a,i),text:!this.isEditable?"View Details":"Edit Details",icon:!this.isEditable?"sap-icon://display":"sap-icon://form",press:e=>{const a=e.getSource();const n=a.getModel(s);if(!n)return;const l=a.getBindingContext(s);let u=i;if(l&&!i.startsWith("/")){const t=l.getPath();u=t.endsWith("/")?t+i:t==="/"?"/"+i:t+"/"+i}const c=JSON.parse(JSON.stringify(n.getProperty(u)||{}));sap.ui.require(["nz/co/siliconst/ui5/metaui/controls/DynamicHost"],e=>{const i=new e({schemaDefinition:r,data:c,editable:this.isEditable});if(!!this.isEditable){i.attachSubmit(t=>{const e=t.getParameter("payload");n.setProperty(u,e);if(this.onChange){this.onChange(true,o)}})}const s=t.ui?.dialogButtonText||(!this.isEditable?"Close":"OK");i.openInDialog(`Nested Details: ${t.ui?.label||o}`,s)})}});return this.control}validate(){return{isValid:true}}getValue(){return null}applyState(){}}var a={__esModule:true};a.ObjectPlugin=s;return a});
|
|
2
2
|
//# sourceMappingURL=ObjectPlugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectPlugin.js","names":["BasePlugin","___BasePlugin","ObjectPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","this","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","validate","isValid","getValue","applyState","__exports","__esModule"],"sources":["ObjectPlugin.ts"],"sourcesContent":["/**\n * @file ObjectPlugin.ts\n * @description Renders a button that opens a dialog to edit a nested object structure.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPluginValidationResult } from \"../../interfaces/IPlugin\";\nimport { ISchema, IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Event from \"sap/ui/base/Event\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ObjectPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested Object form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"object\",\n title: field.ui?.label || propKey,\n properties: field.properties || {}\n };\n \n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Details\" : \"Edit Details\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://form\",\n press: (oEvent: Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || {}));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable\n });\n\n if (!!this.isEditable) {\n host.attachSubmit((e: Event) => {\n const payload = (e.getParameter(\"payload\") as unknown);\n parentModel.setProperty(updatePath, payload);\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Details: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n\n return this.control as Control;\n }\n\n /**\n * Validates the object plugin (always true as validation is deferred to the dialog host).\n * @returns {IPluginValidationResult} The validation result.\n */\n public validate(): IPluginValidationResult {\n return { isValid: true };\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): null {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // No dynamic state handling needed for the button\n }\n}\n"],"mappings":"yEAAA,MAKSA,EAAUC,EAAA,cAQZ,MAAMC,UAAqBF,EAWvBG,OAAOC,EAA2BC,EAAsBC,EAAoB,OAAQC,EAAwBC,GAC/GC,KAAKD,SAAWA,EAChBC,KAAKC,SAAWN,EAChB,MAAMO,EAAUN,EAAYO,WAAW,KAAOP,EAAYQ,UAAU,GAAKR,EAEzE,MAAMS,EAAqB,CACvBC,KAAM,SACNC,MAAOZ,EAAMa,IAAIC,OAASP,EAC1BQ,WAAYf,EAAMe,YAAc,CAAC,GAGrC,GAAIf,EAAMgB,SAAU,CAChBN,EAAUM,SAAWhB,EAAMgB,QAC/B,CAEAX,KAAKY,QAAU,IAAIC,EAAO,CACtBC,GAAId,KAAKe,iBAAiBjB,EAAeF,GACzCoB,MAAOhB,KAAKiB,WAAa,eAAiB,eAC1CC,MAAOlB,KAAKiB,WAAa,qBAAuB,kBAChDE,MAAQC,IACJ,MAAMC,EAAMD,EAAOE,YACnB,MAAMC,EAAcF,EAAIG,SAAS3B,GACjC,IAAK0B,EAAa,OAElB,MAAME,EAAiBJ,EAAIK,kBAAkB7B,GAC7C,IAAI8B,EAAa/B,EACjB,GAAI6B,IAAmB7B,EAAYO,WAAW,KAAM,CAChD,MAAMyB,EAAUH,EAAeI,UAC/BF,EAAaC,EAAQE,SAAS,KAAOF,EAAUhC,EAAegC,IAAY,IAAM,IAAMhC,EAAcgC,EAAU,IAAMhC,CACxH,CAGA,MAAMmC,EAAaC,KAAKC,MAAMD,KAAKE,UAAUX,EAAYY,YAAYR,IAAe,CAAC,IAErFS,IAAI5B,GAAG6B,QAAQ,CAAC,mDAAqDC,IACjE,MAAMC,EAAO,IAAID,EAAY,CACzBE,iBAAkBnC,EAClBoC,KAAMV,EACNW,SAAU1C,KAAKiB,aAGnB,KAAMjB,KAAKiB,WAAY,CACnBsB,EAAKI,aAAcC,IACf,MAAMC,EAAWD,EAAEE,aAAa,WAChCvB,EAAYwB,YAAYpB,EAAYkB,
|
|
1
|
+
{"version":3,"file":"ObjectPlugin.js","names":["BasePlugin","___BasePlugin","ObjectPlugin","render","field","bindingPath","modelName","engineScopeId","onChange","this","metadata","propKey","startsWith","substring","subSchema","type","title","ui","label","properties","uiLayout","control","Button","id","generateStableId","text","isEditable","icon","press","oEvent","btn","getSource","parentModel","getModel","bindingContext","getBindingContext","updatePath","ctxPath","getPath","endsWith","nestedData","JSON","parse","stringify","getProperty","sap","require","DynamicHost","host","schemaDefinition","data","editable","attachSubmit","e","payload","getParameter","setProperty","buttonText","dialogButtonText","openInDialog","validate","isValid","getValue","applyState","__exports","__esModule"],"sources":["ObjectPlugin.ts"],"sourcesContent":["/**\n * @file ObjectPlugin.ts\n * @description Renders a button that opens a dialog to edit a nested object structure.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPluginValidationResult } from \"../../interfaces/IPlugin\";\nimport { ISchema, IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport Control from \"sap/ui/core/Control\";\nimport Event from \"sap/ui/base/Event\";\nimport Button from \"sap/m/Button\";\nimport JSONModel from \"sap/ui/model/json/JSONModel\";\n\nexport class ObjectPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.Button` to open a nested Object form dialog.\n * \n * @param field The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured Button control.\n */\n public render(field: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = field;\n const propKey = bindingPath.startsWith(\"/\") ? bindingPath.substring(1) : bindingPath;\n \n const subSchema: ISchema = {\n type: \"object\",\n title: field.ui?.label || propKey,\n properties: field.properties || {}\n };\n \n if (field.uiLayout) {\n subSchema.uiLayout = field.uiLayout;\n }\n\n this.control = new Button({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: !this.isEditable ? \"View Details\" : \"Edit Details\",\n icon: !this.isEditable ? \"sap-icon://display\" : \"sap-icon://form\",\n press: (oEvent: Event) => {\n const btn = oEvent.getSource() as Button;\n const parentModel = btn.getModel(modelName) as JSONModel;\n if (!parentModel) return;\n \n const bindingContext = btn.getBindingContext(modelName);\n let updatePath = bindingPath;\n if (bindingContext && !bindingPath.startsWith(\"/\")) {\n const ctxPath = bindingContext.getPath();\n updatePath = ctxPath.endsWith(\"/\") ? ctxPath + bindingPath : (ctxPath === \"/\" ? \"/\" + bindingPath : ctxPath + \"/\" + bindingPath);\n }\n \n // Deep clone to prevent live-mutations on the parent model before 'Submit' is clicked\n const nestedData = JSON.parse(JSON.stringify(parentModel.getProperty(updatePath) || {}));\n\n sap.ui.require([\"nz/co/siliconst/ui5/metaui/controls/DynamicHost\"], (DynamicHost: typeof import(\"../../controls/DynamicHost\").default) => {\n const host = new DynamicHost({\n schemaDefinition: subSchema,\n data: nestedData,\n editable: this.isEditable\n });\n\n if (!!this.isEditable) {\n host.attachSubmit((e: Event) => {\n const payload = (e.getParameter(\"payload\") as unknown);\n parentModel.setProperty(updatePath, payload);\n \n // CRITICAL: Notify the parent Engine that this field mutated\n // so it can trigger LiveUpdate syncs and validate!\n if (this.onChange) {\n this.onChange(true, propKey);\n }\n });\n }\n\n const buttonText = field.ui?.dialogButtonText || (!this.isEditable ? \"Close\" : \"OK\");\n host.openInDialog(`Nested Details: ${field.ui?.label || propKey}`, buttonText);\n });\n }\n });\n\n return this.control as Control;\n }\n\n /**\n * Validates the object plugin (always true as validation is deferred to the dialog host).\n * @returns {IPluginValidationResult} The validation result.\n */\n public validate(): IPluginValidationResult {\n return { isValid: true };\n }\n\n /**\n * Read-only component for the engine, returns null.\n */\n protected getValue(): null {\n return null;\n }\n\n /**\n * Read-only component, no dynamic state handling needed for the button itself.\n */\n protected applyState(): void {\n // No dynamic state handling needed for the button\n }\n}\n"],"mappings":"yEAAA,MAKSA,EAAUC,EAAA,cAQZ,MAAMC,UAAqBF,EAWvBG,OAAOC,EAA2BC,EAAsBC,EAAoB,OAAQC,EAAwBC,GAC/GC,KAAKD,SAAWA,EAChBC,KAAKC,SAAWN,EAChB,MAAMO,EAAUN,EAAYO,WAAW,KAAOP,EAAYQ,UAAU,GAAKR,EAEzE,MAAMS,EAAqB,CACvBC,KAAM,SACNC,MAAOZ,EAAMa,IAAIC,OAASP,EAC1BQ,WAAYf,EAAMe,YAAc,CAAC,GAGrC,GAAIf,EAAMgB,SAAU,CAChBN,EAAUM,SAAWhB,EAAMgB,QAC/B,CAEAX,KAAKY,QAAU,IAAIC,EAAO,CACtBC,GAAId,KAAKe,iBAAiBjB,EAAeF,GACzCoB,MAAOhB,KAAKiB,WAAa,eAAiB,eAC1CC,MAAOlB,KAAKiB,WAAa,qBAAuB,kBAChDE,MAAQC,IACJ,MAAMC,EAAMD,EAAOE,YACnB,MAAMC,EAAcF,EAAIG,SAAS3B,GACjC,IAAK0B,EAAa,OAElB,MAAME,EAAiBJ,EAAIK,kBAAkB7B,GAC7C,IAAI8B,EAAa/B,EACjB,GAAI6B,IAAmB7B,EAAYO,WAAW,KAAM,CAChD,MAAMyB,EAAUH,EAAeI,UAC/BF,EAAaC,EAAQE,SAAS,KAAOF,EAAUhC,EAAegC,IAAY,IAAM,IAAMhC,EAAcgC,EAAU,IAAMhC,CACxH,CAGA,MAAMmC,EAAaC,KAAKC,MAAMD,KAAKE,UAAUX,EAAYY,YAAYR,IAAe,CAAC,IAErFS,IAAI5B,GAAG6B,QAAQ,CAAC,mDAAqDC,IACjE,MAAMC,EAAO,IAAID,EAAY,CACzBE,iBAAkBnC,EAClBoC,KAAMV,EACNW,SAAU1C,KAAKiB,aAGnB,KAAMjB,KAAKiB,WAAY,CACnBsB,EAAKI,aAAcC,IACf,MAAMC,EAAWD,EAAEE,aAAa,WAChCvB,EAAYwB,YAAYpB,EAAYkB,GAIpC,GAAI7C,KAAKD,SAAU,CACfC,KAAKD,SAAS,KAAMG,EACxB,GAER,CAEA,MAAM8C,EAAarD,EAAMa,IAAIyC,oBAAsBjD,KAAKiB,WAAa,QAAU,MAC/EsB,EAAKW,aAAa,mBAAmBvD,EAAMa,IAAIC,OAASP,IAAW8C,QAK/E,OAAOhD,KAAKY,OAChB,CAMOuC,WACH,MAAO,CAAEC,QAAS,KACtB,CAKUC,WACN,OAAO,IACX,CAKUC,aACN,EAEP,IAAAC,EAAA,CAAAC,WAAA,MAAAD,EAAA9D,eAAA,OAAA8D,CAAA","ignoreList":[]}
|
|
@@ -67,6 +67,12 @@ export class ObjectPlugin extends BasePlugin {
|
|
|
67
67
|
host.attachSubmit((e: Event) => {
|
|
68
68
|
const payload = (e.getParameter("payload") as unknown);
|
|
69
69
|
parentModel.setProperty(updatePath, payload);
|
|
70
|
+
|
|
71
|
+
// CRITICAL: Notify the parent Engine that this field mutated
|
|
72
|
+
// so it can trigger LiveUpdate syncs and validate!
|
|
73
|
+
if (this.onChange) {
|
|
74
|
+
this.onChange(true, propKey);
|
|
75
|
+
}
|
|
70
76
|
});
|
|
71
77
|
}
|
|
72
78
|
|
|
@@ -38,20 +38,56 @@ sap.ui.define(["./BasePlugin", "sap/m/TextArea", "sap/m/Text"], function (___Bas
|
|
|
38
38
|
value: `{${modelName}>${bindingPath}}`,
|
|
39
39
|
maxLength: fieldMetadata.maxLength || 0,
|
|
40
40
|
required: !!fieldMetadata.required,
|
|
41
|
-
rows:
|
|
42
|
-
//
|
|
41
|
+
rows: 3,
|
|
42
|
+
// Start with at least 3 lines
|
|
43
|
+
growing: false,
|
|
44
|
+
// We manage height manually to maintain the +2 lines requirement
|
|
43
45
|
change: oEvent => {
|
|
44
|
-
|
|
46
|
+
this.updateHeight(oEvent.getSource());
|
|
45
47
|
const result = this.validate();
|
|
46
48
|
if (this.onChange) {
|
|
47
49
|
this.onChange(result.isValid, this.fieldKey);
|
|
48
50
|
}
|
|
51
|
+
},
|
|
52
|
+
liveChange: oEvent => {
|
|
53
|
+
this.updateHeight(oEvent.getSource());
|
|
49
54
|
}
|
|
50
55
|
});
|
|
56
|
+
|
|
57
|
+
// Clean architecture: Wait for the model context, then calculate initial height
|
|
58
|
+
this.control.attachEventOnce("modelContextChange", () => {
|
|
59
|
+
const oBinding = this.control.getBinding("value");
|
|
60
|
+
const initLogic = () => {
|
|
61
|
+
if (this.control) {
|
|
62
|
+
this.updateHeight(this.control);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
if (oBinding) {
|
|
66
|
+
oBinding.attachChange(initLogic);
|
|
67
|
+
}
|
|
68
|
+
// Execute immediately in case the model is synchronous (JSONModel)
|
|
69
|
+
initLogic();
|
|
70
|
+
});
|
|
51
71
|
this.applyCommonDirectives(this.control, fieldMetadata, modelName);
|
|
52
72
|
return this.control;
|
|
53
73
|
}
|
|
54
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Dynamically sets the rows to the content length + 2
|
|
77
|
+
*/
|
|
78
|
+
updateHeight(oTextArea) {
|
|
79
|
+
const val = oTextArea.getValue() || "";
|
|
80
|
+
// Count actual newlines in the string
|
|
81
|
+
const numLines = val.split(/\r\n|\r|\n/).length;
|
|
82
|
+
// Also estimate word wrapping if they type a really long single line without pressing enter
|
|
83
|
+
// A standard character width approximation, assuming ~80 chars per line for full width
|
|
84
|
+
const wrappedLines = Math.ceil(val.length / 80);
|
|
85
|
+
const totalLines = Math.max(numLines, wrappedLines);
|
|
86
|
+
|
|
87
|
+
// Ensure there is always 2 lines of extra breathing room
|
|
88
|
+
oTextArea.setRows(Math.max(3, totalLines + 2));
|
|
89
|
+
}
|
|
90
|
+
|
|
55
91
|
/**
|
|
56
92
|
* Retrieves the current text string.
|
|
57
93
|
* @returns {unknown} The text string.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextAreaPlugin-dbg.js","names":["BasePlugin","___BasePlugin","TextAreaPlugin","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","metadata","fieldKey","replace","isEditable","control","TextControl","id","generateStableId","text","applyCommonDirectives","TextArea","value","maxLength","required","rows","
|
|
1
|
+
{"version":3,"file":"TextAreaPlugin-dbg.js","names":["BasePlugin","___BasePlugin","TextAreaPlugin","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","metadata","fieldKey","replace","isEditable","control","TextControl","id","generateStableId","text","applyCommonDirectives","TextArea","value","maxLength","required","rows","growing","change","oEvent","updateHeight","getSource","result","validate","isValid","liveChange","attachEventOnce","oBinding","getBinding","initLogic","attachChange","oTextArea","val","getValue","numLines","split","length","wrappedLines","Math","ceil","totalLines","max","setRows","applyState","input","setEditable","ui","readOnly","setRequired","__exports","__esModule"],"sources":["TextAreaPlugin.ts"],"sourcesContent":["/**\n * @file TextAreaPlugin.ts\n * @description Renders a sap.m.TextArea for string data specifically marked with the textArea widget.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport TextArea from \"sap/m/TextArea\";\nimport Control from \"sap/ui/core/Control\";\nimport TextControl from \"sap/m/Text\";\n\n/**\n * Handles rendering and logic for multi-line text areas.\n */\nexport class TextAreaPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.TextArea` component.\n * \n * @param fieldMetadata The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured TextArea control.\n */\n public render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = fieldMetadata;\n this.fieldKey = bindingPath.replace(\"/\", \"\"); // For EventBus\n \n if (!this.isEditable) {\n \n this.control = new TextControl({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: `{${modelName}>${bindingPath}}`\n });\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n return this.control as Control;\n }\n\n this.control = new TextArea({\n id: this.generateStableId(engineScopeId, bindingPath),\n value: `{${modelName}>${bindingPath}}`,\n maxLength: fieldMetadata.maxLength || 0,\n required: !!fieldMetadata.required,\n rows: 3, // Start with at least 3 lines\n growing: false, // We manage height manually to maintain the +2 lines requirement\n change: (oEvent: sap.ui.base.Event) => {\n this.updateHeight(oEvent.getSource() as TextArea);\n const result = this.validate();\n if (this.onChange) {\n this.onChange(result.isValid, this.fieldKey);\n }\n },\n liveChange: (oEvent: sap.ui.base.Event) => {\n this.updateHeight(oEvent.getSource() as TextArea);\n }\n });\n\n // Clean architecture: Wait for the model context, then calculate initial height\n (this.control as TextArea).attachEventOnce(\"modelContextChange\", () => {\n const oBinding = (this.control as TextArea).getBinding(\"value\");\n \n const initLogic = () => {\n if (this.control) {\n this.updateHeight(this.control as TextArea);\n }\n };\n\n if (oBinding) {\n oBinding.attachChange(initLogic);\n }\n // Execute immediately in case the model is synchronous (JSONModel)\n initLogic();\n });\n\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n\n return this.control as Control;\n }\n\n /**\n * Dynamically sets the rows to the content length + 2\n */\n private updateHeight(oTextArea: TextArea): void {\n const val = oTextArea.getValue() || \"\";\n // Count actual newlines in the string\n const numLines = val.split(/\\r\\n|\\r|\\n/).length;\n // Also estimate word wrapping if they type a really long single line without pressing enter\n // A standard character width approximation, assuming ~80 chars per line for full width\n const wrappedLines = Math.ceil(val.length / 80);\n \n const totalLines = Math.max(numLines, wrappedLines);\n \n // Ensure there is always 2 lines of extra breathing room\n oTextArea.setRows(Math.max(3, totalLines + 2));\n }\n\n /**\n * Retrieves the current text string.\n * @returns {unknown} The text string.\n */\n protected getValue(): unknown {\n return this.control ? (this.control as TextArea).getValue() : null;\n }\n\n /**\n * Applies dynamic read-only state.\n */\n protected applyState(): void {\n if (this.control && this.metadata) {\n if (!this.isEditable) return;\n const input = this.control as TextArea;\n input.setEditable(!this.metadata.ui?.readOnly);\n input.setRequired(this.metadata.required);\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -21,6 +21,10 @@ declare module "nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin" {
|
|
|
21
21
|
* @returns {Control} The configured TextArea control.
|
|
22
22
|
*/
|
|
23
23
|
render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName?: string, engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control;
|
|
24
|
+
/**
|
|
25
|
+
* Dynamically sets the rows to the content length + 2
|
|
26
|
+
*/
|
|
27
|
+
private updateHeight;
|
|
24
28
|
/**
|
|
25
29
|
* Retrieves the current text string.
|
|
26
30
|
* @returns {unknown} The text string.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextAreaPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,4DAA4D,CAAC;IAC5E;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAElF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAG1C;;OAEG;IACH,MAAa,cAAe,SAAQ,UAAU;QAC1C;;;;;;;;;WASG;QACI,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAG,WAAW,EAAE,MAAM,EAAG,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"TextAreaPlugin.d.ts","sourceRoot":"../../../../../../../../..","sources":["src/nz/co/siliconst/ui5/metaui/plugins/controls/TextAreaPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,4DAA4D,CAAC;IAC5E;;;OAGG;IAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wDAAwD,CAAC;IACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;IAElF,OAAO,OAAO,MAAM,qBAAqB,CAAC;IAG1C;;OAEG;IACH,MAAa,cAAe,SAAQ,UAAU;QAC1C;;;;;;;;;WASG;QACI,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAG,WAAW,EAAE,MAAM,EAAG,SAAS,GAAE,MAAe,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO;QAwD7L;;WAEG;QACH,OAAO,CAAC,YAAY;QAcpB;;;WAGG;QACH,SAAS,CAAC,QAAQ,IAAI,OAAO;QAI7B;;WAEG;QACH,SAAS,CAAC,UAAU,IAAI,IAAI;KAQ/B;CAEA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
sap.ui.define(["./BasePlugin","sap/m/TextArea","sap/m/Text"],function(t,e,i){"use strict";const a=t["BasePlugin"];class
|
|
1
|
+
sap.ui.define(["./BasePlugin","sap/m/TextArea","sap/m/Text"],function(t,e,i){"use strict";const a=t["BasePlugin"];class n extends a{render(t,a,n="meta",s,h){this.onChange=h;this.metadata=t;this.fieldKey=a.replace("/","");if(!this.isEditable){this.control=new i({id:this.generateStableId(s,a),text:`{${n}>${a}}`});this.applyCommonDirectives(this.control,t,n);return this.control}this.control=new e({id:this.generateStableId(s,a),value:`{${n}>${a}}`,maxLength:t.maxLength||0,required:!!t.required,rows:3,growing:false,change:t=>{this.updateHeight(t.getSource());const e=this.validate();if(this.onChange){this.onChange(e.isValid,this.fieldKey)}},liveChange:t=>{this.updateHeight(t.getSource())}});this.control.attachEventOnce("modelContextChange",()=>{const t=this.control.getBinding("value");const e=()=>{if(this.control){this.updateHeight(this.control)}};if(t){t.attachChange(e)}e()});this.applyCommonDirectives(this.control,t,n);return this.control}updateHeight(t){const e=t.getValue()||"";const i=e.split(/\r\n|\r|\n/).length;const a=Math.ceil(e.length/80);const n=Math.max(i,a);t.setRows(Math.max(3,n+2))}getValue(){return this.control?this.control.getValue():null}applyState(){if(this.control&&this.metadata){if(!this.isEditable)return;const t=this.control;t.setEditable(!this.metadata.ui?.readOnly);t.setRequired(this.metadata.required)}}}var s={__esModule:true};s.TextAreaPlugin=n;return s});
|
|
2
2
|
//# sourceMappingURL=TextAreaPlugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextAreaPlugin.js","names":["BasePlugin","___BasePlugin","TextAreaPlugin","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","this","metadata","fieldKey","replace","isEditable","control","TextControl","id","generateStableId","text","applyCommonDirectives","TextArea","value","maxLength","required","rows","
|
|
1
|
+
{"version":3,"file":"TextAreaPlugin.js","names":["BasePlugin","___BasePlugin","TextAreaPlugin","render","fieldMetadata","bindingPath","modelName","engineScopeId","onChange","this","metadata","fieldKey","replace","isEditable","control","TextControl","id","generateStableId","text","applyCommonDirectives","TextArea","value","maxLength","required","rows","growing","change","oEvent","updateHeight","getSource","result","validate","isValid","liveChange","attachEventOnce","oBinding","getBinding","initLogic","attachChange","oTextArea","val","getValue","numLines","split","length","wrappedLines","Math","ceil","totalLines","max","setRows","applyState","input","setEditable","ui","readOnly","setRequired","__exports","__esModule"],"sources":["TextAreaPlugin.ts"],"sourcesContent":["/**\n * @file TextAreaPlugin.ts\n * @description Renders a sap.m.TextArea for string data specifically marked with the textArea widget.\n */\n\nimport { BasePlugin } from \"./BasePlugin\";\nimport { IPropertyMetadata } from \"../../interfaces/ISchema\";\nimport TextArea from \"sap/m/TextArea\";\nimport Control from \"sap/ui/core/Control\";\nimport TextControl from \"sap/m/Text\";\n\n/**\n * Handles rendering and logic for multi-line text areas.\n */\nexport class TextAreaPlugin extends BasePlugin {\n /**\n * Renders a `sap.m.TextArea` component.\n * \n * @param fieldMetadata The specific JSON schema properties for this field.\n * @param bindingPath The JSON path bound to this control.\n * @param modelName The UI5 JSONModel name.\n * @param engineScopeId The deterministic scope ID.\n * @param onChange The callback fired on value change.\n * @returns {Control} The configured TextArea control.\n */\n public render(fieldMetadata: IPropertyMetadata, bindingPath: string, modelName: string = \"meta\", engineScopeId?: string, onChange?: (isValid: boolean, fieldKey?: string) => void): Control {\n this.onChange = onChange;\n this.metadata = fieldMetadata;\n this.fieldKey = bindingPath.replace(\"/\", \"\"); // For EventBus\n \n if (!this.isEditable) {\n \n this.control = new TextControl({\n id: this.generateStableId(engineScopeId, bindingPath),\n text: `{${modelName}>${bindingPath}}`\n });\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n return this.control as Control;\n }\n\n this.control = new TextArea({\n id: this.generateStableId(engineScopeId, bindingPath),\n value: `{${modelName}>${bindingPath}}`,\n maxLength: fieldMetadata.maxLength || 0,\n required: !!fieldMetadata.required,\n rows: 3, // Start with at least 3 lines\n growing: false, // We manage height manually to maintain the +2 lines requirement\n change: (oEvent: sap.ui.base.Event) => {\n this.updateHeight(oEvent.getSource() as TextArea);\n const result = this.validate();\n if (this.onChange) {\n this.onChange(result.isValid, this.fieldKey);\n }\n },\n liveChange: (oEvent: sap.ui.base.Event) => {\n this.updateHeight(oEvent.getSource() as TextArea);\n }\n });\n\n // Clean architecture: Wait for the model context, then calculate initial height\n (this.control as TextArea).attachEventOnce(\"modelContextChange\", () => {\n const oBinding = (this.control as TextArea).getBinding(\"value\");\n \n const initLogic = () => {\n if (this.control) {\n this.updateHeight(this.control as TextArea);\n }\n };\n\n if (oBinding) {\n oBinding.attachChange(initLogic);\n }\n // Execute immediately in case the model is synchronous (JSONModel)\n initLogic();\n });\n\n this.applyCommonDirectives(this.control, fieldMetadata, modelName);\n\n return this.control as Control;\n }\n\n /**\n * Dynamically sets the rows to the content length + 2\n */\n private updateHeight(oTextArea: TextArea): void {\n const val = oTextArea.getValue() || \"\";\n // Count actual newlines in the string\n const numLines = val.split(/\\r\\n|\\r|\\n/).length;\n // Also estimate word wrapping if they type a really long single line without pressing enter\n // A standard character width approximation, assuming ~80 chars per line for full width\n const wrappedLines = Math.ceil(val.length / 80);\n \n const totalLines = Math.max(numLines, wrappedLines);\n \n // Ensure there is always 2 lines of extra breathing room\n oTextArea.setRows(Math.max(3, totalLines + 2));\n }\n\n /**\n * Retrieves the current text string.\n * @returns {unknown} The text string.\n */\n protected getValue(): unknown {\n return this.control ? (this.control as TextArea).getValue() : null;\n }\n\n /**\n * Applies dynamic read-only state.\n */\n protected applyState(): void {\n if (this.control && this.metadata) {\n if (!this.isEditable) return;\n const input = this.control as TextArea;\n input.setEditable(!this.metadata.ui?.readOnly);\n input.setRequired(this.metadata.required);\n }\n }\n}\n"],"mappings":"0FAAA,MAKSA,EAAUC,EAAA,cASZ,MAAMC,UAAuBF,EAWzBG,OAAOC,EAAmCC,EAAsBC,EAAoB,OAAQC,EAAwBC,GACvHC,KAAKD,SAAWA,EAChBC,KAAKC,SAAWN,EAChBK,KAAKE,SAAWN,EAAYO,QAAQ,IAAK,IAEzC,IAAKH,KAAKI,WAAY,CAElBJ,KAAKK,QAAU,IAAIC,EAAY,CAC3BC,GAAIP,KAAKQ,iBAAiBV,EAAeF,GACzCa,KAAM,IAAIZ,KAAaD,OAE3BI,KAAKU,sBAAsBV,KAAKK,QAASV,EAAeE,GACxD,OAAOG,KAAKK,OAChB,CAEAL,KAAKK,QAAU,IAAIM,EAAS,CACxBJ,GAAIP,KAAKQ,iBAAiBV,EAAeF,GACzCgB,MAAO,IAAIf,KAAaD,KACxBiB,UAAWlB,EAAckB,WAAa,EACtCC,WAAYnB,EAAcmB,SAC1BC,KAAM,EACNC,QAAS,MACTC,OAASC,IACLlB,KAAKmB,aAAaD,EAAOE,aACzB,MAAMC,EAASrB,KAAKsB,WACpB,GAAItB,KAAKD,SAAU,CACfC,KAAKD,SAASsB,EAAOE,QAASvB,KAAKE,SACvC,GAEJsB,WAAaN,IACTlB,KAAKmB,aAAaD,EAAOE,gBAKhCpB,KAAKK,QAAqBoB,gBAAgB,qBAAsB,KAC7D,MAAMC,EAAY1B,KAAKK,QAAqBsB,WAAW,SAEvD,MAAMC,EAAYA,KACd,GAAI5B,KAAKK,QAAS,CACdL,KAAKmB,aAAanB,KAAKK,QAC3B,GAGJ,GAAIqB,EAAU,CACVA,EAASG,aAAaD,EAC1B,CAEAA,MAGJ5B,KAAKU,sBAAsBV,KAAKK,QAASV,EAAeE,GAExD,OAAOG,KAAKK,OAChB,CAKQc,aAAaW,GACjB,MAAMC,EAAMD,EAAUE,YAAc,GAEpC,MAAMC,EAAWF,EAAIG,MAAM,cAAcC,OAGzC,MAAMC,EAAeC,KAAKC,KAAKP,EAAII,OAAS,IAE5C,MAAMI,EAAaF,KAAKG,IAAIP,EAAUG,GAGtCN,EAAUW,QAAQJ,KAAKG,IAAI,EAAGD,EAAa,GAC/C,CAMUP,WACN,OAAOhC,KAAKK,QAAWL,KAAKK,QAAqB2B,WAAa,IAClE,CAKUU,aACN,GAAI1C,KAAKK,SAAWL,KAAKC,SAAU,CAC/B,IAAKD,KAAKI,WAAY,OACtB,MAAMuC,EAAQ3C,KAAKK,QACnBsC,EAAMC,aAAa5C,KAAKC,SAAS4C,IAAIC,UACrCH,EAAMI,YAAY/C,KAAKC,SAASa,SACpC,CACJ,EACH,IAAAkC,EAAA,CAAAC,WAAA,MAAAD,EAAAvD,iBAAA,OAAAuD,CAAA","ignoreList":[]}
|