@acorex/platform 20.6.0-next.9 → 21.0.0-next.1
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/auth/index.d.ts +91 -12
- package/common/index.d.ts +615 -44
- package/core/index.d.ts +718 -422
- package/fesm2022/acorex-platform-auth.mjs +152 -39
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/acorex-platform-common.mjs +1009 -112
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +887 -408
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +99 -11
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +555 -492
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +2446 -2733
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +9 -9
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +9708 -4721
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +32 -26
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +252 -182
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-D0y-9nE5.mjs → acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs} +2 -2
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs +30 -0
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-C1l2KSDa.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs} +2 -2
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-D-31ej0C.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs} +2 -2
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +9791 -6928
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +79 -3
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs +157 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs +1542 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +101 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-B_P0a5KW.mjs → acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs} +3 -3
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +282 -43
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs +55 -0
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +42 -137
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +658 -45
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/layout/builder/index.d.ts +10 -34
- package/layout/components/index.d.ts +694 -375
- package/layout/designer/index.d.ts +4 -4
- package/layout/entity/index.d.ts +802 -183
- package/layout/views/index.d.ts +5 -58
- package/layout/widget-core/index.d.ts +63 -75
- package/layout/widgets/README.md +0 -1
- package/layout/widgets/index.d.ts +493 -129
- package/package.json +1 -1
- package/runtime/index.d.ts +36 -8
- package/themes/default/index.d.ts +44 -75
- package/themes/shared/index.d.ts +11 -49
- package/workflow/index.d.ts +401 -90
- package/fesm2022/acorex-platform-layout-entity-create-entity.command-DGeylNSY.mjs +0 -52
- package/fesm2022/acorex-platform-layout-entity-create-entity.command-DGeylNSY.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-fhhZOWul.mjs +0 -50
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-fhhZOWul.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-C3Qbs0fz.mjs +0 -42
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-C3Qbs0fz.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-CngQBUlN.mjs +0 -55
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-CngQBUlN.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-DSNo9e4W.mjs +0 -50
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-DSNo9e4W.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-CL0CwEHX.mjs +0 -48
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-CL0CwEHX.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-B6Fi0xTw.mjs +0 -42
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-B6Fi0xTw.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-D0y-9nE5.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-C1l2KSDa.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-D-31ej0C.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-WbPPqDON.mjs +0 -115
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-WbPPqDON.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CD7rJIMh.mjs +0 -803
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-CD7rJIMh.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BTA6h7Xd.mjs +0 -101
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-BTA6h7Xd.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-B_P0a5KW.mjs.map +0 -1
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import * as i4 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import {
|
|
4
|
+
import { Injectable, inject, input, model, signal, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output, Input } from '@angular/core';
|
|
5
5
|
import { AXPopupService } from '@acorex/components/popup';
|
|
6
|
+
import { cloneDeep, isNil, set, isEqual } from 'lodash-es';
|
|
6
7
|
import * as i2 from '@acorex/components/form';
|
|
7
8
|
import { AXFormComponent, AXFormModule } from '@acorex/components/form';
|
|
8
|
-
import { AXPExpressionEvaluatorService } from '@acorex/platform/core';
|
|
9
9
|
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
10
10
|
import { AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
11
|
-
import { isEqual, get, cloneDeep } from 'lodash-es';
|
|
12
11
|
import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
|
|
13
12
|
import * as i1$1 from '@acorex/components/button';
|
|
14
13
|
import { AXButtonModule } from '@acorex/components/button';
|
|
@@ -19,6 +18,282 @@ import { AXLoadingModule } from '@acorex/components/loading';
|
|
|
19
18
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
20
19
|
import * as i5 from '@acorex/core/translation';
|
|
21
20
|
import { AXTranslationModule } from '@acorex/core/translation';
|
|
21
|
+
import { AXPExpressionEvaluatorService } from '@acorex/platform/core';
|
|
22
|
+
|
|
23
|
+
class AXPLayoutConversionService {
|
|
24
|
+
constructor() {
|
|
25
|
+
//#region ---- Caching ----
|
|
26
|
+
this.widgetTreeCache = new Map();
|
|
27
|
+
this.formDefinitionCache = new Map();
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region ---- Public Methods ----
|
|
31
|
+
/**
|
|
32
|
+
* Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
|
|
33
|
+
* Groups become Fieldset Layouts with Form Field widgets as children
|
|
34
|
+
* Fields become Form Field widgets with Editor widgets as children
|
|
35
|
+
*/
|
|
36
|
+
convertFormDefinition(formDefinition) {
|
|
37
|
+
// Create cache key based on form definition content
|
|
38
|
+
const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
|
|
39
|
+
// Check cache first
|
|
40
|
+
if (this.widgetTreeCache.has(cacheKey)) {
|
|
41
|
+
return this.widgetTreeCache.get(cacheKey);
|
|
42
|
+
}
|
|
43
|
+
// Generate widget tree
|
|
44
|
+
const widgetTree = {
|
|
45
|
+
type: 'grid-layout',
|
|
46
|
+
name: 'dynamic-form-container',
|
|
47
|
+
mode: formDefinition.mode, // Preserve form-level mode
|
|
48
|
+
options: {
|
|
49
|
+
title: 'Dynamic Form',
|
|
50
|
+
grid: {
|
|
51
|
+
default: {
|
|
52
|
+
columns: 1,
|
|
53
|
+
gap: '1rem',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
children: formDefinition.groups.map((group) => this.createGroupAsFieldsetWidget(group, formDefinition.mode)),
|
|
58
|
+
};
|
|
59
|
+
// Cache the result
|
|
60
|
+
this.widgetTreeCache.set(cacheKey, widgetTree);
|
|
61
|
+
return widgetTree;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
|
|
65
|
+
* Parses Fieldset Layouts back to Groups
|
|
66
|
+
* Parses Form Field widgets back to Fields
|
|
67
|
+
*/
|
|
68
|
+
convertWidgetTreeToFormDefinition(widgetTree) {
|
|
69
|
+
// Create cache key based on widget tree content
|
|
70
|
+
const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
|
|
71
|
+
// Check cache first
|
|
72
|
+
if (this.formDefinitionCache.has(cacheKey)) {
|
|
73
|
+
return this.formDefinitionCache.get(cacheKey);
|
|
74
|
+
}
|
|
75
|
+
// Parse widget tree
|
|
76
|
+
const groups = [];
|
|
77
|
+
if (widgetTree.children) {
|
|
78
|
+
widgetTree.children.forEach((child) => {
|
|
79
|
+
if (child.type === 'fieldset-layout') {
|
|
80
|
+
const group = this.extractGroupFromFieldset(child);
|
|
81
|
+
groups.push(group);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const formDefinition = { groups };
|
|
86
|
+
// Cache the result
|
|
87
|
+
this.formDefinitionCache.set(cacheKey, formDefinition);
|
|
88
|
+
return formDefinition;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Validate that a widget tree represents a valid dynamic form structure
|
|
92
|
+
*/
|
|
93
|
+
validateFormWidgetTree(widgetTree) {
|
|
94
|
+
if (!widgetTree || widgetTree.type !== 'grid-layout') {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (!widgetTree.children || widgetTree.children.length === 0) {
|
|
98
|
+
return true; // Empty form is valid
|
|
99
|
+
}
|
|
100
|
+
// Check that all children are fieldset-layout widgets
|
|
101
|
+
return widgetTree.children.every((child) => child.type === 'fieldset-layout' &&
|
|
102
|
+
child.children &&
|
|
103
|
+
child.children.every((formField) => formField.type === 'form-field' && formField.children && formField.children.length > 0));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Clear all caches
|
|
107
|
+
*/
|
|
108
|
+
clearCaches() {
|
|
109
|
+
this.widgetTreeCache.clear();
|
|
110
|
+
this.formDefinitionCache.clear();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get cache statistics
|
|
114
|
+
*/
|
|
115
|
+
getCacheStats() {
|
|
116
|
+
return {
|
|
117
|
+
widgetTreeCacheSize: this.widgetTreeCache.size,
|
|
118
|
+
formDefinitionCacheSize: this.formDefinitionCache.size,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region ---- Private Methods ----
|
|
123
|
+
/**
|
|
124
|
+
* Convert a single group to Fieldset widget structure
|
|
125
|
+
*/
|
|
126
|
+
createGroupAsFieldsetWidget(group, formMode) {
|
|
127
|
+
// Determine columns count from layout or default to 1
|
|
128
|
+
const columnsCount = 1;
|
|
129
|
+
// Use group mode if set, otherwise inherit from form mode
|
|
130
|
+
const groupMode = group.mode || formMode;
|
|
131
|
+
return {
|
|
132
|
+
type: 'fieldset-layout',
|
|
133
|
+
name: group.name,
|
|
134
|
+
mode: groupMode,
|
|
135
|
+
options: {
|
|
136
|
+
title: group.title,
|
|
137
|
+
description: group.description,
|
|
138
|
+
cols: columnsCount,
|
|
139
|
+
look: group.look || 'container', // Default to 'container' if not specified
|
|
140
|
+
},
|
|
141
|
+
children: this.createFieldWidgets(group.parameters, columnsCount, groupMode),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Convert fields to Form Field widgets
|
|
146
|
+
*/
|
|
147
|
+
createFieldWidgets(fields, columnsCount, groupMode) {
|
|
148
|
+
return fields.map((field) => this.createFormFieldWidget(field, groupMode));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Convert a single field to Form Field widget with editor as child
|
|
152
|
+
*/
|
|
153
|
+
createFormFieldWidget(field, groupMode) {
|
|
154
|
+
// Use field mode if set, otherwise inherit from group mode
|
|
155
|
+
const fieldMode = field.mode || groupMode;
|
|
156
|
+
// Ensure the editor widget also has the mode set
|
|
157
|
+
const editorWidget = { ...field.widget };
|
|
158
|
+
if (!editorWidget.mode) {
|
|
159
|
+
editorWidget.mode = fieldMode;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
type: 'form-field',
|
|
163
|
+
name: field.path,
|
|
164
|
+
mode: fieldMode,
|
|
165
|
+
options: {
|
|
166
|
+
label: field.title,
|
|
167
|
+
badge: field.badge,
|
|
168
|
+
description: field.description,
|
|
169
|
+
showLabel: true,
|
|
170
|
+
},
|
|
171
|
+
children: [editorWidget], // The editor widget becomes a child of form-field
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Extract group information from Fieldset Layout widget
|
|
176
|
+
*/
|
|
177
|
+
extractGroupFromFieldset(fieldsetNode) {
|
|
178
|
+
const columnsCount = fieldsetNode.options?.['cols'] || 1;
|
|
179
|
+
// Extract fields directly from fieldset children
|
|
180
|
+
const fields = [];
|
|
181
|
+
if (fieldsetNode.children) {
|
|
182
|
+
fieldsetNode.children.forEach((formField) => {
|
|
183
|
+
if (formField.type === 'form-field' && formField.children && formField.children.length > 0) {
|
|
184
|
+
const field = this.extractFieldFromFormWidget(formField);
|
|
185
|
+
if (field) {
|
|
186
|
+
fields.push(field);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
name: fieldsetNode.name || `group-${Date.now()}`,
|
|
193
|
+
title: fieldsetNode.options?.['title'],
|
|
194
|
+
description: fieldsetNode.options?.['description'],
|
|
195
|
+
parameters: fields,
|
|
196
|
+
mode: fieldsetNode.mode,
|
|
197
|
+
look: fieldsetNode.options?.['look'],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Extract field information from Form Field widget
|
|
202
|
+
*/
|
|
203
|
+
extractFieldFromFormWidget(formFieldNode) {
|
|
204
|
+
if (!formFieldNode.children || formFieldNode.children.length === 0) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const editorWidget = formFieldNode.children[0];
|
|
208
|
+
return {
|
|
209
|
+
path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
|
|
210
|
+
title: formFieldNode.options?.['label'],
|
|
211
|
+
badge: formFieldNode.options?.['badge'],
|
|
212
|
+
description: formFieldNode.options?.['description'],
|
|
213
|
+
widget: editorWidget,
|
|
214
|
+
mode: formFieldNode.mode,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Create cache key for form definition
|
|
219
|
+
*/
|
|
220
|
+
createFormDefinitionCacheKey(formDefinition) {
|
|
221
|
+
// Create a hash-like key instead of full JSON string
|
|
222
|
+
const keyParts = [];
|
|
223
|
+
keyParts.push(`groups:${formDefinition.groups.length}`);
|
|
224
|
+
formDefinition.groups.forEach((group, groupIndex) => {
|
|
225
|
+
keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
|
|
226
|
+
group.parameters.forEach((param, paramIndex) => {
|
|
227
|
+
keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
if (formDefinition.mode) {
|
|
231
|
+
keyParts.push(`mode:${formDefinition.mode}`);
|
|
232
|
+
}
|
|
233
|
+
// Join with delimiter and create a shorter hash
|
|
234
|
+
const keyString = keyParts.join('|');
|
|
235
|
+
// If still too long, create a simple hash
|
|
236
|
+
if (keyString.length > 100) {
|
|
237
|
+
return this.createSimpleHash(keyString);
|
|
238
|
+
}
|
|
239
|
+
return keyString;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Create cache key for widget tree
|
|
243
|
+
*/
|
|
244
|
+
createWidgetTreeCacheKey(widgetTree) {
|
|
245
|
+
// Create a hash-like key instead of full JSON string
|
|
246
|
+
const keyParts = [];
|
|
247
|
+
keyParts.push(`type:${widgetTree.type}`);
|
|
248
|
+
if (widgetTree.name) {
|
|
249
|
+
keyParts.push(`name:${widgetTree.name}`);
|
|
250
|
+
}
|
|
251
|
+
if (widgetTree.children) {
|
|
252
|
+
keyParts.push(`children:${widgetTree.children.length}`);
|
|
253
|
+
widgetTree.children.forEach((child, index) => {
|
|
254
|
+
keyParts.push(`c${index}:${child.type}`);
|
|
255
|
+
if (child.children) {
|
|
256
|
+
keyParts.push(`cc${index}:${child.children.length}`);
|
|
257
|
+
child.children.forEach((grandChild, gIndex) => {
|
|
258
|
+
keyParts.push(`gc${index}.${gIndex}:${grandChild.type}`);
|
|
259
|
+
if (grandChild.children) {
|
|
260
|
+
keyParts.push(`gcc${index}.${gIndex}:${grandChild.children.length}`);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// Join with delimiter and create a shorter hash
|
|
267
|
+
const keyString = keyParts.join('|');
|
|
268
|
+
// If still too long, create a simple hash
|
|
269
|
+
if (keyString.length > 100) {
|
|
270
|
+
return this.createSimpleHash(keyString);
|
|
271
|
+
}
|
|
272
|
+
return keyString;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Create a simple hash from a string
|
|
276
|
+
*/
|
|
277
|
+
createSimpleHash(str) {
|
|
278
|
+
let hash = 0;
|
|
279
|
+
if (str.length === 0)
|
|
280
|
+
return hash.toString();
|
|
281
|
+
for (let i = 0; i < str.length; i++) {
|
|
282
|
+
const char = str.charCodeAt(i);
|
|
283
|
+
hash = (hash << 5) - hash + char;
|
|
284
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
285
|
+
}
|
|
286
|
+
return Math.abs(hash).toString(36); // Convert to base36 for shorter string
|
|
287
|
+
}
|
|
288
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
289
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
|
|
290
|
+
}
|
|
291
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
|
|
292
|
+
type: Injectable,
|
|
293
|
+
args: [{
|
|
294
|
+
providedIn: 'root',
|
|
295
|
+
}]
|
|
296
|
+
}] });
|
|
22
297
|
|
|
23
298
|
//#region ---- Inheritance Utilities ----
|
|
24
299
|
/**
|
|
@@ -74,6 +349,54 @@ function generateValueWidgetPath(widgetName, formFieldName, formFieldLabel) {
|
|
|
74
349
|
}
|
|
75
350
|
return generateRandomId();
|
|
76
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Collects default values from widget node tree and merges them into context
|
|
354
|
+
* Only sets values for paths that don't already exist in the context
|
|
355
|
+
* @param node - The widget node to process
|
|
356
|
+
* @param context - The context object to modify in place (cloned at top level only)
|
|
357
|
+
* @param isTopLevel - Internal flag to track if this is the top-level call
|
|
358
|
+
*/
|
|
359
|
+
function collectDefaultValues(node, context = {}, isTopLevel = true) {
|
|
360
|
+
// Clone context only at the top level, then modify in place for recursive calls
|
|
361
|
+
const result = isTopLevel ? cloneDeep(context) : context;
|
|
362
|
+
// Check if this node has a defaultValue and a path
|
|
363
|
+
// Note: We check for both node.defaultValue and also look in node.options.defaultValue as fallback
|
|
364
|
+
const defaultValue = node.defaultValue !== undefined
|
|
365
|
+
? node.defaultValue
|
|
366
|
+
: node.options?.defaultValue;
|
|
367
|
+
if (defaultValue !== undefined && !isNil(defaultValue) && node.path) {
|
|
368
|
+
// Check if path exists in context using lodash get equivalent check
|
|
369
|
+
const currentValue = getNestedValue(result, node.path);
|
|
370
|
+
if (currentValue === undefined) {
|
|
371
|
+
// Clone the defaultValue to avoid reference issues (especially for Date objects)
|
|
372
|
+
const clonedValue = defaultValue instanceof Date
|
|
373
|
+
? new Date(defaultValue.getTime())
|
|
374
|
+
: cloneDeep(defaultValue);
|
|
375
|
+
set(result, node.path, clonedValue);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// Recursively process children - pass result object to accumulate values in place
|
|
379
|
+
if (node.children && Array.isArray(node.children)) {
|
|
380
|
+
for (const child of node.children) {
|
|
381
|
+
collectDefaultValues(child, result, false);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Gets a nested value from an object using dot notation path
|
|
388
|
+
*/
|
|
389
|
+
function getNestedValue(obj, path) {
|
|
390
|
+
const keys = path.split('.');
|
|
391
|
+
let current = obj;
|
|
392
|
+
for (const key of keys) {
|
|
393
|
+
if (current === undefined || current === null || typeof current !== 'object') {
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
current = current[key];
|
|
397
|
+
}
|
|
398
|
+
return current;
|
|
399
|
+
}
|
|
77
400
|
//#endregion
|
|
78
401
|
//#region ---- Service Implementation ----
|
|
79
402
|
class AXPLayoutBuilderService {
|
|
@@ -480,6 +803,26 @@ class ChildContainerMixin extends LayoutContainerMixin {
|
|
|
480
803
|
this.containerState.children.push(field.build());
|
|
481
804
|
return this;
|
|
482
805
|
}
|
|
806
|
+
dynamicForm(definition) {
|
|
807
|
+
// Get conversion service using inject() - works in any context in Angular 14+
|
|
808
|
+
let conversionService;
|
|
809
|
+
try {
|
|
810
|
+
conversionService = inject(AXPLayoutConversionService);
|
|
811
|
+
}
|
|
812
|
+
catch {
|
|
813
|
+
// Fallback: create service instance if inject() fails (shouldn't happen in normal usage)
|
|
814
|
+
conversionService = new AXPLayoutConversionService();
|
|
815
|
+
}
|
|
816
|
+
// Convert form definition to widget node
|
|
817
|
+
const widgetNode = conversionService.convertFormDefinition(definition);
|
|
818
|
+
// Add the widget node's children to this container
|
|
819
|
+
// The converted widget node has a root grid-layout, we want its children (fieldsets)
|
|
820
|
+
if (widgetNode.children && widgetNode.children.length > 0) {
|
|
821
|
+
this.ensureChildren();
|
|
822
|
+
this.containerState.children.push(...widgetNode.children);
|
|
823
|
+
}
|
|
824
|
+
return this;
|
|
825
|
+
}
|
|
483
826
|
}
|
|
484
827
|
/**
|
|
485
828
|
* Widget container mixin - Interface Segregation Principle
|
|
@@ -540,8 +883,56 @@ class WidgetContainerMixin extends ChildContainerMixin {
|
|
|
540
883
|
this.containerState.children.push(container.build());
|
|
541
884
|
return this;
|
|
542
885
|
}
|
|
543
|
-
customWidget(type,
|
|
544
|
-
|
|
886
|
+
customWidget(type, optionsOrDelegate, delegate) {
|
|
887
|
+
const child = new WidgetBuilder();
|
|
888
|
+
child.type(type);
|
|
889
|
+
// Determine if second parameter is delegate or options
|
|
890
|
+
const isDelegate = typeof optionsOrDelegate === 'function';
|
|
891
|
+
const options = isDelegate ? undefined : optionsOrDelegate;
|
|
892
|
+
const actualDelegate = isDelegate ? optionsOrDelegate : delegate;
|
|
893
|
+
// Apply inheritance context BEFORE setting options or calling delegate
|
|
894
|
+
child.withInheritanceContext(this.inheritanceContext);
|
|
895
|
+
// If options are provided (non-delegate overload), handle them
|
|
896
|
+
if (!isDelegate && options !== undefined) {
|
|
897
|
+
const widgetOptions = options;
|
|
898
|
+
const path = widgetOptions.path;
|
|
899
|
+
const name = widgetOptions.name;
|
|
900
|
+
// Set name and path in widget state, not options
|
|
901
|
+
if (name) {
|
|
902
|
+
child.name(name);
|
|
903
|
+
}
|
|
904
|
+
if (path) {
|
|
905
|
+
child.path(path);
|
|
906
|
+
}
|
|
907
|
+
// Remove name and path from options
|
|
908
|
+
const { name: _, path: __, ...cleanOptions } = widgetOptions;
|
|
909
|
+
child.options(cleanOptions);
|
|
910
|
+
}
|
|
911
|
+
// If delegate is provided, call it to allow setting path, options, and other control methods
|
|
912
|
+
if (actualDelegate) {
|
|
913
|
+
actualDelegate(child);
|
|
914
|
+
}
|
|
915
|
+
// Build the widget to check if path is set (for value widgets)
|
|
916
|
+
const builtWidget = child.build();
|
|
917
|
+
// Check if value widget requires path
|
|
918
|
+
const valueWidgetTypes = [
|
|
919
|
+
'text-editor',
|
|
920
|
+
'large-text-editor',
|
|
921
|
+
'rich-text-editor',
|
|
922
|
+
'password-editor',
|
|
923
|
+
'number-editor',
|
|
924
|
+
'select-editor',
|
|
925
|
+
'lookup-editor',
|
|
926
|
+
'selection-list-editor',
|
|
927
|
+
'date-time-editor',
|
|
928
|
+
'toggle-editor',
|
|
929
|
+
'color-editor',
|
|
930
|
+
];
|
|
931
|
+
if (valueWidgetTypes.includes(type) && !builtWidget.path) {
|
|
932
|
+
throw new Error(`Value widget '${type}' requires a 'path' property`);
|
|
933
|
+
}
|
|
934
|
+
this.ensureChildren();
|
|
935
|
+
this.containerState.children.push(builtWidget);
|
|
545
936
|
return this;
|
|
546
937
|
}
|
|
547
938
|
}
|
|
@@ -725,6 +1116,14 @@ class FormFieldBuilder extends LayoutContainerMixin {
|
|
|
725
1116
|
setShowLabel(showLabel) {
|
|
726
1117
|
return this.setOptions({ showLabel });
|
|
727
1118
|
}
|
|
1119
|
+
defaultValue(value) {
|
|
1120
|
+
this.containerState.defaultValue = value;
|
|
1121
|
+
this.inheritanceContext.defaultValue = value;
|
|
1122
|
+
if (this.childWidget) {
|
|
1123
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
1124
|
+
}
|
|
1125
|
+
return this;
|
|
1126
|
+
}
|
|
728
1127
|
// Single widget methods with automatic path generation
|
|
729
1128
|
addSingleWidget(type, options) {
|
|
730
1129
|
if (this.hasWidget) {
|
|
@@ -916,7 +1315,7 @@ class FieldsetContainerBuilder extends LayoutContainerMixin {
|
|
|
916
1315
|
*/
|
|
917
1316
|
class ListWidgetBuilder extends WidgetContainerMixin {
|
|
918
1317
|
constructor() {
|
|
919
|
-
super('list');
|
|
1318
|
+
super('data-list');
|
|
920
1319
|
}
|
|
921
1320
|
setOptions(options) {
|
|
922
1321
|
this.containerState.options = { ...this.containerState.options, ...options };
|
|
@@ -1099,11 +1498,14 @@ class DialogContainerBuilder {
|
|
|
1099
1498
|
const dialogNode = this.build();
|
|
1100
1499
|
// Import the dialog renderer component dynamically
|
|
1101
1500
|
const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
|
|
1501
|
+
// Collect default values from widget tree and merge into initial context
|
|
1502
|
+
const initialContext = this.dialogState.dialogOptions?.context || {};
|
|
1503
|
+
const contextWithDefaults = collectDefaultValues(dialogNode, initialContext);
|
|
1102
1504
|
// Create dialog configuration
|
|
1103
1505
|
const dialogConfig = {
|
|
1104
1506
|
title: this.dialogState.dialogOptions?.title || '',
|
|
1105
1507
|
message: this.dialogState.dialogOptions?.message,
|
|
1106
|
-
context:
|
|
1508
|
+
context: contextWithDefaults,
|
|
1107
1509
|
definition: dialogNode,
|
|
1108
1510
|
actions: this.dialogState.actions,
|
|
1109
1511
|
};
|
|
@@ -1159,8 +1561,18 @@ class WidgetBuilder {
|
|
|
1159
1561
|
return this;
|
|
1160
1562
|
}
|
|
1161
1563
|
options(options) {
|
|
1162
|
-
//
|
|
1163
|
-
|
|
1564
|
+
// Extract defaultValue from options - it's an exceptional parameter that updates context, not a widget option
|
|
1565
|
+
if (options && options.defaultValue !== undefined) {
|
|
1566
|
+
this.widgetState.defaultValue = options.defaultValue;
|
|
1567
|
+
// Remove defaultValue from options since it's stored on the node, not in options
|
|
1568
|
+
const { defaultValue: _, ...cleanOptions } = options;
|
|
1569
|
+
// Merge clean options instead of replacing to preserve inherited properties
|
|
1570
|
+
this.widgetState.options = { ...this.widgetState.options, ...cleanOptions };
|
|
1571
|
+
}
|
|
1572
|
+
else {
|
|
1573
|
+
// Merge options instead of replacing to preserve inherited properties
|
|
1574
|
+
this.widgetState.options = { ...this.widgetState.options, ...options };
|
|
1575
|
+
}
|
|
1164
1576
|
return this;
|
|
1165
1577
|
}
|
|
1166
1578
|
layout(value) {
|
|
@@ -1201,6 +1613,10 @@ class WidgetBuilder {
|
|
|
1201
1613
|
this.inheritanceContext.disabled = condition;
|
|
1202
1614
|
return this;
|
|
1203
1615
|
}
|
|
1616
|
+
defaultValue(defaultValue) {
|
|
1617
|
+
this.widgetState.defaultValue = defaultValue;
|
|
1618
|
+
return this;
|
|
1619
|
+
}
|
|
1204
1620
|
readonly(condition) {
|
|
1205
1621
|
if (!this.widgetState.options) {
|
|
1206
1622
|
this.widgetState.options = {};
|
|
@@ -1241,6 +1657,9 @@ class WidgetBuilder {
|
|
|
1241
1657
|
if (resolved.visible !== undefined) {
|
|
1242
1658
|
this.widgetState.options['visible'] = resolved.visible;
|
|
1243
1659
|
}
|
|
1660
|
+
if (context.defaultValue !== undefined) {
|
|
1661
|
+
this.widgetState.defaultValue = context.defaultValue;
|
|
1662
|
+
}
|
|
1244
1663
|
return this;
|
|
1245
1664
|
}
|
|
1246
1665
|
getInheritanceContext() {
|
|
@@ -1308,412 +1727,133 @@ class StepBuilder {
|
|
|
1308
1727
|
}
|
|
1309
1728
|
setIcon(icon) {
|
|
1310
1729
|
this.icon = icon;
|
|
1311
|
-
return this;
|
|
1312
|
-
}
|
|
1313
|
-
setDescription(description) {
|
|
1314
|
-
this.description = description;
|
|
1315
|
-
return this;
|
|
1316
|
-
}
|
|
1317
|
-
setSkippable(skippable) {
|
|
1318
|
-
this.skippable = skippable;
|
|
1319
|
-
return this;
|
|
1320
|
-
}
|
|
1321
|
-
content(delegate) {
|
|
1322
|
-
if (delegate) {
|
|
1323
|
-
// Create LayoutBuilder in injection context (will be called from component)
|
|
1324
|
-
const layoutBuilder = new LayoutBuilder();
|
|
1325
|
-
// ✅ IMPORTANT: Propagate inheritance context to content
|
|
1326
|
-
layoutBuilder.inheritanceContext = { ...this.inheritanceContext };
|
|
1327
|
-
delegate(layoutBuilder);
|
|
1328
|
-
this.contentNode = layoutBuilder.build();
|
|
1329
|
-
}
|
|
1330
|
-
return this;
|
|
1331
|
-
}
|
|
1332
|
-
withInheritanceContext(context) {
|
|
1333
|
-
this.inheritanceContext = mergeInheritanceContext(context);
|
|
1334
|
-
return this;
|
|
1335
|
-
}
|
|
1336
|
-
build() {
|
|
1337
|
-
if (!this.contentNode) {
|
|
1338
|
-
throw new Error(`Step '${this.id}' must have content`);
|
|
1339
|
-
}
|
|
1340
|
-
return {
|
|
1341
|
-
id: this.id,
|
|
1342
|
-
title: this.title,
|
|
1343
|
-
icon: this.icon,
|
|
1344
|
-
description: this.description,
|
|
1345
|
-
skippable: this.skippable,
|
|
1346
|
-
content: this.contentNode,
|
|
1347
|
-
};
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
/**
|
|
1351
|
-
* Step Wizard Builder - Builds step wizard widget
|
|
1352
|
-
*/
|
|
1353
|
-
class StepWizardBuilder extends LayoutContainerMixin {
|
|
1354
|
-
constructor() {
|
|
1355
|
-
super('step-wizard');
|
|
1356
|
-
this.steps = [];
|
|
1357
|
-
this.linear = true;
|
|
1358
|
-
this.wizardDirection = 'horizontal';
|
|
1359
|
-
}
|
|
1360
|
-
setLinear(linear) {
|
|
1361
|
-
this.linear = linear;
|
|
1362
|
-
return this;
|
|
1363
|
-
}
|
|
1364
|
-
setDirection(direction) {
|
|
1365
|
-
this.wizardDirection = direction;
|
|
1366
|
-
return this;
|
|
1367
|
-
}
|
|
1368
|
-
setLook(look) {
|
|
1369
|
-
this.look = look;
|
|
1370
|
-
return this;
|
|
1371
|
-
}
|
|
1372
|
-
setShowActions(show) {
|
|
1373
|
-
this.showActions = show;
|
|
1374
|
-
return this;
|
|
1375
|
-
}
|
|
1376
|
-
setActions(actions) {
|
|
1377
|
-
this.wizardActions = actions;
|
|
1378
|
-
return this;
|
|
1379
|
-
}
|
|
1380
|
-
setGuards(guards) {
|
|
1381
|
-
this.guards = guards;
|
|
1382
|
-
return this;
|
|
1383
|
-
}
|
|
1384
|
-
setEvents(events) {
|
|
1385
|
-
this.events = events;
|
|
1386
|
-
return this;
|
|
1387
|
-
}
|
|
1388
|
-
step(id, title, delegate) {
|
|
1389
|
-
const stepBuilder = new StepBuilder(id, title);
|
|
1390
|
-
// ✅ IMPORTANT: Propagate inheritance context to step
|
|
1391
|
-
stepBuilder.withInheritanceContext(this.inheritanceContext);
|
|
1392
|
-
if (delegate) {
|
|
1393
|
-
delegate(stepBuilder);
|
|
1394
|
-
}
|
|
1395
|
-
this.steps.push(stepBuilder.build());
|
|
1396
|
-
return this;
|
|
1397
|
-
}
|
|
1398
|
-
build() {
|
|
1399
|
-
// ✅ Validation
|
|
1400
|
-
if (this.steps.length === 0) {
|
|
1401
|
-
throw new Error('StepWizard must have at least one step');
|
|
1402
|
-
}
|
|
1403
|
-
// ✅ Check duplicate IDs
|
|
1404
|
-
const ids = this.steps.map((s) => s.id);
|
|
1405
|
-
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
|
|
1406
|
-
if (duplicates.length > 0) {
|
|
1407
|
-
throw new Error(`Duplicate step IDs found: ${duplicates.join(', ')}`);
|
|
1408
|
-
}
|
|
1409
|
-
const definition = {
|
|
1410
|
-
steps: this.steps,
|
|
1411
|
-
linear: this.linear,
|
|
1412
|
-
direction: this.wizardDirection,
|
|
1413
|
-
look: this.look,
|
|
1414
|
-
// Do not auto-detect based on dialog context; keep explicit or undefined
|
|
1415
|
-
showActions: this.showActions,
|
|
1416
|
-
actions: this.wizardActions,
|
|
1417
|
-
guards: this.guards,
|
|
1418
|
-
events: this.events,
|
|
1419
|
-
};
|
|
1420
|
-
const node = {
|
|
1421
|
-
name: this.containerState.name,
|
|
1422
|
-
type: 'step-wizard',
|
|
1423
|
-
options: { definition },
|
|
1424
|
-
mode: this.containerState.mode,
|
|
1425
|
-
};
|
|
1426
|
-
return node;
|
|
1427
|
-
}
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
class AXPLayoutConversionService {
|
|
1431
|
-
constructor() {
|
|
1432
|
-
//#region ---- Caching ----
|
|
1433
|
-
this.widgetTreeCache = new Map();
|
|
1434
|
-
this.formDefinitionCache = new Map();
|
|
1435
|
-
}
|
|
1436
|
-
//#endregion
|
|
1437
|
-
//#region ---- Public Methods ----
|
|
1438
|
-
/**
|
|
1439
|
-
* Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
|
|
1440
|
-
* Groups become Fieldset Layouts with Form Field widgets as children
|
|
1441
|
-
* Fields become Form Field widgets with Editor widgets as children
|
|
1442
|
-
*/
|
|
1443
|
-
convertFormDefinition(formDefinition) {
|
|
1444
|
-
// Create cache key based on form definition content
|
|
1445
|
-
const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
|
|
1446
|
-
// Check cache first
|
|
1447
|
-
if (this.widgetTreeCache.has(cacheKey)) {
|
|
1448
|
-
return this.widgetTreeCache.get(cacheKey);
|
|
1449
|
-
}
|
|
1450
|
-
// Generate widget tree
|
|
1451
|
-
const widgetTree = {
|
|
1452
|
-
type: 'grid-layout',
|
|
1453
|
-
name: 'dynamic-form-container',
|
|
1454
|
-
options: {
|
|
1455
|
-
title: 'Dynamic Form',
|
|
1456
|
-
grid: {
|
|
1457
|
-
default: {
|
|
1458
|
-
columns: 1,
|
|
1459
|
-
gap: '1rem',
|
|
1460
|
-
},
|
|
1461
|
-
},
|
|
1462
|
-
},
|
|
1463
|
-
children: formDefinition.groups.map((group) => this.createGroupAsFieldsetWidget(group)),
|
|
1464
|
-
};
|
|
1465
|
-
// Cache the result
|
|
1466
|
-
this.widgetTreeCache.set(cacheKey, widgetTree);
|
|
1467
|
-
return widgetTree;
|
|
1468
|
-
}
|
|
1469
|
-
/**
|
|
1470
|
-
* Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
|
|
1471
|
-
* Parses Fieldset Layouts back to Groups
|
|
1472
|
-
* Parses Form Field widgets back to Fields
|
|
1473
|
-
*/
|
|
1474
|
-
convertWidgetTreeToFormDefinition(widgetTree) {
|
|
1475
|
-
// Create cache key based on widget tree content
|
|
1476
|
-
const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
|
|
1477
|
-
// Check cache first
|
|
1478
|
-
if (this.formDefinitionCache.has(cacheKey)) {
|
|
1479
|
-
return this.formDefinitionCache.get(cacheKey);
|
|
1480
|
-
}
|
|
1481
|
-
// Parse widget tree
|
|
1482
|
-
const groups = [];
|
|
1483
|
-
if (widgetTree.children) {
|
|
1484
|
-
widgetTree.children.forEach((child) => {
|
|
1485
|
-
if (child.type === 'fieldset-layout') {
|
|
1486
|
-
const group = this.extractGroupFromFieldset(child);
|
|
1487
|
-
groups.push(group);
|
|
1488
|
-
}
|
|
1489
|
-
});
|
|
1490
|
-
}
|
|
1491
|
-
const formDefinition = { groups };
|
|
1492
|
-
// Cache the result
|
|
1493
|
-
this.formDefinitionCache.set(cacheKey, formDefinition);
|
|
1494
|
-
return formDefinition;
|
|
1495
|
-
}
|
|
1496
|
-
/**
|
|
1497
|
-
* Validate that a widget tree represents a valid dynamic form structure
|
|
1498
|
-
*/
|
|
1499
|
-
validateFormWidgetTree(widgetTree) {
|
|
1500
|
-
if (!widgetTree || widgetTree.type !== 'grid-layout') {
|
|
1501
|
-
return false;
|
|
1502
|
-
}
|
|
1503
|
-
if (!widgetTree.children || widgetTree.children.length === 0) {
|
|
1504
|
-
return true; // Empty form is valid
|
|
1505
|
-
}
|
|
1506
|
-
// Check that all children are fieldset-layout widgets
|
|
1507
|
-
return widgetTree.children.every((child) => child.type === 'fieldset-layout' &&
|
|
1508
|
-
child.children &&
|
|
1509
|
-
child.children.every((formField) => formField.type === 'form-field' && formField.children && formField.children.length > 0));
|
|
1510
|
-
}
|
|
1511
|
-
/**
|
|
1512
|
-
* Clear all caches
|
|
1513
|
-
*/
|
|
1514
|
-
clearCaches() {
|
|
1515
|
-
this.widgetTreeCache.clear();
|
|
1516
|
-
this.formDefinitionCache.clear();
|
|
1517
|
-
}
|
|
1518
|
-
/**
|
|
1519
|
-
* Get cache statistics
|
|
1520
|
-
*/
|
|
1521
|
-
getCacheStats() {
|
|
1522
|
-
return {
|
|
1523
|
-
widgetTreeCacheSize: this.widgetTreeCache.size,
|
|
1524
|
-
formDefinitionCacheSize: this.formDefinitionCache.size,
|
|
1525
|
-
};
|
|
1526
|
-
}
|
|
1527
|
-
//#endregion
|
|
1528
|
-
//#region ---- Private Methods ----
|
|
1529
|
-
/**
|
|
1530
|
-
* Convert a single group to Fieldset widget structure
|
|
1531
|
-
*/
|
|
1532
|
-
createGroupAsFieldsetWidget(group) {
|
|
1533
|
-
// Determine columns count from layout or default to 1
|
|
1534
|
-
const columnsCount = 1;
|
|
1535
|
-
return {
|
|
1536
|
-
type: 'fieldset-layout',
|
|
1537
|
-
name: group.name,
|
|
1538
|
-
mode: group.mode,
|
|
1539
|
-
options: {
|
|
1540
|
-
title: group.title,
|
|
1541
|
-
description: group.description,
|
|
1542
|
-
cols: columnsCount,
|
|
1543
|
-
look: group.look || 'container', // Default to 'container' if not specified
|
|
1544
|
-
},
|
|
1545
|
-
children: this.createFieldWidgets(group.parameters, columnsCount),
|
|
1546
|
-
};
|
|
1547
|
-
}
|
|
1548
|
-
/**
|
|
1549
|
-
* Convert fields to Form Field widgets
|
|
1550
|
-
*/
|
|
1551
|
-
createFieldWidgets(fields, columnsCount) {
|
|
1552
|
-
return fields.map((field) => this.createFormFieldWidget(field));
|
|
1553
|
-
}
|
|
1554
|
-
/**
|
|
1555
|
-
* Convert a single field to Form Field widget with editor as child
|
|
1556
|
-
*/
|
|
1557
|
-
createFormFieldWidget(field) {
|
|
1558
|
-
return {
|
|
1559
|
-
type: 'form-field',
|
|
1560
|
-
name: field.path,
|
|
1561
|
-
options: {
|
|
1562
|
-
label: field.title,
|
|
1563
|
-
description: field.description,
|
|
1564
|
-
showLabel: true,
|
|
1565
|
-
},
|
|
1566
|
-
children: [field.widget], // The editor widget becomes a child of form-field
|
|
1567
|
-
};
|
|
1730
|
+
return this;
|
|
1568
1731
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1732
|
+
setDescription(description) {
|
|
1733
|
+
this.description = description;
|
|
1734
|
+
return this;
|
|
1735
|
+
}
|
|
1736
|
+
setSkippable(skippable) {
|
|
1737
|
+
this.skippable = skippable;
|
|
1738
|
+
return this;
|
|
1739
|
+
}
|
|
1740
|
+
content(delegate) {
|
|
1741
|
+
if (delegate) {
|
|
1742
|
+
// Create LayoutBuilder in injection context (will be called from component)
|
|
1743
|
+
const layoutBuilder = new LayoutBuilder();
|
|
1744
|
+
// ✅ IMPORTANT: Propagate inheritance context to content
|
|
1745
|
+
layoutBuilder.inheritanceContext = { ...this.inheritanceContext };
|
|
1746
|
+
delegate(layoutBuilder);
|
|
1747
|
+
this.contentNode = layoutBuilder.build();
|
|
1585
1748
|
}
|
|
1586
|
-
return
|
|
1587
|
-
name: fieldsetNode.name || `group-${Date.now()}`,
|
|
1588
|
-
title: fieldsetNode.options?.['title'],
|
|
1589
|
-
description: fieldsetNode.options?.['description'],
|
|
1590
|
-
parameters: fields,
|
|
1591
|
-
mode: fieldsetNode.mode,
|
|
1592
|
-
look: fieldsetNode.options?.['look'],
|
|
1593
|
-
};
|
|
1749
|
+
return this;
|
|
1594
1750
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1751
|
+
withInheritanceContext(context) {
|
|
1752
|
+
this.inheritanceContext = mergeInheritanceContext(context);
|
|
1753
|
+
return this;
|
|
1754
|
+
}
|
|
1755
|
+
build() {
|
|
1756
|
+
if (!this.contentNode) {
|
|
1757
|
+
throw new Error(`Step '${this.id}' must have content`);
|
|
1601
1758
|
}
|
|
1602
|
-
const editorWidget = formFieldNode.children[0];
|
|
1603
1759
|
return {
|
|
1604
|
-
|
|
1605
|
-
title:
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1760
|
+
id: this.id,
|
|
1761
|
+
title: this.title,
|
|
1762
|
+
icon: this.icon,
|
|
1763
|
+
description: this.description,
|
|
1764
|
+
skippable: this.skippable,
|
|
1765
|
+
content: this.contentNode,
|
|
1609
1766
|
};
|
|
1610
1767
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
|
|
1622
|
-
});
|
|
1623
|
-
});
|
|
1624
|
-
if (formDefinition.mode) {
|
|
1625
|
-
keyParts.push(`mode:${formDefinition.mode}`);
|
|
1626
|
-
}
|
|
1627
|
-
// Join with delimiter and create a shorter hash
|
|
1628
|
-
const keyString = keyParts.join('|');
|
|
1629
|
-
// If still too long, create a simple hash
|
|
1630
|
-
if (keyString.length > 100) {
|
|
1631
|
-
return this.createSimpleHash(keyString);
|
|
1632
|
-
}
|
|
1633
|
-
return keyString;
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Step Wizard Builder - Builds step wizard widget
|
|
1771
|
+
*/
|
|
1772
|
+
class StepWizardBuilder extends LayoutContainerMixin {
|
|
1773
|
+
constructor() {
|
|
1774
|
+
super('step-wizard');
|
|
1775
|
+
this.steps = [];
|
|
1776
|
+
this.linear = true;
|
|
1777
|
+
this.wizardDirection = 'horizontal';
|
|
1634
1778
|
}
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1779
|
+
setLinear(linear) {
|
|
1780
|
+
this.linear = linear;
|
|
1781
|
+
return this;
|
|
1782
|
+
}
|
|
1783
|
+
setDirection(direction) {
|
|
1784
|
+
this.wizardDirection = direction;
|
|
1785
|
+
return this;
|
|
1786
|
+
}
|
|
1787
|
+
setLook(look) {
|
|
1788
|
+
this.look = look;
|
|
1789
|
+
return this;
|
|
1790
|
+
}
|
|
1791
|
+
setShowActions(show) {
|
|
1792
|
+
this.showActions = show;
|
|
1793
|
+
return this;
|
|
1794
|
+
}
|
|
1795
|
+
setActions(actions) {
|
|
1796
|
+
this.wizardActions = actions;
|
|
1797
|
+
return this;
|
|
1798
|
+
}
|
|
1799
|
+
setGuards(guards) {
|
|
1800
|
+
this.guards = guards;
|
|
1801
|
+
return this;
|
|
1802
|
+
}
|
|
1803
|
+
setEvents(events) {
|
|
1804
|
+
this.events = events;
|
|
1805
|
+
return this;
|
|
1806
|
+
}
|
|
1807
|
+
step(id, title, delegate) {
|
|
1808
|
+
const stepBuilder = new StepBuilder(id, title);
|
|
1809
|
+
// ✅ IMPORTANT: Propagate inheritance context to step
|
|
1810
|
+
stepBuilder.withInheritanceContext(this.inheritanceContext);
|
|
1811
|
+
if (delegate) {
|
|
1812
|
+
delegate(stepBuilder);
|
|
1665
1813
|
}
|
|
1666
|
-
|
|
1814
|
+
this.steps.push(stepBuilder.build());
|
|
1815
|
+
return this;
|
|
1667
1816
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
let hash = 0;
|
|
1673
|
-
if (str.length === 0)
|
|
1674
|
-
return hash.toString();
|
|
1675
|
-
for (let i = 0; i < str.length; i++) {
|
|
1676
|
-
const char = str.charCodeAt(i);
|
|
1677
|
-
hash = (hash << 5) - hash + char;
|
|
1678
|
-
hash = hash & hash; // Convert to 32-bit integer
|
|
1817
|
+
build() {
|
|
1818
|
+
// ✅ Validation
|
|
1819
|
+
if (this.steps.length === 0) {
|
|
1820
|
+
throw new Error('StepWizard must have at least one step');
|
|
1679
1821
|
}
|
|
1680
|
-
|
|
1822
|
+
// ✅ Check duplicate IDs
|
|
1823
|
+
const ids = this.steps.map((s) => s.id);
|
|
1824
|
+
const duplicates = ids.filter((id, index) => ids.indexOf(id) !== index);
|
|
1825
|
+
if (duplicates.length > 0) {
|
|
1826
|
+
throw new Error(`Duplicate step IDs found: ${duplicates.join(', ')}`);
|
|
1827
|
+
}
|
|
1828
|
+
const definition = {
|
|
1829
|
+
steps: this.steps,
|
|
1830
|
+
linear: this.linear,
|
|
1831
|
+
direction: this.wizardDirection,
|
|
1832
|
+
look: this.look,
|
|
1833
|
+
// Do not auto-detect based on dialog context; keep explicit or undefined
|
|
1834
|
+
showActions: this.showActions,
|
|
1835
|
+
actions: this.wizardActions,
|
|
1836
|
+
guards: this.guards,
|
|
1837
|
+
events: this.events,
|
|
1838
|
+
};
|
|
1839
|
+
const node = {
|
|
1840
|
+
name: this.containerState.name,
|
|
1841
|
+
type: 'step-wizard',
|
|
1842
|
+
options: { definition },
|
|
1843
|
+
mode: this.containerState.mode,
|
|
1844
|
+
};
|
|
1845
|
+
return node;
|
|
1681
1846
|
}
|
|
1682
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1683
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
|
|
1684
1847
|
}
|
|
1685
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
|
|
1686
|
-
type: Injectable,
|
|
1687
|
-
args: [{
|
|
1688
|
-
providedIn: 'root',
|
|
1689
|
-
}]
|
|
1690
|
-
}] });
|
|
1691
1848
|
|
|
1692
1849
|
class AXPLayoutRendererComponent {
|
|
1693
1850
|
constructor() {
|
|
1694
|
-
this.evaluatorService = inject(AXPExpressionEvaluatorService);
|
|
1695
1851
|
this.conversionService = inject(AXPLayoutConversionService);
|
|
1696
|
-
/**
|
|
1697
|
-
* Tracks the latest scheduled evaluation to ensure last-write-wins for async evaluate
|
|
1698
|
-
*/
|
|
1699
|
-
this.evaluationRunId = 0;
|
|
1700
1852
|
/**
|
|
1701
1853
|
* RxJS subjects for context management
|
|
1702
1854
|
*/
|
|
1703
1855
|
this.contextUpdateSubject = new Subject();
|
|
1704
1856
|
this.contextChangeSubject = new Subject();
|
|
1705
|
-
/**
|
|
1706
|
-
* Cache for expression evaluation results
|
|
1707
|
-
*/
|
|
1708
|
-
this.expressionCache = new Map();
|
|
1709
|
-
/**
|
|
1710
|
-
* Cache for widget tree comparisons
|
|
1711
|
-
*/
|
|
1712
|
-
this.widgetTreeCache = new Map();
|
|
1713
|
-
/**
|
|
1714
|
-
* Last layout hash for change detection
|
|
1715
|
-
*/
|
|
1716
|
-
this.lastLayoutHash = '';
|
|
1717
1857
|
//#region ---- Inputs ----
|
|
1718
1858
|
/**
|
|
1719
1859
|
* Form definition containing groups and fields OR widget tree
|
|
@@ -1735,36 +1875,29 @@ class AXPLayoutRendererComponent {
|
|
|
1735
1875
|
//#region ---- Widget Tree Conversion ----
|
|
1736
1876
|
this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : []));
|
|
1737
1877
|
/**
|
|
1738
|
-
* Convert
|
|
1878
|
+
* Convert layout data to widget tree when inputs change
|
|
1739
1879
|
*/
|
|
1740
1880
|
this.conversionEffect = effect(() => {
|
|
1741
1881
|
const inputData = this.layout();
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
if (
|
|
1882
|
+
// Convert to widget tree
|
|
1883
|
+
let tree;
|
|
1884
|
+
if (this.isFormDefinition(inputData)) {
|
|
1885
|
+
// Convert form definition to widget tree
|
|
1886
|
+
tree = this.conversionService.convertFormDefinition(inputData);
|
|
1887
|
+
}
|
|
1888
|
+
else if (this.isWidgetNode(inputData)) {
|
|
1889
|
+
// Use widget tree directly
|
|
1890
|
+
tree = inputData;
|
|
1891
|
+
}
|
|
1892
|
+
else {
|
|
1893
|
+
console.warn('AXPLayoutRendererComponent: Invalid layout input. Expected AXPDynamicFormDefinition or AXPWidgetNode.', inputData);
|
|
1749
1894
|
return;
|
|
1750
1895
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
if (runId !== this.evaluationRunId) {
|
|
1757
|
-
return;
|
|
1758
|
-
}
|
|
1759
|
-
// Convert to widget tree (this will also apply the layout look)
|
|
1760
|
-
const tree = evaluated;
|
|
1761
|
-
// Update widget tree
|
|
1762
|
-
const prev = this.widgetTree();
|
|
1763
|
-
if (!isEqual(prev, tree)) {
|
|
1764
|
-
tree.mode = this.mode();
|
|
1765
|
-
this.widgetTree.set(tree);
|
|
1766
|
-
}
|
|
1767
|
-
})();
|
|
1896
|
+
// Update widget tree only if changed (Angular effect already prevents unnecessary runs)
|
|
1897
|
+
const prev = this.widgetTree();
|
|
1898
|
+
if (!isEqual(prev, tree)) {
|
|
1899
|
+
this.widgetTree.set(tree);
|
|
1900
|
+
}
|
|
1768
1901
|
}, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : []));
|
|
1769
1902
|
//#endregion
|
|
1770
1903
|
//#region ---- Outputs ----
|
|
@@ -1807,32 +1940,6 @@ class AXPLayoutRendererComponent {
|
|
|
1807
1940
|
}
|
|
1808
1941
|
}, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : []));
|
|
1809
1942
|
}
|
|
1810
|
-
async expressionEvaluator(expression, context) {
|
|
1811
|
-
// Check if it's a form definition that needs conversion
|
|
1812
|
-
if (this.isFormDefinition(expression)) {
|
|
1813
|
-
return this.conversionService.convertFormDefinition(expression);
|
|
1814
|
-
}
|
|
1815
|
-
// Generate cache key using a more efficient method
|
|
1816
|
-
const cacheKey = this.generateCacheKey(expression, context);
|
|
1817
|
-
// Check cache first
|
|
1818
|
-
if (this.expressionCache.has(cacheKey)) {
|
|
1819
|
-
return this.expressionCache.get(cacheKey);
|
|
1820
|
-
}
|
|
1821
|
-
const scope = {
|
|
1822
|
-
context: {
|
|
1823
|
-
eval: (path) => get(context, path),
|
|
1824
|
-
},
|
|
1825
|
-
};
|
|
1826
|
-
const result = await this.evaluatorService.evaluate(expression, scope);
|
|
1827
|
-
// Cache result with LRU-like behavior
|
|
1828
|
-
if (this.expressionCache.size > 50) {
|
|
1829
|
-
// Clear half the cache when it gets too large
|
|
1830
|
-
const keysToDelete = Array.from(this.expressionCache.keys()).slice(0, 25);
|
|
1831
|
-
keysToDelete.forEach((key) => this.expressionCache.delete(key));
|
|
1832
|
-
}
|
|
1833
|
-
this.expressionCache.set(cacheKey, result);
|
|
1834
|
-
return result;
|
|
1835
|
-
}
|
|
1836
1943
|
//#endregion
|
|
1837
1944
|
//#region ---- Lifecycle Methods ----
|
|
1838
1945
|
ngOnInit() {
|
|
@@ -1965,55 +2072,11 @@ class AXPLayoutRendererComponent {
|
|
|
1965
2072
|
isFormDefinition(data) {
|
|
1966
2073
|
return data && typeof data === 'object' && 'groups' in data && Array.isArray(data.groups);
|
|
1967
2074
|
}
|
|
1968
|
-
//#endregion
|
|
1969
|
-
//#region ---- Utility Methods ----
|
|
1970
|
-
/**
|
|
1971
|
-
* Generate layout hash for change detection (short hash)
|
|
1972
|
-
*/
|
|
1973
|
-
generateLayoutHash(layout, look) {
|
|
1974
|
-
if (!layout)
|
|
1975
|
-
return '';
|
|
1976
|
-
// Generate short hash for large layout strings
|
|
1977
|
-
const layoutStr = typeof layout === 'string' ? layout : JSON.stringify(layout);
|
|
1978
|
-
const layoutHash = this.simpleHash(layoutStr);
|
|
1979
|
-
return `${layoutHash}|${look}`;
|
|
1980
|
-
}
|
|
1981
|
-
/**
|
|
1982
|
-
* Generate cache key for expression evaluation (short hash)
|
|
1983
|
-
*/
|
|
1984
|
-
generateCacheKey(expression, context) {
|
|
1985
|
-
// Use short hash for better performance
|
|
1986
|
-
const exprStr = typeof expression === 'string' ? expression : JSON.stringify(expression);
|
|
1987
|
-
const exprHash = this.simpleHash(exprStr);
|
|
1988
|
-
const ctxHash = this.generateContextHash(context);
|
|
1989
|
-
return `${exprHash}|${ctxHash}`;
|
|
1990
|
-
}
|
|
1991
|
-
/**
|
|
1992
|
-
* Generate a simple hash for context change detection
|
|
1993
|
-
*/
|
|
1994
|
-
generateContextHash(context) {
|
|
1995
|
-
if (!context || typeof context !== 'object') {
|
|
1996
|
-
return String(context);
|
|
1997
|
-
}
|
|
1998
|
-
// Generate short hash for context
|
|
1999
|
-
const keys = Object.keys(context).sort();
|
|
2000
|
-
const contextStr = keys.map((key) => `${key}:${context[key]}`).join('|');
|
|
2001
|
-
return this.simpleHash(contextStr);
|
|
2002
|
-
}
|
|
2003
2075
|
/**
|
|
2004
|
-
*
|
|
2076
|
+
* Type guard to check if the input is a widget node
|
|
2005
2077
|
*/
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
if (str.length === 0)
|
|
2009
|
-
return hash.toString();
|
|
2010
|
-
for (let i = 0; i < str.length; i++) {
|
|
2011
|
-
const char = str.charCodeAt(i);
|
|
2012
|
-
hash = (hash << 5) - hash + char;
|
|
2013
|
-
hash = hash & hash; // Convert to 32-bit integer
|
|
2014
|
-
}
|
|
2015
|
-
// Convert to positive hex string
|
|
2016
|
-
return Math.abs(hash).toString(16);
|
|
2078
|
+
isWidgetNode(data) {
|
|
2079
|
+
return data && typeof data === 'object' && 'type' in data && typeof data.type === 'string';
|
|
2017
2080
|
}
|
|
2018
2081
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2019
2082
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.12", type: AXPLayoutRendererComponent, isStandalone: true, selector: "axp-layout-renderer", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: true, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, look: { classPropertyName: "look", publicName: "look", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { context: "contextChange", contextInitiated: "contextInitiated", validityChange: "validityChange" }, viewQueries: [{ propertyName: "form", first: true, predicate: AXFormComponent, descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: AXPWidgetContainerComponent, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
@@ -2024,7 +2087,7 @@ class AXPLayoutRendererComponent {
|
|
|
2024
2087
|
}
|
|
2025
2088
|
</axp-widgets-container>
|
|
2026
2089
|
</ax-form>
|
|
2027
|
-
`, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i2.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2090
|
+
`, isInline: true, styles: [":host{display:block;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: AXPWidgetCoreModule }, { kind: "component", type: i1.AXPWidgetContainerComponent, selector: "axp-widgets-container", inputs: ["context", "functions"], outputs: ["onContextChanged"] }, { kind: "directive", type: i1.AXPWidgetRendererDirective, selector: "[axp-widget-renderer]", inputs: ["parentNode", "index", "mode", "node"], outputs: ["onOptionsChanged", "onValueChanged", "onLoad"], exportAs: ["widgetRenderer"] }, { kind: "ngmodule", type: AXFormModule }, { kind: "component", type: i2.AXFormComponent, selector: "ax-form", inputs: ["disabled", "readonly", "labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2028
2091
|
}
|
|
2029
2092
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
|
|
2030
2093
|
type: Component,
|