@acorex/platform 20.3.0-next.2 → 20.3.0-next.20
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/common/index.d.ts +403 -374
- package/core/index.d.ts +563 -46
- package/fesm2022/acorex-platform-auth.mjs +19 -19
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/acorex-platform-common.mjs +124 -224
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +644 -110
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +16 -16
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +1927 -1951
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +3897 -435
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +96 -89
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity-create-entity.command-BXExgI3W.mjs +52 -0
- package/fesm2022/acorex-platform-layout-entity-create-entity.command-BXExgI3W.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity.mjs +1763 -1233
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +43 -33
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +2756 -0
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-button-widget-designer.component-C2Qn1YAW.mjs → acorex-platform-layout-widgets-button-widget-designer.component-BzsfTNs2.mjs} +6 -6
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-BzsfTNs2.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-extra-properties-schema-widget-edit.component-D9mf08rU.mjs → acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-Dvk76-2W.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-Dvk76-2W.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-extra-properties-schema-widget-view.component-D6GQ-eyr.mjs → acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-BYLaipWi.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-BYLaipWi.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-extra-properties-values-widget-edit.component-DVbIdVZ6.mjs → acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-DcSllNik.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-DcSllNik.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-extra-properties-values-widget-view.component-D-aM64Hu.mjs → acorex-platform-layout-widgets-extra-properties-values-widget-view.component-BT-U4BiA.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-BT-U4BiA.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-extra-properties-widget-edit.component-em2-aU8E.mjs → acorex-platform-layout-widgets-extra-properties-widget-edit.component-Il7jnRBg.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-Il7jnRBg.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-extra-properties-widget-view.component-BeuIofdr.mjs → acorex-platform-layout-widgets-extra-properties-widget-view.component-CBEPu7Fl.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-CBEPu7Fl.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-file-list-popup.component-rW2RD35f.mjs → acorex-platform-layout-widgets-file-list-popup.component-BPzn8lr3.mjs} +10 -10
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-BPzn8lr3.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-page-widget-designer.component-DNvnQ4Mc.mjs → acorex-platform-layout-widgets-page-widget-designer.component-C_JrGoXy.mjs} +8 -8
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-C_JrGoXy.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-tabular-data-edit-popup.component-CPVRbE8B.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-C6DaBt_N.mjs} +14 -14
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-C6DaBt_N.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-tabular-data-view-popup.component-Dmg5DdX8.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-Bth3jI9T.mjs} +6 -5
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-Bth3jI9T.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-text-block-widget-designer.component-yADN3Xji.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-CUHptbP4.mjs} +6 -7
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-CUHptbP4.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets.mjs → acorex-platform-layout-widgets.mjs} +8362 -7479
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -0
- package/fesm2022/acorex-platform-native.mjs +7 -7
- package/fesm2022/acorex-platform-native.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +40 -40
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-eGzN6g2Y.mjs +115 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-eGzN6g2Y.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-list-view.component-X0hLRZhX.mjs → acorex-platform-themes-default-entity-master-list-view.component-nDHfQQ3O.mjs} +34 -36
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-nDHfQQ3O.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-HJyalvcu.mjs +101 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-HJyalvcu.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-BExtm1JE.mjs → acorex-platform-themes-default-entity-master-single-view.component-e7m70Wls.mjs} +17 -17
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-e7m70Wls.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-error-401.component-DrO1PEOH.mjs → acorex-platform-themes-default-error-401.component-CoBaQFTn.mjs} +4 -4
- package/fesm2022/{acorex-platform-themes-default-error-401.component-DrO1PEOH.mjs.map → acorex-platform-themes-default-error-401.component-CoBaQFTn.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-themes-default-error-404.component-DqVq0oHX.mjs → acorex-platform-themes-default-error-404.component-BLlVOsS2.mjs} +4 -4
- package/fesm2022/{acorex-platform-themes-default-error-404.component-DqVq0oHX.mjs.map → acorex-platform-themes-default-error-404.component-BLlVOsS2.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-themes-default-error-offline.component-Bt2PTL7_.mjs → acorex-platform-themes-default-error-offline.component-CybYQI9F.mjs} +4 -4
- package/fesm2022/{acorex-platform-themes-default-error-offline.component-Bt2PTL7_.mjs.map → acorex-platform-themes-default-error-offline.component-CybYQI9F.mjs.map} +1 -1
- package/fesm2022/acorex-platform-themes-default.mjs +45 -45
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-KpZWpnOJ.mjs → acorex-platform-themes-shared-icon-chooser-view.component-ReKSoVeN.mjs} +25 -15
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-ReKSoVeN.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-settings.provider-CXiRmniv.mjs → acorex-platform-themes-shared-settings.provider-DY2xFnrv.mjs} +9 -9
- package/fesm2022/acorex-platform-themes-shared-settings.provider-DY2xFnrv.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-column.component-BvOiVCgt.mjs → acorex-platform-themes-shared-theme-color-chooser-column.component-B2HDyY2z.mjs} +24 -9
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-B2HDyY2z.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-view.component-BW0rfkjk.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-CeZxa49U.mjs} +24 -9
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-CeZxa49U.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +264 -86
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +27 -39
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/layout/builder/README.md +2 -3
- package/layout/builder/index.d.ts +683 -819
- package/layout/components/index.d.ts +1141 -115
- package/layout/designer/index.d.ts +8 -6
- package/layout/entity/index.d.ts +979 -282
- package/layout/views/index.d.ts +13 -13
- package/layout/widget-core/README.md +4 -0
- package/layout/widget-core/index.d.ts +957 -0
- package/layout/widgets/README.md +4 -0
- package/{widgets → layout/widgets}/index.d.ts +1933 -770
- package/package.json +14 -10
- package/themes/shared/index.d.ts +2 -2
- package/workflow/index.d.ts +3 -173
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-BXbkGGei.mjs +0 -115
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-BXbkGGei.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-X0hLRZhX.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Bp1JLsj1.mjs +0 -101
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Bp1JLsj1.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-BExtm1JE.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-KpZWpnOJ.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-settings.provider-CXiRmniv.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-BvOiVCgt.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BW0rfkjk.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-button-widget-designer.component-C2Qn1YAW.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-checkbox-widget-column.component-CzEFmKWG.mjs +0 -84
- package/fesm2022/acorex-platform-widgets-checkbox-widget-column.component-CzEFmKWG.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-JC_nYunG.mjs +0 -55
- package/fesm2022/acorex-platform-widgets-checkbox-widget-designer.component-JC_nYunG.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-checkbox-widget-view.component-C-4bWr9G.mjs +0 -76
- package/fesm2022/acorex-platform-widgets-checkbox-widget-view.component-C-4bWr9G.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-color-box-widget-designer.component-CxgKO2VI.mjs +0 -55
- package/fesm2022/acorex-platform-widgets-color-box-widget-designer.component-CxgKO2VI.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-edit.component-D9mf08rU.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-extra-properties-schema-widget-view.component-D6GQ-eyr.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-edit.component-DVbIdVZ6.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-extra-properties-values-widget-view.component-D-aM64Hu.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-extra-properties-widget-edit.component-em2-aU8E.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-extra-properties-widget-view.component-BeuIofdr.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-file-list-popup.component-rW2RD35f.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-file-rename-popup.component-DHFMnkls.mjs +0 -211
- package/fesm2022/acorex-platform-widgets-file-rename-popup.component-DHFMnkls.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-page-widget-designer.component-DNvnQ4Mc.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-rich-text-popup.component-Cydlpsat.mjs +0 -40
- package/fesm2022/acorex-platform-widgets-rich-text-popup.component-Cydlpsat.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-tabular-data-edit-popup.component-CPVRbE8B.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-tabular-data-view-popup.component-Dmg5DdX8.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets-text-block-widget-designer.component-yADN3Xji.mjs.map +0 -1
- package/fesm2022/acorex-platform-widgets.mjs.map +0 -1
- package/widgets/README.md +0 -4
|
@@ -1,2104 +1,2080 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { signal, computed, Injectable, InjectionToken, inject, ElementRef, effect, Injector, ChangeDetectorRef, ViewChild, Input, ChangeDetectionStrategy, Component, EventEmitter, Output, input, output, ViewContainerRef, Directive, Optional, Inject, NgModule } from '@angular/core';
|
|
3
|
-
import { convertArrayToDataSource, AXDataSource } from '@acorex/cdk/common';
|
|
4
|
-
import { setSmart, AXPDataSourceDefinitionProviderService, extractValue, getSmart, AXPExpressionEvaluatorService } from '@acorex/platform/core';
|
|
5
|
-
import { set, cloneDeep, isEqual, get, merge, isNil, isUndefined, isObjectLike, sum, isEmpty, isString } from 'lodash-es';
|
|
6
|
-
import { Subject, BehaviorSubject, filter } from 'rxjs';
|
|
7
|
-
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
|
8
|
-
import * as i1$1 from '@acorex/components/skeleton';
|
|
9
|
-
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
10
|
-
import * as i2 from '@acorex/core/translation';
|
|
11
|
-
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
12
|
-
import { PortalModule } from '@angular/cdk/portal';
|
|
13
|
-
import * as i1 from '@angular/common';
|
|
1
|
+
import * as i1$1 from '@angular/common';
|
|
14
2
|
import { CommonModule } from '@angular/common';
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
AXPPageStatus["Error"] = "error";
|
|
35
|
-
})(AXPPageStatus || (AXPPageStatus = {}));
|
|
36
|
-
var AXPWidgetStatus;
|
|
37
|
-
(function (AXPWidgetStatus) {
|
|
38
|
-
// Rendering statuses
|
|
39
|
-
AXPWidgetStatus["Rendering"] = "rendering";
|
|
40
|
-
AXPWidgetStatus["Rendered"] = "rendered";
|
|
41
|
-
// Processing statuses
|
|
42
|
-
AXPWidgetStatus["Processing"] = "processing";
|
|
43
|
-
// Error handling
|
|
44
|
-
AXPWidgetStatus["Error"] = "error";
|
|
45
|
-
})(AXPWidgetStatus || (AXPWidgetStatus = {}));
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, Injectable, input, model, signal, effect, output, viewChild, ChangeDetectionStrategy, Component, NgModule, EventEmitter, Output, Input } from '@angular/core';
|
|
5
|
+
import { AXPopupService } from '@acorex/components/popup';
|
|
6
|
+
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
7
|
+
import { AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
8
|
+
import * as i2 from '@acorex/components/form';
|
|
9
|
+
import { AXFormComponent, AXFormModule } from '@acorex/components/form';
|
|
10
|
+
import { isEqual, get, cloneDeep } from 'lodash-es';
|
|
11
|
+
import { AXPExpressionEvaluatorService } from '@acorex/platform/core';
|
|
12
|
+
import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
|
|
13
|
+
import * as i2$1 from '@acorex/components/button';
|
|
14
|
+
import { AXButtonModule } from '@acorex/components/button';
|
|
15
|
+
import * as i3 from '@acorex/components/decorators';
|
|
16
|
+
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
17
|
+
import * as i4 from '@acorex/components/loading';
|
|
18
|
+
import { AXLoadingModule } from '@acorex/components/loading';
|
|
19
|
+
import { AXBasePageComponent } from '@acorex/components/page';
|
|
20
|
+
import * as i5 from '@acorex/core/translation';
|
|
21
|
+
import { AXTranslationModule } from '@acorex/core/translation';
|
|
46
22
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
23
|
+
//#region ---- Inheritance Utilities ----
|
|
24
|
+
/**
|
|
25
|
+
* Resolves inherited properties from context and local values
|
|
26
|
+
*/
|
|
27
|
+
function resolveInheritedProperties(context, localValues = {}) {
|
|
28
|
+
return {
|
|
29
|
+
mode: localValues.mode ?? context.mode ?? 'edit',
|
|
30
|
+
disabled: localValues.disabled ?? context.disabled,
|
|
31
|
+
readonly: localValues.readonly ?? context.readonly,
|
|
32
|
+
direction: localValues.direction ?? context.direction,
|
|
33
|
+
visible: localValues.visible ?? context.visible,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Merges inheritance context with local overrides
|
|
38
|
+
*/
|
|
39
|
+
function mergeInheritanceContext(parentContext, localOverrides = {}) {
|
|
40
|
+
return {
|
|
41
|
+
...parentContext,
|
|
42
|
+
...localOverrides,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Generates a random string for path/name generation
|
|
47
|
+
*/
|
|
48
|
+
function generateRandomId() {
|
|
49
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Converts label to a valid path/name
|
|
53
|
+
*/
|
|
54
|
+
function labelToPath(label) {
|
|
55
|
+
return label
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.replace(/[^a-z0-9\s]/g, '') // Remove special characters
|
|
58
|
+
.replace(/\s+/g, '_') // Replace spaces with underscores
|
|
59
|
+
.substring(0, 50); // Limit length
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Generates path for value widgets based on hierarchy
|
|
63
|
+
*/
|
|
64
|
+
function generateValueWidgetPath(widgetName, formFieldName, formFieldLabel) {
|
|
65
|
+
// Priority: widget name -> form field name -> generated from label -> random
|
|
66
|
+
if (widgetName) {
|
|
67
|
+
return widgetName;
|
|
68
|
+
}
|
|
69
|
+
if (formFieldName) {
|
|
70
|
+
return formFieldName;
|
|
50
71
|
}
|
|
72
|
+
if (formFieldLabel) {
|
|
73
|
+
return labelToPath(formFieldLabel);
|
|
74
|
+
}
|
|
75
|
+
return generateRandomId();
|
|
51
76
|
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region ---- Service Implementation ----
|
|
52
79
|
class AXPLayoutBuilderService {
|
|
53
80
|
constructor() {
|
|
54
|
-
this.
|
|
55
|
-
this.functions$ = signal({}, ...(ngDevMode ? [{ debugName: "functions$" }] : []));
|
|
56
|
-
this.onRefresh = new Subject();
|
|
57
|
-
this.widgets = new Map();
|
|
58
|
-
this.onWidgetRegistered = new Subject();
|
|
59
|
-
this.status$ = signal(AXPPageStatus.Rendering, ...(ngDevMode ? [{ debugName: "status$" }] : []));
|
|
60
|
-
this.status = this.status$.asReadonly();
|
|
61
|
-
this.isBusy = computed(() => {
|
|
62
|
-
return [AXPPageStatus.Processing, AXPPageStatus.Submitting, AXPPageStatus.Rendering].includes(this.status());
|
|
63
|
-
}, ...(ngDevMode ? [{ debugName: "isBusy" }] : []));
|
|
64
|
-
}
|
|
65
|
-
get variables() {
|
|
66
|
-
return this.variables$();
|
|
67
|
-
}
|
|
68
|
-
get functions() {
|
|
69
|
-
return this.functions$();
|
|
70
|
-
}
|
|
71
|
-
updateStatus() {
|
|
72
|
-
this.status$.update(() => this.detectStatus());
|
|
73
|
-
}
|
|
74
|
-
detectStatus() {
|
|
75
|
-
const statuses = Array.from(this.widgets.values()).map((c) => c.status());
|
|
76
|
-
// Rendering statuses
|
|
77
|
-
if (statuses.some((status) => status === AXPWidgetStatus.Rendering)) {
|
|
78
|
-
return AXPPageStatus.Rendering;
|
|
79
|
-
}
|
|
80
|
-
if (statuses.every((status) => status === AXPWidgetStatus.Rendered)) {
|
|
81
|
-
return AXPPageStatus.Rendered;
|
|
82
|
-
}
|
|
83
|
-
// Processing statuses
|
|
84
|
-
if (statuses.some((status) => status === AXPWidgetStatus.Processing)) {
|
|
85
|
-
return AXPPageStatus.Processing;
|
|
86
|
-
}
|
|
87
|
-
// Error handling
|
|
88
|
-
if (statuses.some((status) => status === AXPWidgetStatus.Error)) {
|
|
89
|
-
return AXPPageStatus.Error;
|
|
90
|
-
}
|
|
91
|
-
return AXPPageStatus.Rendered; // Default to Loaded when all widgets are in a completed state
|
|
92
|
-
}
|
|
93
|
-
refresh() {
|
|
94
|
-
setTimeout(() => {
|
|
95
|
-
this.onRefresh.next();
|
|
96
|
-
}, 0);
|
|
97
|
-
}
|
|
98
|
-
setStatus(status) {
|
|
99
|
-
this.status$.set(status);
|
|
100
|
-
}
|
|
101
|
-
setVariables(...args) {
|
|
102
|
-
if (args.length == 0)
|
|
103
|
-
return;
|
|
104
|
-
else if (args.length == 1)
|
|
105
|
-
this.variables$.set(args[0]);
|
|
106
|
-
else if (args.length == 2) {
|
|
107
|
-
this.variables$.update((v) => set(v, args[0], args[1]));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
setFunctions(...args) {
|
|
111
|
-
if (args.length == 0)
|
|
112
|
-
return;
|
|
113
|
-
else if (args.length == 1)
|
|
114
|
-
this.functions$.set(args[0]);
|
|
115
|
-
else if (args.length == 2) {
|
|
116
|
-
this.functions$.update((v) => set(v, args[0], args[1]));
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
registerWidget(id, widget) {
|
|
120
|
-
this.widgets.set(id, widget);
|
|
121
|
-
this.onWidgetRegistered.next({ id, widget });
|
|
122
|
-
}
|
|
123
|
-
getWidget(id) {
|
|
124
|
-
return this.widgets.get(id);
|
|
81
|
+
this.popupService = inject(AXPopupService);
|
|
125
82
|
}
|
|
126
83
|
/**
|
|
127
|
-
*
|
|
128
|
-
* If the widget is already registered, resolves immediately.
|
|
129
|
-
* Optionally accepts a timeout (in ms) after which it resolves with undefined.
|
|
84
|
+
* Create a new layout builder
|
|
130
85
|
*/
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (existing) {
|
|
134
|
-
return existing;
|
|
135
|
-
}
|
|
136
|
-
return new Promise((resolve) => {
|
|
137
|
-
let resolved = false;
|
|
138
|
-
let timer = null;
|
|
139
|
-
const sub = this.onWidgetRegistered.subscribe(({ id: registeredId, widget }) => {
|
|
140
|
-
if (registeredId === id && !resolved) {
|
|
141
|
-
resolved = true;
|
|
142
|
-
sub.unsubscribe();
|
|
143
|
-
if (timer) {
|
|
144
|
-
clearTimeout(timer);
|
|
145
|
-
}
|
|
146
|
-
resolve(widget);
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
if (timeoutMs != null && timeoutMs > 0) {
|
|
150
|
-
timer = setTimeout(() => {
|
|
151
|
-
if (!resolved) {
|
|
152
|
-
resolved = true;
|
|
153
|
-
sub.unsubscribe();
|
|
154
|
-
resolve(undefined);
|
|
155
|
-
}
|
|
156
|
-
}, timeoutMs);
|
|
157
|
-
}
|
|
158
|
-
});
|
|
86
|
+
create() {
|
|
87
|
+
return new LayoutBuilder(this.popupService);
|
|
159
88
|
}
|
|
160
|
-
|
|
161
|
-
static { this.ɵ
|
|
162
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPLayoutBuilderService }); }
|
|
89
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
90
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutBuilderService, providedIn: 'root' }); }
|
|
163
91
|
}
|
|
164
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
165
|
-
type: Injectable
|
|
92
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutBuilderService, decorators: [{
|
|
93
|
+
type: Injectable,
|
|
94
|
+
args: [{
|
|
95
|
+
providedIn: 'root',
|
|
96
|
+
}]
|
|
166
97
|
}] });
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
})),
|
|
181
|
-
// Computed Signals
|
|
182
|
-
withComputed(({ data, state, lastChange, initialSnapshot, previousSnapshot }) => ({
|
|
183
|
-
isChanged: computed(() => state() === 'changed'),
|
|
184
|
-
isReset: computed(() => state() === 'restored'),
|
|
185
|
-
isInitiated: computed(() => state() === 'initiated'),
|
|
186
|
-
isEmpty: computed(() => Object.keys(data()).length === 0),
|
|
187
|
-
isDirty: computed(() => !isEqual(data(), previousSnapshot())),
|
|
188
|
-
snapshot: computed(() => cloneDeep(data())), // Current data snapshot
|
|
189
|
-
initial: computed(() => cloneDeep(initialSnapshot())), // Initial snapshot
|
|
190
|
-
previous: computed(() => cloneDeep(previousSnapshot())), // Previous snapshot
|
|
191
|
-
changeEvent: computed(() => lastChange()), // Reactive last change event
|
|
192
|
-
})),
|
|
193
|
-
// Methods for State Management
|
|
194
|
-
withMethods((store) => ({
|
|
195
|
-
// Update a specific value
|
|
196
|
-
update(path, value) {
|
|
197
|
-
const currentData = cloneDeep(store.data());
|
|
198
|
-
const oldValue = get(currentData, path);
|
|
199
|
-
// Skip if the value hasn't changed
|
|
200
|
-
if (isEqual(oldValue, value)) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
// Update the value and prepare the change event
|
|
204
|
-
const updatedData = setSmart(currentData, path, value);
|
|
205
|
-
const changeEvent = {
|
|
206
|
-
oldValue,
|
|
207
|
-
newValue: value,
|
|
208
|
-
path,
|
|
209
|
-
state: 'changed',
|
|
210
|
-
data: updatedData,
|
|
211
|
-
};
|
|
212
|
-
// Patch the state
|
|
213
|
-
patchState(store, {
|
|
214
|
-
previousSnapshot: store.snapshot(), // Save the previous state
|
|
215
|
-
data: updatedData,
|
|
216
|
-
state: 'changed',
|
|
217
|
-
lastChange: changeEvent,
|
|
218
|
-
});
|
|
219
|
-
},
|
|
220
|
-
patch(context) {
|
|
221
|
-
const currentData = cloneDeep(store.data());
|
|
222
|
-
// Update the value and prepare the change event
|
|
223
|
-
const updatedData = { ...currentData, ...context };
|
|
224
|
-
const changeEvent = {
|
|
225
|
-
state: 'patch',
|
|
226
|
-
data: updatedData,
|
|
227
|
-
};
|
|
228
|
-
// Patch the state
|
|
229
|
-
patchState(store, {
|
|
230
|
-
previousSnapshot: store.snapshot(), // Save the previous state
|
|
231
|
-
data: updatedData,
|
|
232
|
-
state: 'changed',
|
|
233
|
-
lastChange: changeEvent,
|
|
234
|
-
});
|
|
235
|
-
},
|
|
236
|
-
// Reset to the initial state
|
|
237
|
-
reset() {
|
|
238
|
-
const initialData = store.initial();
|
|
239
|
-
const changeEvent = {
|
|
240
|
-
oldValue: cloneDeep(store.data()), // Current data becomes old value
|
|
241
|
-
newValue: cloneDeep(initialData), // Reset to the initial state
|
|
242
|
-
path: '',
|
|
243
|
-
state: 'restored',
|
|
244
|
-
data: initialData,
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region ---- Layout Builder Implementation ----
|
|
100
|
+
/**
|
|
101
|
+
* Main layout builder - Single Responsibility: Layout orchestration
|
|
102
|
+
* Open/Closed: Extensible through container delegates
|
|
103
|
+
*/
|
|
104
|
+
class LayoutBuilder {
|
|
105
|
+
constructor(popupService) {
|
|
106
|
+
this.popupService = popupService;
|
|
107
|
+
this.root = {
|
|
108
|
+
children: [],
|
|
109
|
+
mode: 'edit',
|
|
110
|
+
type: 'flex-layout',
|
|
245
111
|
};
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
data: initialData,
|
|
249
|
-
state: 'restored',
|
|
250
|
-
lastChange: changeEvent,
|
|
251
|
-
});
|
|
252
|
-
},
|
|
253
|
-
// Initialize the state
|
|
254
|
-
set(initialData) {
|
|
255
|
-
const currentData = store.data();
|
|
256
|
-
if (isEqual(currentData, initialData)) {
|
|
257
|
-
return; // Skip if the current state matches the initial state
|
|
258
|
-
}
|
|
259
|
-
const changeEvent = {
|
|
260
|
-
oldValue: null,
|
|
261
|
-
newValue: cloneDeep(initialData),
|
|
262
|
-
path: '',
|
|
263
|
-
state: 'initiated',
|
|
264
|
-
data: initialData,
|
|
112
|
+
this.inheritanceContext = {
|
|
113
|
+
mode: 'edit',
|
|
265
114
|
};
|
|
266
|
-
patchState(store, {
|
|
267
|
-
initialSnapshot: cloneDeep(initialData), // Save the initial state
|
|
268
|
-
previousSnapshot: store.snapshot(), // Save the current state as the previous
|
|
269
|
-
data: initialData,
|
|
270
|
-
state: 'initiated',
|
|
271
|
-
lastChange: changeEvent,
|
|
272
|
-
});
|
|
273
|
-
},
|
|
274
|
-
// Get a specific value
|
|
275
|
-
getValue(path) {
|
|
276
|
-
return get(store.data(), path);
|
|
277
|
-
},
|
|
278
|
-
})));
|
|
279
|
-
|
|
280
|
-
const AXPWidgetsCatalog = {
|
|
281
|
-
timeDuration: 'time-duration',
|
|
282
|
-
tagable: 'tagable-editor',
|
|
283
|
-
checkbox: 'checkbox-editor',
|
|
284
|
-
color: 'color-editor',
|
|
285
|
-
contact: 'contact-editor',
|
|
286
|
-
dateTime: 'date-time-editor',
|
|
287
|
-
email: 'email-editor',
|
|
288
|
-
largeText: 'large-text-editor',
|
|
289
|
-
link: 'link-editor',
|
|
290
|
-
number: 'number-editor',
|
|
291
|
-
numberUnit: 'number-unit-editor',
|
|
292
|
-
password: 'password-editor',
|
|
293
|
-
phone: 'phone-editor',
|
|
294
|
-
richText: 'rich-text-editor',
|
|
295
|
-
select: 'select-editor',
|
|
296
|
-
selectionList: 'selection-list-editor',
|
|
297
|
-
text: 'text-editor',
|
|
298
|
-
table: 'table-editor',
|
|
299
|
-
toggle: 'toggle-editor',
|
|
300
|
-
blockLayout: 'block-layout',
|
|
301
|
-
pageLayout: 'page-layout',
|
|
302
|
-
repeaterLayout: 'repeater-layout',
|
|
303
|
-
textBlockLayout: 'text-block-layout',
|
|
304
|
-
fileUploader: 'file-uploader',
|
|
305
|
-
fileTypeExtension: 'file-type-extension',
|
|
306
|
-
map: 'map',
|
|
307
|
-
imageMarker: 'image-marker',
|
|
308
|
-
image: 'image',
|
|
309
|
-
gallery: 'gallery',
|
|
310
|
-
signature: 'signature',
|
|
311
|
-
buttonAction: 'button-action',
|
|
312
|
-
document: 'document-layout',
|
|
313
|
-
lookup: 'lookup-editor',
|
|
314
|
-
formField: 'form-field',
|
|
315
|
-
qrcode: 'qrcode',
|
|
316
|
-
advancedGrid: 'advanced-grid-layout',
|
|
317
|
-
advancedGridItem: 'advanced-grid-item-layout',
|
|
318
|
-
grid: 'grid-layout',
|
|
319
|
-
gridItem: 'grid-item-layout',
|
|
320
|
-
gridRow: 'grid-row-layout',
|
|
321
|
-
widgetSelector: 'widget-selector',
|
|
322
|
-
template: 'template',
|
|
323
|
-
templateDesigner: 'template-designer',
|
|
324
|
-
cronJob: 'cron-job',
|
|
325
|
-
spacing: 'spacing',
|
|
326
|
-
direction: 'direction',
|
|
327
|
-
border: 'border',
|
|
328
|
-
flexLayout: 'flex-layout',
|
|
329
|
-
flexItem: 'flex-item-layout',
|
|
330
|
-
avatar: 'avatar',
|
|
331
|
-
themePaletteChooser: 'theme-palette-chooser',
|
|
332
|
-
themeModeChooser: 'theme-mode-chooser',
|
|
333
|
-
menuOrientationChooser: 'menu-orientation-chooser',
|
|
334
|
-
fontStyleChooser: 'font-style-chooser',
|
|
335
|
-
fontSizeChooser: 'font-size-chooser',
|
|
336
|
-
iconChooser: 'icon-chooser',
|
|
337
|
-
themeColorChooser: 'theme-color-chooser',
|
|
338
|
-
gridOptions: 'grid-options',
|
|
339
|
-
gridItemOptions: 'grid-item-options',
|
|
340
|
-
advancedGridOptions: 'advanced-grid-options',
|
|
341
|
-
stringFilter: 'string-filter',
|
|
342
|
-
numberFilter: 'number-filter',
|
|
343
|
-
dateTimeFilter: 'datetime-filter',
|
|
344
|
-
booleanFilter: 'boolean-filter',
|
|
345
|
-
lookupFilter: 'lookup-filter',
|
|
346
|
-
flexOptions: 'flex-options',
|
|
347
|
-
flexItemOptions: 'flex-item-options',
|
|
348
|
-
selectFilter: 'select-filter',
|
|
349
|
-
requiredValidation: 'required-validation',
|
|
350
|
-
regularExpressionValidation: 'regular-expression-validation',
|
|
351
|
-
minLengthValidation: 'min-length-validation',
|
|
352
|
-
maxLengthValidation: 'max-length-validation',
|
|
353
|
-
lessThanValidation: 'less-than-validation',
|
|
354
|
-
greaterThanValidation: 'greater-than-validation',
|
|
355
|
-
betweenValidation: 'between-validation',
|
|
356
|
-
equalValidation: 'equal-validation',
|
|
357
|
-
callbackValidation: 'callback-validation',
|
|
358
|
-
donutChart: 'donut-chart',
|
|
359
|
-
lineChart: 'line-chart',
|
|
360
|
-
barChart: 'bar-chart',
|
|
361
|
-
gaugeChart: 'gauge-chart',
|
|
362
|
-
stickyNote: 'sticky-note',
|
|
363
|
-
clockCalendar: 'clock-calendar',
|
|
364
|
-
analogClock: 'analog-clock',
|
|
365
|
-
weather: 'weather',
|
|
366
|
-
minimalWeather: 'minimal-weather',
|
|
367
|
-
advancedWeather: 'advanced-weather',
|
|
368
|
-
metaData: 'meta-data-editor',
|
|
369
|
-
templateEditor: 'template-box-editor',
|
|
370
|
-
panel: 'panel',
|
|
371
|
-
notification: 'notification',
|
|
372
|
-
taskBoard: 'task-board',
|
|
373
|
-
comment: 'comment',
|
|
374
|
-
list: 'list',
|
|
375
|
-
listToolbar: 'list-toolbar',
|
|
376
|
-
entityList: 'entity-list',
|
|
377
|
-
documentUploader: 'document-uploader',
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
function cloneProperty(property, values) {
|
|
381
|
-
return merge(cloneDeep(property), values);
|
|
382
|
-
}
|
|
383
|
-
function createStringProperty(ctor) {
|
|
384
|
-
return {
|
|
385
|
-
name: ctor.name,
|
|
386
|
-
title: ctor.title,
|
|
387
|
-
group: ctor.group,
|
|
388
|
-
schema: {
|
|
389
|
-
dataType: 'string',
|
|
390
|
-
defaultValue: ctor.defaultValue,
|
|
391
|
-
interface: {
|
|
392
|
-
name: ctor.name,
|
|
393
|
-
path: ctor.path ?? ctor.name,
|
|
394
|
-
type: AXPWidgetsCatalog.text,
|
|
395
|
-
},
|
|
396
|
-
},
|
|
397
|
-
visible: !isNil(ctor.visible) ? ctor.visible : true,
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
function createNumberProperty(ctor) {
|
|
401
|
-
return {
|
|
402
|
-
name: ctor.name,
|
|
403
|
-
title: ctor.title,
|
|
404
|
-
group: ctor.group,
|
|
405
|
-
schema: {
|
|
406
|
-
dataType: 'number',
|
|
407
|
-
defaultValue: ctor.defaultValue,
|
|
408
|
-
interface: {
|
|
409
|
-
name: ctor.name,
|
|
410
|
-
path: ctor.path ?? ctor.name,
|
|
411
|
-
type: AXPWidgetsCatalog.number,
|
|
412
|
-
options: ctor.options,
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
visible: !isNil(ctor.visible) ? ctor.visible : true,
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
function createBooleanProperty(ctor) {
|
|
419
|
-
return {
|
|
420
|
-
name: ctor.name,
|
|
421
|
-
title: ctor.title,
|
|
422
|
-
group: ctor.group,
|
|
423
|
-
schema: {
|
|
424
|
-
dataType: 'boolean',
|
|
425
|
-
defaultValue: ctor.defaultValue ?? false,
|
|
426
|
-
interface: {
|
|
427
|
-
name: ctor.name,
|
|
428
|
-
path: ctor.path ?? ctor.name,
|
|
429
|
-
type: AXPWidgetsCatalog.toggle,
|
|
430
|
-
},
|
|
431
|
-
},
|
|
432
|
-
visible: ctor.visible ?? true,
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
function createSelectProperty(ctor) {
|
|
436
|
-
return {
|
|
437
|
-
name: ctor.name,
|
|
438
|
-
title: ctor.title,
|
|
439
|
-
group: ctor.group,
|
|
440
|
-
schema: {
|
|
441
|
-
dataType: 'string',
|
|
442
|
-
defaultValue: Array.isArray(ctor.defaultValue)
|
|
443
|
-
? ctor.defaultValue.map((item) => (typeof item === 'string' ? { id: item } : item))
|
|
444
|
-
: typeof ctor.defaultValue === 'string'
|
|
445
|
-
? { id: ctor.defaultValue, title: ctor.defaultValue }
|
|
446
|
-
: ctor.defaultValue,
|
|
447
|
-
interface: {
|
|
448
|
-
name: ctor.name,
|
|
449
|
-
path: ctor.path ?? ctor.name,
|
|
450
|
-
type: AXPWidgetsCatalog.select,
|
|
451
|
-
options: {
|
|
452
|
-
dataSource: ctor.dataSource.map((item) => (typeof item === 'string' ? { id: item, title: item } : item)),
|
|
453
|
-
},
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
visible: ctor.visible ?? true,
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
const AXP_WIDGET_TOKEN = new InjectionToken('AXP_WIDGET_TOKEN');
|
|
460
|
-
const AXP_WIDGET_COLUMN_TOKEN = new InjectionToken('AXP_WIDGET_COLUMN_TOKEN');
|
|
461
|
-
|
|
462
|
-
class AXPBaseWidgetComponent extends AXPLayoutElement {
|
|
463
|
-
constructor() {
|
|
464
|
-
super(...arguments);
|
|
465
|
-
this.token = inject(AXP_WIDGET_TOKEN);
|
|
466
|
-
this.host = inject(ElementRef).nativeElement;
|
|
467
|
-
this.layoutService = inject(AXPLayoutBuilderService);
|
|
468
|
-
this.contextService = inject(AXPLayoutBuilderContextStore);
|
|
469
|
-
this.config = this.token.config;
|
|
470
|
-
this.node = this.token.node;
|
|
471
|
-
this.name = this.token.node.name;
|
|
472
|
-
this._options = signal(this.token.options ?? {}, ...(ngDevMode ? [{ debugName: "_options" }] : []));
|
|
473
|
-
this.options = this._options.asReadonly();
|
|
474
|
-
this.onOptionsChanged = new Subject();
|
|
475
|
-
this._status = signal(AXPWidgetStatus.Rendering, ...(ngDevMode ? [{ debugName: "_status" }] : []));
|
|
476
|
-
this.status = this._status.asReadonly();
|
|
477
|
-
this.onStatusChanged = new BehaviorSubject(this._status());
|
|
478
|
-
this.#statusEffect = effect(() => {
|
|
479
|
-
this.onStatusChanged.next(this.status());
|
|
480
|
-
}, ...(ngDevMode ? [{ debugName: "#statusEffect" }] : []));
|
|
481
|
-
this.isBusy = computed(() => [AXPWidgetStatus.Rendering, AXPWidgetStatus.Processing].includes(this.status()), ...(ngDevMode ? [{ debugName: "isBusy" }] : []));
|
|
482
|
-
this._children = signal(this.token.node.children ?? [], ...(ngDevMode ? [{ debugName: "_children" }] : []));
|
|
483
|
-
this.children = this._children.asReadonly();
|
|
484
|
-
}
|
|
485
|
-
get id() {
|
|
486
|
-
return this._id;
|
|
487
|
-
}
|
|
488
|
-
#statusEffect;
|
|
489
|
-
outputs() {
|
|
490
|
-
return [];
|
|
491
115
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
this.
|
|
500
|
-
this.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const
|
|
505
|
-
this.
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
116
|
+
// Predefined layout containers at root level - delegate pattern required
|
|
117
|
+
grid(delegate) {
|
|
118
|
+
const container = new GridContainerBuilder();
|
|
119
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
120
|
+
if (delegate) {
|
|
121
|
+
delegate(container);
|
|
122
|
+
}
|
|
123
|
+
//this.state.children!.push(container.build());
|
|
124
|
+
this.root = container.build();
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
flex(delegate) {
|
|
128
|
+
const container = new FlexContainerBuilder();
|
|
129
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
130
|
+
if (delegate) {
|
|
131
|
+
delegate(container);
|
|
132
|
+
}
|
|
133
|
+
this.root.children.push(container.build());
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
panel(delegate) {
|
|
137
|
+
const container = new PanelContainerBuilder();
|
|
138
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
139
|
+
if (delegate) {
|
|
140
|
+
delegate(container);
|
|
141
|
+
}
|
|
142
|
+
this.root.children.push(container.build());
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
page(delegate) {
|
|
146
|
+
const container = new PageContainerBuilder();
|
|
147
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
148
|
+
if (delegate) {
|
|
149
|
+
delegate(container);
|
|
150
|
+
}
|
|
151
|
+
this.root.children.push(container.build());
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
tabset(delegate) {
|
|
155
|
+
const container = new TabsetContainerBuilder();
|
|
156
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
157
|
+
if (delegate) {
|
|
158
|
+
delegate(container);
|
|
516
159
|
}
|
|
517
|
-
|
|
160
|
+
this.root.children.push(container.build());
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
fieldset(delegate) {
|
|
164
|
+
const container = new FieldsetContainerBuilder();
|
|
165
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
166
|
+
if (delegate) {
|
|
167
|
+
delegate(container);
|
|
168
|
+
}
|
|
169
|
+
this.root.children.push(container.build());
|
|
170
|
+
return this;
|
|
518
171
|
}
|
|
519
|
-
|
|
520
|
-
const
|
|
521
|
-
if (
|
|
522
|
-
|
|
172
|
+
dialog(delegate) {
|
|
173
|
+
const container = new DialogContainerBuilder(this.popupService);
|
|
174
|
+
if (delegate) {
|
|
175
|
+
delegate(container);
|
|
523
176
|
}
|
|
177
|
+
return container;
|
|
524
178
|
}
|
|
525
|
-
|
|
526
|
-
|
|
179
|
+
formField(label, delegate) {
|
|
180
|
+
const field = new FormFieldBuilder(label);
|
|
181
|
+
field.withInheritanceContext(this.inheritanceContext);
|
|
182
|
+
if (delegate) {
|
|
183
|
+
delegate(field);
|
|
184
|
+
}
|
|
185
|
+
this.root.children.push(field.build());
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
build() {
|
|
189
|
+
return {
|
|
190
|
+
type: this.root.type,
|
|
191
|
+
children: this.root.children,
|
|
192
|
+
mode: this.root.mode,
|
|
193
|
+
};
|
|
527
194
|
}
|
|
528
|
-
onAdded() { }
|
|
529
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBaseWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
530
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBaseWidgetComponent }); }
|
|
531
|
-
}
|
|
532
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBaseWidgetComponent, decorators: [{
|
|
533
|
-
type: Injectable
|
|
534
|
-
}] });
|
|
535
|
-
class AXPLayoutBaseWidgetComponent extends AXPBaseWidgetComponent {
|
|
536
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPLayoutBaseWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
537
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPLayoutBaseWidgetComponent }); }
|
|
538
195
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
this.
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
this.
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region ---- Container Builder Implementation ----
|
|
198
|
+
/**
|
|
199
|
+
* Abstract base container builder - Open/Closed Principle
|
|
200
|
+
* Provides common functionality for all container types
|
|
201
|
+
*/
|
|
202
|
+
class BaseContainerBuilder {
|
|
203
|
+
constructor(containerType) {
|
|
204
|
+
this.containerState = {
|
|
205
|
+
mode: 'edit',
|
|
206
|
+
type: 'flex-layout',
|
|
207
|
+
children: [],
|
|
208
|
+
};
|
|
209
|
+
this.inheritanceContext = {};
|
|
210
|
+
this.containerState.type = containerType;
|
|
211
|
+
}
|
|
212
|
+
// Base methods shared by all containers
|
|
213
|
+
ensureChildren() {
|
|
214
|
+
this.containerState.children = this.containerState.children || [];
|
|
215
|
+
}
|
|
216
|
+
addWidget(type, options) {
|
|
217
|
+
const child = new WidgetBuilder();
|
|
218
|
+
child.type(type);
|
|
219
|
+
// For value widgets, ensure path is provided
|
|
220
|
+
const widgetOptions = options ?? {};
|
|
221
|
+
const path = widgetOptions.path;
|
|
222
|
+
const name = widgetOptions.name;
|
|
223
|
+
if (this.isValueWidget(type) && !path) {
|
|
224
|
+
throw new Error(`Value widget '${type}' requires a 'path' property`);
|
|
225
|
+
}
|
|
226
|
+
// Set name and path in widget state, not options
|
|
227
|
+
if (name) {
|
|
228
|
+
child.name(name);
|
|
229
|
+
}
|
|
230
|
+
if (path) {
|
|
231
|
+
child.path(path);
|
|
232
|
+
}
|
|
233
|
+
// Remove name and path from options
|
|
234
|
+
const { name: _, path: __, ...cleanOptions } = widgetOptions;
|
|
235
|
+
// IMPORTANT: Apply inheritance context BEFORE setting options
|
|
236
|
+
// This ensures that inherited properties (readonly, disabled, etc.) are applied first
|
|
237
|
+
// Then user-provided options will override them if explicitly set
|
|
238
|
+
child.withInheritanceContext(this.inheritanceContext);
|
|
239
|
+
child.options(cleanOptions);
|
|
240
|
+
this.ensureChildren();
|
|
241
|
+
this.containerState.children.push(child.build());
|
|
242
|
+
return this;
|
|
243
|
+
}
|
|
244
|
+
isValueWidget(type) {
|
|
245
|
+
const valueWidgetTypes = [
|
|
246
|
+
'text-editor',
|
|
247
|
+
'large-text-editor',
|
|
248
|
+
'rich-text-editor',
|
|
249
|
+
'password-editor',
|
|
250
|
+
'number-editor',
|
|
251
|
+
'select-editor',
|
|
252
|
+
'lookup-editor',
|
|
253
|
+
'selection-list-editor',
|
|
254
|
+
'date-time-editor',
|
|
255
|
+
'toggle-editor',
|
|
256
|
+
'color-editor',
|
|
257
|
+
];
|
|
258
|
+
return valueWidgetTypes.includes(type);
|
|
259
|
+
}
|
|
260
|
+
build() {
|
|
261
|
+
const result = {
|
|
262
|
+
type: this.containerState.type,
|
|
263
|
+
children: this.containerState.children,
|
|
264
|
+
options: this.containerState.options,
|
|
265
|
+
mode: this.containerState.mode,
|
|
266
|
+
visible: this.containerState.visible,
|
|
267
|
+
};
|
|
268
|
+
// Add name with _form_field suffix for form fields
|
|
269
|
+
if (this.containerState.type === 'form-field') {
|
|
270
|
+
if (this.containerState.name) {
|
|
271
|
+
result.name = this.containerState.name;
|
|
559
272
|
}
|
|
560
|
-
|
|
561
|
-
.
|
|
562
|
-
.map((c) => ({
|
|
563
|
-
rule: c.rule,
|
|
564
|
-
message: c.message,
|
|
565
|
-
options: c.options,
|
|
566
|
-
}));
|
|
567
|
-
}, ...(ngDevMode ? [{ debugName: "validationRules" }] : []));
|
|
568
|
-
}
|
|
569
|
-
ngOnInit() {
|
|
570
|
-
this._isValueWidget = this.config.properties?.some((c) => c.name == 'path') ?? false;
|
|
571
|
-
if (this.isValueWidget()) {
|
|
572
|
-
this.detectFullPath();
|
|
573
|
-
if (!isNil(this.defaultValue) && isNil(this.getValue())) {
|
|
574
|
-
this.setValue(this.defaultValue);
|
|
273
|
+
else if (this.containerState.options?.['label']) {
|
|
274
|
+
result.name = labelToPath(this.containerState.options['label']) + '_form_field';
|
|
575
275
|
}
|
|
276
|
+
// Form fields don't have path
|
|
576
277
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const rawValue = this.contextService.getValue(path);
|
|
582
|
-
if (this.node.valueTransforms?.getter) {
|
|
583
|
-
return this.node.valueTransforms?.getter(rawValue);
|
|
584
|
-
}
|
|
585
|
-
return rawValue;
|
|
586
|
-
}
|
|
587
|
-
setValue(value) {
|
|
588
|
-
if (this.node.valueTransforms?.setter) {
|
|
589
|
-
value = this.node.valueTransforms?.setter(value);
|
|
590
|
-
}
|
|
591
|
-
const oldValue = this.getValue();
|
|
592
|
-
value = isUndefined(value) ? null : value;
|
|
593
|
-
if (isNil(value) && isNil(oldValue)) {
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
if (isEqual(oldValue, value)) {
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
if (this.fullPath()) {
|
|
600
|
-
this.contextService.update(this.fullPath(), value);
|
|
601
|
-
this.onValueChanged.next({ sender: this });
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
detectFullPath() {
|
|
605
|
-
const sections = [];
|
|
606
|
-
const ids = [];
|
|
607
|
-
//
|
|
608
|
-
let parent = this;
|
|
609
|
-
//
|
|
610
|
-
while (parent) {
|
|
611
|
-
const isValueWidget = parent instanceof AXPValueWidgetComponent && parent.isValueWidget();
|
|
612
|
-
const valueParent = parent;
|
|
613
|
-
const path = valueParent.path ?? (isValueWidget ? valueParent.name : null);
|
|
614
|
-
const id = valueParent.name;
|
|
615
|
-
//
|
|
616
|
-
if (path) {
|
|
617
|
-
sections.push(path);
|
|
278
|
+
else {
|
|
279
|
+
// Other containers can have name and path
|
|
280
|
+
if (this.containerState.name) {
|
|
281
|
+
result.name = this.containerState.name;
|
|
618
282
|
}
|
|
619
|
-
if (
|
|
620
|
-
|
|
283
|
+
if (this.containerState.path) {
|
|
284
|
+
result.path = this.containerState.path;
|
|
621
285
|
}
|
|
622
|
-
if (
|
|
623
|
-
|
|
624
|
-
if (parent.index != null) {
|
|
625
|
-
ids.push(`${parent.index}`);
|
|
626
|
-
}
|
|
286
|
+
if (this.containerState.defaultValue !== undefined) {
|
|
287
|
+
result.defaultValue = this.containerState.defaultValue;
|
|
627
288
|
}
|
|
628
|
-
parent = parent.parent;
|
|
629
|
-
}
|
|
630
|
-
//
|
|
631
|
-
this.fullPath.set(sections.reverse().join('.'));
|
|
632
|
-
this.parentPath.set(sections.slice(0, sections.length - 1).join('.'));
|
|
633
|
-
this._id = this.name || this.parent ? ids.reverse().join('_') : null;
|
|
634
|
-
if (this._id) {
|
|
635
|
-
this.layoutService.registerWidget(this._id, this);
|
|
636
289
|
}
|
|
290
|
+
return result;
|
|
637
291
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Base container builder mixin - Interface Segregation Principle
|
|
295
|
+
* Provides common container operations
|
|
296
|
+
*/
|
|
297
|
+
class BaseContainerMixin extends BaseContainerBuilder {
|
|
298
|
+
name(name) {
|
|
299
|
+
this.containerState.name = name;
|
|
300
|
+
return this;
|
|
301
|
+
}
|
|
302
|
+
path(path) {
|
|
303
|
+
this.containerState.path = path;
|
|
304
|
+
return this;
|
|
305
|
+
}
|
|
306
|
+
mode(mode) {
|
|
307
|
+
this.containerState.mode = mode;
|
|
308
|
+
this.inheritanceContext.mode = mode;
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
visible(condition) {
|
|
312
|
+
if (!this.containerState.options)
|
|
313
|
+
this.containerState.options = {};
|
|
314
|
+
this.containerState.options['visible'] = condition;
|
|
315
|
+
this.inheritanceContext.visible = condition;
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
disabled(condition) {
|
|
319
|
+
if (!this.containerState.options)
|
|
320
|
+
this.containerState.options = {};
|
|
321
|
+
this.containerState.options['disabled'] = condition;
|
|
322
|
+
this.inheritanceContext.disabled = condition;
|
|
323
|
+
return this;
|
|
324
|
+
}
|
|
325
|
+
readonly(condition) {
|
|
326
|
+
if (!this.containerState.options)
|
|
327
|
+
this.containerState.options = {};
|
|
328
|
+
this.containerState.options['readonly'] = condition;
|
|
329
|
+
this.inheritanceContext.readonly = condition;
|
|
330
|
+
return this;
|
|
331
|
+
}
|
|
332
|
+
direction(direction) {
|
|
333
|
+
if (!this.containerState.options)
|
|
334
|
+
this.containerState.options = {};
|
|
335
|
+
this.containerState.options['direction'] = direction;
|
|
336
|
+
this.inheritanceContext.direction = direction;
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
339
|
+
// Inheritance context methods
|
|
340
|
+
withInheritanceContext(context) {
|
|
341
|
+
this.inheritanceContext = mergeInheritanceContext(context);
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
344
|
+
getInheritanceContext() {
|
|
345
|
+
return { ...this.inheritanceContext };
|
|
642
346
|
}
|
|
643
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPValueWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
644
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPValueWidgetComponent }); }
|
|
645
347
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
this.valueField = computed(() => this.options()['valueField'] ?? 'id', ...(ngDevMode ? [{ debugName: "valueField" }] : []));
|
|
655
|
-
this.dataSource = signal(convertArrayToDataSource([]), ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
|
|
656
|
-
this.isReady = computed(() => {
|
|
657
|
-
const key = this.dataSource().config?.key;
|
|
658
|
-
const valueField = this.valueField();
|
|
659
|
-
const result = key == valueField;
|
|
660
|
-
return result;
|
|
661
|
-
}, ...(ngDevMode ? [{ debugName: "isReady" }] : []));
|
|
662
|
-
this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
663
|
-
this.rf = effect(async () => {
|
|
664
|
-
const rawValue = this.options()['dataSource'];
|
|
665
|
-
// static datasource class
|
|
666
|
-
if (rawValue instanceof AXDataSource) {
|
|
667
|
-
this.dataSource.set(rawValue);
|
|
668
|
-
}
|
|
669
|
-
// static array datasource
|
|
670
|
-
else if (Array.isArray(rawValue)) {
|
|
671
|
-
const ds = new AXDataSource({
|
|
672
|
-
key: this.valueField(),
|
|
673
|
-
pageSize: 10,
|
|
674
|
-
load: async (e) => {
|
|
675
|
-
const raw = this.options()['dataSource'];
|
|
676
|
-
return {
|
|
677
|
-
items: raw,
|
|
678
|
-
total: raw.length,
|
|
679
|
-
};
|
|
680
|
-
},
|
|
681
|
-
byKey: (key) => {
|
|
682
|
-
const raw = this.options()['dataSource'];
|
|
683
|
-
const item = raw.filter((c) => c[this.valueField()] == key);
|
|
684
|
-
return Promise.resolve(item[0]);
|
|
685
|
-
},
|
|
686
|
-
});
|
|
687
|
-
this.dataSource.set(ds);
|
|
688
|
-
}
|
|
689
|
-
// resolve data source by name
|
|
690
|
-
else if (rawValue && (typeof rawValue == 'string' || typeof rawValue == 'object')) {
|
|
691
|
-
const id = typeof rawValue == 'object' ? rawValue['id'] : rawValue;
|
|
692
|
-
const c = await this.dataService.get(id);
|
|
693
|
-
if (this.mode == 'designer' && c?.samples?.length) {
|
|
694
|
-
this.dataSource.set(convertArrayToDataSource(c.samples, {
|
|
695
|
-
key: this.valueField(),
|
|
696
|
-
pageSize: 500,
|
|
697
|
-
}));
|
|
698
|
-
}
|
|
699
|
-
else {
|
|
700
|
-
const ds = c?.source();
|
|
701
|
-
if (ds && ds instanceof Promise) {
|
|
702
|
-
const d = await ds;
|
|
703
|
-
this.dataSource.set(d);
|
|
704
|
-
}
|
|
705
|
-
else if (ds) {
|
|
706
|
-
this.dataSource.set(ds);
|
|
707
|
-
}
|
|
708
|
-
// empty datasource
|
|
709
|
-
else {
|
|
710
|
-
this.dataSource.set(convertArrayToDataSource([]));
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
// empty datasource
|
|
715
|
-
else {
|
|
716
|
-
this.dataSource.set(convertArrayToDataSource([]));
|
|
717
|
-
}
|
|
718
|
-
}, ...(ngDevMode ? [{ debugName: "rf" }] : []));
|
|
719
|
-
this.effect2 = effect(async () => {
|
|
720
|
-
const value = this.getValue();
|
|
721
|
-
const items = [];
|
|
722
|
-
if (Array.isArray(value)) {
|
|
723
|
-
items.push(...(await Promise.all(value.map((item) => this.extractItem(item)))));
|
|
724
|
-
}
|
|
725
|
-
else {
|
|
726
|
-
items.push(await this.extractItem(value));
|
|
727
|
-
}
|
|
728
|
-
this.selectedItems.set(items.filter((c) => c != null));
|
|
729
|
-
}, ...(ngDevMode ? [{ debugName: "effect2" }] : []));
|
|
348
|
+
/**
|
|
349
|
+
* Layout container mixin - Interface Segregation Principle
|
|
350
|
+
* Provides layout-specific operations
|
|
351
|
+
*/
|
|
352
|
+
class LayoutContainerMixin extends BaseContainerMixin {
|
|
353
|
+
layout(value) {
|
|
354
|
+
// Layout handling can be added here if needed
|
|
355
|
+
return this;
|
|
730
356
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Child container mixin - Interface Segregation Principle
|
|
360
|
+
* Provides child container management
|
|
361
|
+
*/
|
|
362
|
+
class ChildContainerMixin extends LayoutContainerMixin {
|
|
363
|
+
grid(delegate) {
|
|
364
|
+
const container = new GridContainerBuilder();
|
|
365
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
366
|
+
if (delegate) {
|
|
367
|
+
delegate(container);
|
|
734
368
|
}
|
|
735
|
-
|
|
736
|
-
|
|
369
|
+
this.ensureChildren();
|
|
370
|
+
this.containerState.children.push(container.build());
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
flex(delegate) {
|
|
374
|
+
const container = new FlexContainerBuilder();
|
|
375
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
376
|
+
if (delegate) {
|
|
377
|
+
delegate(container);
|
|
737
378
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
379
|
+
this.ensureChildren();
|
|
380
|
+
this.containerState.children.push(container.build());
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
panel(delegate) {
|
|
384
|
+
const container = new PanelContainerBuilder();
|
|
385
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
386
|
+
if (delegate) {
|
|
387
|
+
delegate(container);
|
|
745
388
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
389
|
+
this.ensureChildren();
|
|
390
|
+
this.containerState.children.push(container.build());
|
|
391
|
+
return this;
|
|
392
|
+
}
|
|
393
|
+
page(delegate) {
|
|
394
|
+
const container = new PageContainerBuilder();
|
|
395
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
396
|
+
if (delegate) {
|
|
397
|
+
delegate(container);
|
|
398
|
+
}
|
|
399
|
+
this.ensureChildren();
|
|
400
|
+
this.containerState.children.push(container.build());
|
|
401
|
+
return this;
|
|
402
|
+
}
|
|
403
|
+
tabset(delegate) {
|
|
404
|
+
const container = new TabsetContainerBuilder();
|
|
405
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
406
|
+
if (delegate) {
|
|
407
|
+
delegate(container);
|
|
408
|
+
}
|
|
409
|
+
this.ensureChildren();
|
|
410
|
+
this.containerState.children.push(container.build());
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
fieldset(delegate) {
|
|
414
|
+
const container = new FieldsetContainerBuilder();
|
|
415
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
416
|
+
if (delegate) {
|
|
417
|
+
delegate(container);
|
|
418
|
+
}
|
|
419
|
+
this.ensureChildren();
|
|
420
|
+
this.containerState.children.push(container.build());
|
|
421
|
+
return this;
|
|
422
|
+
}
|
|
423
|
+
dialog(delegate) {
|
|
424
|
+
const container = new DialogContainerBuilder(); // Will use inject() fallback
|
|
425
|
+
if (delegate) {
|
|
426
|
+
delegate(container);
|
|
427
|
+
}
|
|
428
|
+
return container;
|
|
429
|
+
}
|
|
430
|
+
formField(label, delegate) {
|
|
431
|
+
const field = new FormFieldBuilder(label);
|
|
432
|
+
field.withInheritanceContext(this.inheritanceContext);
|
|
433
|
+
if (delegate) {
|
|
434
|
+
delegate(field);
|
|
435
|
+
}
|
|
436
|
+
this.ensureChildren();
|
|
437
|
+
this.containerState.children.push(field.build());
|
|
438
|
+
return this;
|
|
752
439
|
}
|
|
753
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPDataListWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
754
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPDataListWidgetComponent }); }
|
|
755
440
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
this.
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
this.
|
|
767
|
-
this
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Widget container mixin - Interface Segregation Principle
|
|
443
|
+
* Provides widget creation operations
|
|
444
|
+
*/
|
|
445
|
+
class WidgetContainerMixin extends ChildContainerMixin {
|
|
446
|
+
textBox(options) {
|
|
447
|
+
this.addWidget('text-editor', options);
|
|
448
|
+
return this;
|
|
449
|
+
}
|
|
450
|
+
largeTextBox(options) {
|
|
451
|
+
this.addWidget('large-text-editor', options);
|
|
452
|
+
return this;
|
|
453
|
+
}
|
|
454
|
+
richText(options) {
|
|
455
|
+
this.addWidget('rich-text-editor', options);
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
458
|
+
passwordBox(options) {
|
|
459
|
+
this.addWidget('password-editor', options);
|
|
460
|
+
return this;
|
|
461
|
+
}
|
|
462
|
+
numberBox(options) {
|
|
463
|
+
this.addWidget('number-editor', options);
|
|
464
|
+
return this;
|
|
465
|
+
}
|
|
466
|
+
selectBox(options) {
|
|
467
|
+
this.addWidget('select-editor', options);
|
|
468
|
+
return this;
|
|
469
|
+
}
|
|
470
|
+
lookupBox(options) {
|
|
471
|
+
this.addWidget('lookup-editor', options);
|
|
472
|
+
return this;
|
|
473
|
+
}
|
|
474
|
+
selectionList(options) {
|
|
475
|
+
this.addWidget('selection-list-editor', options);
|
|
476
|
+
return this;
|
|
477
|
+
}
|
|
478
|
+
dateTimeBox(options) {
|
|
479
|
+
this.addWidget('date-time-editor', options);
|
|
480
|
+
return this;
|
|
481
|
+
}
|
|
482
|
+
toggleSwitch(options) {
|
|
483
|
+
this.addWidget('toggle-editor', options);
|
|
484
|
+
return this;
|
|
485
|
+
}
|
|
486
|
+
colorBox(options) {
|
|
487
|
+
this.addWidget('color-editor', options);
|
|
488
|
+
return this;
|
|
489
|
+
}
|
|
490
|
+
list(delegate) {
|
|
491
|
+
const container = new ListWidgetBuilder();
|
|
492
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
493
|
+
if (delegate) {
|
|
494
|
+
delegate(container);
|
|
495
|
+
}
|
|
496
|
+
this.ensureChildren();
|
|
497
|
+
this.containerState.children.push(container.build());
|
|
498
|
+
return this;
|
|
499
|
+
}
|
|
500
|
+
customWidget(type, options) {
|
|
501
|
+
this.addWidget(type, options);
|
|
502
|
+
return this;
|
|
773
503
|
}
|
|
774
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPColumnWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
775
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPColumnWidgetComponent }); }
|
|
776
504
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
class
|
|
505
|
+
/**
|
|
506
|
+
* Flex Container Builder - Liskov Substitution Principle
|
|
507
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
508
|
+
*/
|
|
509
|
+
class FlexContainerBuilder extends WidgetContainerMixin {
|
|
782
510
|
constructor() {
|
|
783
|
-
super(
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
const height = options?.['height'];
|
|
814
|
-
const minHeight = options?.['minHeight'];
|
|
815
|
-
const maxHeight = options?.['maxHeight'];
|
|
816
|
-
style['min-width'] = minWidth ?? '';
|
|
817
|
-
style['width'] = width ?? '';
|
|
818
|
-
style['max-width'] = maxWidth ?? '';
|
|
819
|
-
style['min-height'] = minHeight ?? '';
|
|
820
|
-
style['height'] = height ?? '';
|
|
821
|
-
style['max-height'] = maxHeight ?? '';
|
|
822
|
-
return style;
|
|
823
|
-
}, ...(ngDevMode ? [{ debugName: "blockStyle" }] : []));
|
|
824
|
-
this.inlineStyle = computed(() => {
|
|
825
|
-
return { ...this.hostBoxStyle() };
|
|
826
|
-
}, ...(ngDevMode ? [{ debugName: "inlineStyle" }] : []));
|
|
827
|
-
this.blockClass = computed(() => {
|
|
828
|
-
return {
|
|
829
|
-
'ax-block': true,
|
|
830
|
-
'ax-w-full': true,
|
|
831
|
-
// 'ax-widget-outline': true,
|
|
832
|
-
};
|
|
833
|
-
}, ...(ngDevMode ? [{ debugName: "blockClass" }] : []));
|
|
834
|
-
this.inlineClass = computed(() => {
|
|
835
|
-
return {
|
|
836
|
-
'ax-inline-block': true,
|
|
837
|
-
};
|
|
838
|
-
}, ...(ngDevMode ? [{ debugName: "inlineClass" }] : []));
|
|
511
|
+
super('flex-layout');
|
|
512
|
+
}
|
|
513
|
+
setOptions(options) {
|
|
514
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
515
|
+
return this;
|
|
516
|
+
}
|
|
517
|
+
// Individual fluent methods for Flex
|
|
518
|
+
setDirection(direction) {
|
|
519
|
+
return this.setOptions({ flexDirection: direction });
|
|
520
|
+
}
|
|
521
|
+
setWrap(wrap) {
|
|
522
|
+
return this.setOptions({ flexWrap: wrap });
|
|
523
|
+
}
|
|
524
|
+
setJustifyContent(justify) {
|
|
525
|
+
return this.setOptions({ justifyContent: justify });
|
|
526
|
+
}
|
|
527
|
+
setAlignItems(align) {
|
|
528
|
+
return this.setOptions({ alignItems: align });
|
|
529
|
+
}
|
|
530
|
+
setGap(gap) {
|
|
531
|
+
return this.setOptions({ gap });
|
|
532
|
+
}
|
|
533
|
+
setBackgroundColor(color) {
|
|
534
|
+
return this.setOptions({ backgroundColor: color });
|
|
535
|
+
}
|
|
536
|
+
setPadding(padding) {
|
|
537
|
+
return this.setOptions({ spacing: { padding } });
|
|
538
|
+
}
|
|
539
|
+
setMargin(margin) {
|
|
540
|
+
return this.setOptions({ spacing: { margin } });
|
|
839
541
|
}
|
|
840
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBoxModelLayoutWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
841
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBoxModelLayoutWidgetComponent }); }
|
|
842
542
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
class
|
|
543
|
+
/**
|
|
544
|
+
* Grid Container Builder - Liskov Substitution Principle
|
|
545
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
546
|
+
*/
|
|
547
|
+
class GridContainerBuilder extends WidgetContainerMixin {
|
|
848
548
|
constructor() {
|
|
849
|
-
super(
|
|
850
|
-
|
|
851
|
-
|
|
549
|
+
super('grid-layout');
|
|
550
|
+
}
|
|
551
|
+
setOptions(options) {
|
|
552
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
553
|
+
return this;
|
|
554
|
+
}
|
|
555
|
+
// Individual fluent methods for Grid
|
|
556
|
+
setColumns(columns) {
|
|
557
|
+
return this.setOptions({ grid: { default: { columns } } });
|
|
558
|
+
}
|
|
559
|
+
setRows(rows) {
|
|
560
|
+
return this.setOptions({ grid: { default: { rows } } });
|
|
561
|
+
}
|
|
562
|
+
setGap(gap) {
|
|
563
|
+
return this.setOptions({ grid: { default: { gap } } });
|
|
564
|
+
}
|
|
565
|
+
setJustifyItems(justify) {
|
|
566
|
+
return this.setOptions({ grid: { default: { justifyItems: justify } } });
|
|
567
|
+
}
|
|
568
|
+
setAlignItems(align) {
|
|
569
|
+
return this.setOptions({ grid: { default: { alignItems: align } } });
|
|
570
|
+
}
|
|
571
|
+
setAutoFlow(flow) {
|
|
572
|
+
return this.setOptions({ grid: { default: { autoFlow: flow } } });
|
|
573
|
+
}
|
|
574
|
+
setBackgroundColor(color) {
|
|
575
|
+
return this.setOptions({ backgroundColor: color });
|
|
576
|
+
}
|
|
577
|
+
setPadding(padding) {
|
|
578
|
+
return this.setOptions({ spacing: { padding } });
|
|
579
|
+
}
|
|
580
|
+
setMargin(margin) {
|
|
581
|
+
return this.setOptions({ spacing: { margin } });
|
|
852
582
|
}
|
|
853
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBlockBaseLayoutWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
854
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPBlockBaseLayoutWidgetComponent }); }
|
|
855
583
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
class
|
|
584
|
+
/**
|
|
585
|
+
* Panel Container Builder - Liskov Substitution Principle
|
|
586
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
587
|
+
*/
|
|
588
|
+
class PanelContainerBuilder extends WidgetContainerMixin {
|
|
861
589
|
constructor() {
|
|
862
|
-
super(
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
style['justify-content'] = '';
|
|
885
|
-
}
|
|
886
|
-
else {
|
|
887
|
-
style['justify-content'] = flex.justifyContent;
|
|
888
|
-
}
|
|
889
|
-
if (isNil(flex?.alignItems)) {
|
|
890
|
-
style['align-items'] = '';
|
|
891
|
-
}
|
|
892
|
-
else {
|
|
893
|
-
style['align-items'] = flex.alignItems;
|
|
894
|
-
}
|
|
895
|
-
if (isNil(flex?.gap)) {
|
|
896
|
-
style['gap'] = '';
|
|
897
|
-
}
|
|
898
|
-
else {
|
|
899
|
-
style['gap'] = flex.gap;
|
|
900
|
-
}
|
|
901
|
-
return style;
|
|
902
|
-
}, ...(ngDevMode ? [{ debugName: "hostFlexStyle" }] : []));
|
|
903
|
-
this.hostFlexClass = computed(() => {
|
|
904
|
-
return {
|
|
905
|
-
...this.blockClass(),
|
|
906
|
-
'ax-flex': true,
|
|
907
|
-
'ax-h-full': true,
|
|
908
|
-
};
|
|
909
|
-
}, ...(ngDevMode ? [{ debugName: "hostFlexClass" }] : []));
|
|
910
|
-
this.hostClass = computed(() => {
|
|
911
|
-
return this.hostFlexClass();
|
|
912
|
-
}, ...(ngDevMode ? [{ debugName: "hostClass" }] : []));
|
|
913
|
-
this.hostStyle = computed(() => {
|
|
914
|
-
return this.hostFlexStyle();
|
|
915
|
-
}, ...(ngDevMode ? [{ debugName: "hostStyle" }] : []));
|
|
916
|
-
}
|
|
917
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPFlexBaseLayoutWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
918
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPFlexBaseLayoutWidgetComponent }); }
|
|
590
|
+
super('panel-layout');
|
|
591
|
+
}
|
|
592
|
+
setOptions(options) {
|
|
593
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
594
|
+
return this;
|
|
595
|
+
}
|
|
596
|
+
// Individual fluent methods for Panel
|
|
597
|
+
setCaption(caption) {
|
|
598
|
+
return this.setOptions({ caption });
|
|
599
|
+
}
|
|
600
|
+
setIcon(icon) {
|
|
601
|
+
return this.setOptions({ icon });
|
|
602
|
+
}
|
|
603
|
+
setLook(look) {
|
|
604
|
+
return this.setOptions({ look });
|
|
605
|
+
}
|
|
606
|
+
setShowHeader(show) {
|
|
607
|
+
return this.setOptions({ showHeader: show });
|
|
608
|
+
}
|
|
609
|
+
setCollapsed(collapsed) {
|
|
610
|
+
return this.setOptions({ collapsed });
|
|
611
|
+
}
|
|
919
612
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
class
|
|
613
|
+
/**
|
|
614
|
+
* Page Container Builder - Liskov Substitution Principle
|
|
615
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
616
|
+
*/
|
|
617
|
+
class PageContainerBuilder extends WidgetContainerMixin {
|
|
925
618
|
constructor() {
|
|
926
|
-
super(
|
|
927
|
-
|
|
928
|
-
|
|
619
|
+
super('page-layout');
|
|
620
|
+
}
|
|
621
|
+
setOptions(options) {
|
|
622
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
623
|
+
return this;
|
|
624
|
+
}
|
|
625
|
+
// Individual fluent methods for Page
|
|
626
|
+
setBackgroundColor(color) {
|
|
627
|
+
return this.setOptions({ backgroundColor: color });
|
|
628
|
+
}
|
|
629
|
+
setTheme(theme) {
|
|
630
|
+
return this.setOptions({ theme });
|
|
631
|
+
}
|
|
632
|
+
setHasHeader(hasHeader) {
|
|
633
|
+
return this.setOptions({ hasHeader });
|
|
634
|
+
}
|
|
635
|
+
setHasFooter(hasFooter) {
|
|
636
|
+
return this.setOptions({ hasFooter });
|
|
637
|
+
}
|
|
638
|
+
setDirection(direction) {
|
|
639
|
+
return this.setOptions({ direction });
|
|
929
640
|
}
|
|
930
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPInlineBaseLayoutWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
931
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPInlineBaseLayoutWidgetComponent }); }
|
|
932
641
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
class
|
|
642
|
+
/**
|
|
643
|
+
* Tabset Container Builder - Liskov Substitution Principle
|
|
644
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
645
|
+
*/
|
|
646
|
+
class TabsetContainerBuilder extends WidgetContainerMixin {
|
|
938
647
|
constructor() {
|
|
939
|
-
super(
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
style['flex-grow'] = fi.grow;
|
|
956
|
-
}
|
|
957
|
-
if (isNil(fi?.shrink)) {
|
|
958
|
-
style['flex-shrink'] = '';
|
|
959
|
-
}
|
|
960
|
-
else {
|
|
961
|
-
style['flex-shrink'] = fi.shrink;
|
|
962
|
-
}
|
|
963
|
-
if (isNil(fi?.basis)) {
|
|
964
|
-
style['flex-basis'] = '';
|
|
965
|
-
}
|
|
966
|
-
else {
|
|
967
|
-
style['flex-basis'] = fi.basis;
|
|
968
|
-
}
|
|
969
|
-
if (isNil(fi?.alignSelf)) {
|
|
970
|
-
style['align-self'] = '';
|
|
971
|
-
}
|
|
972
|
-
else {
|
|
973
|
-
style['align-self'] = fi.alignSelf;
|
|
974
|
-
}
|
|
975
|
-
return style;
|
|
976
|
-
}, ...(ngDevMode ? [{ debugName: "hostFlexItemStyle" }] : []));
|
|
977
|
-
this.hostFlexItemClass = computed(() => {
|
|
978
|
-
return {
|
|
979
|
-
...this.blockClass(),
|
|
980
|
-
};
|
|
981
|
-
}, ...(ngDevMode ? [{ debugName: "hostFlexItemClass" }] : []));
|
|
982
|
-
this.hostClass = computed(() => {
|
|
983
|
-
return this.hostFlexItemClass();
|
|
984
|
-
}, ...(ngDevMode ? [{ debugName: "hostClass" }] : []));
|
|
985
|
-
this.hostStyle = computed(() => {
|
|
986
|
-
return this.hostFlexItemStyle();
|
|
987
|
-
}, ...(ngDevMode ? [{ debugName: "hostStyle" }] : []));
|
|
988
|
-
}
|
|
989
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPFlexItemBaseLayoutWidgetComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
990
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPFlexItemBaseLayoutWidgetComponent }); }
|
|
648
|
+
super('tabset-layout');
|
|
649
|
+
}
|
|
650
|
+
setOptions(options) {
|
|
651
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
652
|
+
return this;
|
|
653
|
+
}
|
|
654
|
+
// Individual fluent methods for Tabset
|
|
655
|
+
setLook(look) {
|
|
656
|
+
return this.setOptions({ look });
|
|
657
|
+
}
|
|
658
|
+
setOrientation(orientation) {
|
|
659
|
+
return this.setOptions({ orientation });
|
|
660
|
+
}
|
|
661
|
+
setActiveIndex(index) {
|
|
662
|
+
return this.setOptions({ activeIndex: index });
|
|
663
|
+
}
|
|
991
664
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
class
|
|
997
|
-
constructor() {
|
|
998
|
-
super(
|
|
999
|
-
this.
|
|
1000
|
-
this.
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
this.
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
665
|
+
/**
|
|
666
|
+
* Form Field Builder - Liskov Substitution Principle
|
|
667
|
+
* Can only contain ONE widget with automatic path generation
|
|
668
|
+
*/
|
|
669
|
+
class FormFieldBuilder extends LayoutContainerMixin {
|
|
670
|
+
constructor(label) {
|
|
671
|
+
super('form-field');
|
|
672
|
+
this.hasWidget = false;
|
|
673
|
+
this.containerState.options = { label, showLabel: true };
|
|
674
|
+
}
|
|
675
|
+
setOptions(options) {
|
|
676
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
677
|
+
return this;
|
|
678
|
+
}
|
|
679
|
+
setLabel(label) {
|
|
680
|
+
return this.setOptions({ label });
|
|
681
|
+
}
|
|
682
|
+
setShowLabel(showLabel) {
|
|
683
|
+
return this.setOptions({ showLabel });
|
|
684
|
+
}
|
|
685
|
+
// Single widget methods with automatic path generation
|
|
686
|
+
addSingleWidget(type, options) {
|
|
687
|
+
if (this.hasWidget) {
|
|
688
|
+
throw new Error('Form field can only contain one widget');
|
|
689
|
+
}
|
|
690
|
+
const formFieldName = this.containerState.name;
|
|
691
|
+
const formFieldPath = this.containerState.path; // Get explicit path from form field
|
|
692
|
+
const formFieldLabel = this.containerState.options?.['label'];
|
|
693
|
+
const widgetName = options?.name;
|
|
694
|
+
// Generate widget path: explicit path -> widget name -> form field name -> label -> random
|
|
695
|
+
let widgetPath;
|
|
696
|
+
if (formFieldPath) {
|
|
697
|
+
widgetPath = formFieldPath; // Use explicit form field path first
|
|
698
|
+
}
|
|
699
|
+
else if (widgetName) {
|
|
700
|
+
widgetPath = widgetName;
|
|
701
|
+
}
|
|
702
|
+
else if (formFieldName) {
|
|
703
|
+
widgetPath = formFieldName; // Use form field name as default path
|
|
704
|
+
}
|
|
705
|
+
else if (formFieldLabel) {
|
|
706
|
+
widgetPath = labelToPath(formFieldLabel);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
widgetPath = generateRandomId();
|
|
710
|
+
}
|
|
711
|
+
const finalName = widgetName || formFieldName || widgetPath;
|
|
712
|
+
const child = new WidgetBuilder();
|
|
713
|
+
child.type(type);
|
|
714
|
+
child.name(finalName);
|
|
715
|
+
child.path(widgetPath);
|
|
716
|
+
// Remove name from options since it's now in state
|
|
717
|
+
const { name: _, ...cleanOptions } = (options || {});
|
|
718
|
+
child.withInheritanceContext(this.inheritanceContext);
|
|
719
|
+
child.options(cleanOptions);
|
|
720
|
+
// IMPORTANT: Store the widget builder, don't build it yet!
|
|
721
|
+
// This allows properties set after this method (like disabled, readonly) to be applied
|
|
722
|
+
this.childWidget = child;
|
|
723
|
+
this.hasWidget = true;
|
|
724
|
+
return this;
|
|
725
|
+
}
|
|
726
|
+
textBox(options) {
|
|
727
|
+
return this.addSingleWidget('text-editor', options);
|
|
728
|
+
}
|
|
729
|
+
largeTextBox(options) {
|
|
730
|
+
return this.addSingleWidget('large-text-editor', options);
|
|
731
|
+
}
|
|
732
|
+
richText(options) {
|
|
733
|
+
return this.addSingleWidget('rich-text-editor', options);
|
|
734
|
+
}
|
|
735
|
+
passwordBox(options) {
|
|
736
|
+
return this.addSingleWidget('password-editor', options);
|
|
737
|
+
}
|
|
738
|
+
numberBox(options) {
|
|
739
|
+
return this.addSingleWidget('number-editor', options);
|
|
740
|
+
}
|
|
741
|
+
selectBox(options) {
|
|
742
|
+
return this.addSingleWidget('select-editor', options);
|
|
743
|
+
}
|
|
744
|
+
lookupBox(options) {
|
|
745
|
+
return this.addSingleWidget('lookup-editor', options);
|
|
746
|
+
}
|
|
747
|
+
selectionList(options) {
|
|
748
|
+
return this.addSingleWidget('selection-list-editor', options);
|
|
749
|
+
}
|
|
750
|
+
dateTimeBox(options) {
|
|
751
|
+
return this.addSingleWidget('date-time-editor', options);
|
|
752
|
+
}
|
|
753
|
+
toggleSwitch(options) {
|
|
754
|
+
return this.addSingleWidget('toggle-editor', options);
|
|
755
|
+
}
|
|
756
|
+
colorBox(options) {
|
|
757
|
+
return this.addSingleWidget('color-editor', options);
|
|
758
|
+
}
|
|
759
|
+
customWidget(type, options) {
|
|
760
|
+
return this.addSingleWidget(type, options);
|
|
761
|
+
}
|
|
762
|
+
// Override property setters to propagate changes to child widget
|
|
763
|
+
disabled(condition) {
|
|
764
|
+
super.disabled(condition);
|
|
765
|
+
if (this.childWidget) {
|
|
766
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
767
|
+
}
|
|
768
|
+
return this;
|
|
769
|
+
}
|
|
770
|
+
readonly(condition) {
|
|
771
|
+
super.readonly(condition);
|
|
772
|
+
if (this.childWidget) {
|
|
773
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
774
|
+
}
|
|
775
|
+
return this;
|
|
776
|
+
}
|
|
777
|
+
visible(condition) {
|
|
778
|
+
super.visible(condition);
|
|
779
|
+
if (this.childWidget) {
|
|
780
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
781
|
+
}
|
|
782
|
+
return this;
|
|
783
|
+
}
|
|
784
|
+
direction(direction) {
|
|
785
|
+
super.direction(direction);
|
|
786
|
+
if (this.childWidget) {
|
|
787
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
788
|
+
}
|
|
789
|
+
return this;
|
|
790
|
+
}
|
|
791
|
+
mode(mode) {
|
|
792
|
+
super.mode(mode);
|
|
793
|
+
if (this.childWidget) {
|
|
794
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
795
|
+
}
|
|
796
|
+
return this;
|
|
797
|
+
}
|
|
798
|
+
// Override withInheritanceContext to pass it to the child widget if it exists
|
|
799
|
+
withInheritanceContext(context) {
|
|
800
|
+
// Call parent implementation first
|
|
801
|
+
super.withInheritanceContext(context);
|
|
802
|
+
// If we have a child widget, update its inheritance context too
|
|
803
|
+
if (this.childWidget) {
|
|
804
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
805
|
+
}
|
|
806
|
+
return this;
|
|
807
|
+
}
|
|
808
|
+
// Override build() to build the child widget at the last moment
|
|
809
|
+
build() {
|
|
810
|
+
// Build the child widget and add it to children before building the form field
|
|
811
|
+
if (this.childWidget) {
|
|
812
|
+
this.ensureChildren();
|
|
813
|
+
this.containerState.children.push(this.childWidget.build());
|
|
814
|
+
}
|
|
815
|
+
// Call parent build
|
|
816
|
+
return super.build();
|
|
817
|
+
}
|
|
1030
818
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
819
|
+
/**
|
|
820
|
+
* Fieldset Container Builder - Liskov Substitution Principle
|
|
821
|
+
* Extends LayoutContainerMixin to inherit layout functionality
|
|
822
|
+
* Specialized for form fields only
|
|
823
|
+
*/
|
|
824
|
+
class FieldsetContainerBuilder extends LayoutContainerMixin {
|
|
1036
825
|
constructor() {
|
|
1037
|
-
super(
|
|
1038
|
-
this.
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
826
|
+
super('fieldset-layout');
|
|
827
|
+
this.containerState.options = {};
|
|
828
|
+
}
|
|
829
|
+
setOptions(options) {
|
|
830
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
831
|
+
return this;
|
|
832
|
+
}
|
|
833
|
+
// Individual fluent methods for Fieldset
|
|
834
|
+
setTitle(title) {
|
|
835
|
+
return this.setOptions({ title });
|
|
836
|
+
}
|
|
837
|
+
setDescription(description) {
|
|
838
|
+
return this.setOptions({ description });
|
|
839
|
+
}
|
|
840
|
+
setIcon(icon) {
|
|
841
|
+
return this.setOptions({ icon });
|
|
842
|
+
}
|
|
843
|
+
setCollapsible(collapsible) {
|
|
844
|
+
return this.setOptions({ collapsible });
|
|
845
|
+
}
|
|
846
|
+
setIsOpen(isOpen) {
|
|
847
|
+
return this.setOptions({ isOpen });
|
|
848
|
+
}
|
|
849
|
+
setLook(look) {
|
|
850
|
+
return this.setOptions({ look });
|
|
851
|
+
}
|
|
852
|
+
setShowHeader(showHeader) {
|
|
853
|
+
return this.setOptions({ showHeader });
|
|
854
|
+
}
|
|
855
|
+
setCols(cols) {
|
|
856
|
+
return this.setOptions({ cols });
|
|
857
|
+
}
|
|
858
|
+
// Only form fields are allowed in fieldset
|
|
859
|
+
formField(label, delegate) {
|
|
860
|
+
const field = new FormFieldBuilder(label);
|
|
861
|
+
field.withInheritanceContext(this.inheritanceContext);
|
|
862
|
+
if (delegate) {
|
|
863
|
+
delegate(field);
|
|
864
|
+
}
|
|
865
|
+
this.ensureChildren();
|
|
866
|
+
this.containerState.children.push(field.build());
|
|
867
|
+
return this;
|
|
868
|
+
}
|
|
1070
869
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
class
|
|
1076
|
-
/**
|
|
1077
|
-
*
|
|
1078
|
-
*/
|
|
870
|
+
/**
|
|
871
|
+
* List Widget Builder - Liskov Substitution Principle
|
|
872
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
873
|
+
*/
|
|
874
|
+
class ListWidgetBuilder extends WidgetContainerMixin {
|
|
1079
875
|
constructor() {
|
|
1080
|
-
|
|
1081
|
-
AXPWidgetRegistryService.instance = this;
|
|
876
|
+
super('list');
|
|
1082
877
|
}
|
|
1083
|
-
|
|
1084
|
-
this.
|
|
878
|
+
setOptions(options) {
|
|
879
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
880
|
+
return this;
|
|
1085
881
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
newWidget.name = widget.name;
|
|
1090
|
-
this.register(newWidget);
|
|
882
|
+
// Individual fluent methods for List Widget
|
|
883
|
+
setDataSource(dataSource) {
|
|
884
|
+
return this.setOptions({ dataSource });
|
|
1091
885
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
return
|
|
886
|
+
setColumns(columns) {
|
|
887
|
+
return this.setOptions({ columns });
|
|
888
|
+
}
|
|
889
|
+
// Event handlers
|
|
890
|
+
setOnRowClick(handler) {
|
|
891
|
+
return this.setOptions({ onRowClick: handler });
|
|
892
|
+
}
|
|
893
|
+
setOnRowDoubleClick(handler) {
|
|
894
|
+
return this.setOptions({ onRowDoubleClick: handler });
|
|
895
|
+
}
|
|
896
|
+
setOnSelectionChange(handler) {
|
|
897
|
+
return this.setOptions({ onSelectionChange: handler });
|
|
898
|
+
}
|
|
899
|
+
setOnRowCommand(handler) {
|
|
900
|
+
return this.setOptions({ onRowCommand: handler });
|
|
901
|
+
}
|
|
902
|
+
// Table features
|
|
903
|
+
setPaging(paging) {
|
|
904
|
+
return this.setOptions({ paging });
|
|
905
|
+
}
|
|
906
|
+
setShowHeader(show) {
|
|
907
|
+
return this.setOptions({ showHeader: show });
|
|
908
|
+
}
|
|
909
|
+
setShowFooter(show) {
|
|
910
|
+
return this.setOptions({ showFooter: show });
|
|
911
|
+
}
|
|
912
|
+
setFixHeader(fix) {
|
|
913
|
+
return this.setOptions({ fixHeader: fix });
|
|
914
|
+
}
|
|
915
|
+
setFixFooter(fix) {
|
|
916
|
+
return this.setOptions({ fixFooter: fix });
|
|
917
|
+
}
|
|
918
|
+
setFetchDataMode(mode) {
|
|
919
|
+
return this.setOptions({ fetchDataMode: mode });
|
|
920
|
+
}
|
|
921
|
+
setParentField(field) {
|
|
922
|
+
return this.setOptions({ parentField: field });
|
|
923
|
+
}
|
|
924
|
+
setMinHeight(height) {
|
|
925
|
+
return this.setOptions({ minHeight: height });
|
|
926
|
+
}
|
|
927
|
+
// Selection & Index
|
|
928
|
+
setShowIndex(show) {
|
|
929
|
+
return this.setOptions({ showIndex: show });
|
|
930
|
+
}
|
|
931
|
+
setAllowSelection(allow) {
|
|
932
|
+
return this.setOptions({ allowSelection: allow });
|
|
933
|
+
}
|
|
934
|
+
// Commands
|
|
935
|
+
setPrimaryCommands(commands) {
|
|
936
|
+
return this.setOptions({ primaryCommands: commands });
|
|
937
|
+
}
|
|
938
|
+
setSecondaryCommands(commands) {
|
|
939
|
+
return this.setOptions({ secondaryCommands: commands });
|
|
1098
940
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
941
|
+
// Loading
|
|
942
|
+
setLoading(loading) {
|
|
943
|
+
return this.setOptions({ loading });
|
|
1101
944
|
}
|
|
1102
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPWidgetRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1103
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPWidgetRegistryService, providedIn: 'root' }); }
|
|
1104
945
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
}
|
|
1125
|
-
set node(v) {
|
|
1126
|
-
this._node = v;
|
|
1127
|
-
}
|
|
1128
|
-
get renderFooterTemplate() {
|
|
1129
|
-
return this.footerTemplate ?? this._contentFooterTemplate;
|
|
1130
|
-
}
|
|
1131
|
-
get renderCellTemplate() {
|
|
1132
|
-
return this.cellTemplate ?? this._contentCellTemplate;
|
|
1133
|
-
}
|
|
1134
|
-
async handleExpandRow(row) {
|
|
1135
|
-
this.loadingRow.set(row);
|
|
1136
|
-
await this.grid.expandRow(row);
|
|
1137
|
-
this.loadingRow.set(null);
|
|
1138
|
-
// if (row.data?.__meta__?.expanded === undefined) {
|
|
1139
|
-
// this.width = `${parseInt(this.width as string) + 24}px`;
|
|
1140
|
-
// }
|
|
1141
|
-
}
|
|
1142
|
-
get renderHeaderTemplate() {
|
|
1143
|
-
return this.headerTemplate ?? this._contentHeaderTemplate;
|
|
1144
|
-
}
|
|
1145
|
-
get loadingEnabled() {
|
|
1146
|
-
return true;
|
|
1147
|
-
}
|
|
1148
|
-
get name() {
|
|
1149
|
-
return `col-${this.node.path}`;
|
|
1150
|
-
}
|
|
1151
|
-
async ngOnInit() {
|
|
1152
|
-
const widget = this.widgetRegistery.resolve(this.node.type);
|
|
1153
|
-
const mode = 'column';
|
|
1154
|
-
this.component = await widget?.components[mode]?.component();
|
|
1155
|
-
//
|
|
1156
|
-
const props = widget?.components[mode]?.properties
|
|
1157
|
-
?.filter((c) => c.schema.defaultValue)
|
|
1158
|
-
.map((c) => ({ [c.name]: c.schema.defaultValue }))
|
|
1159
|
-
.reduce((acc, curr) => {
|
|
1160
|
-
return { ...acc, ...curr };
|
|
1161
|
-
}, {});
|
|
1162
|
-
//
|
|
1163
|
-
this.mergedOptions.set(merge(props, this.node.options) || {});
|
|
1164
|
-
const tokenValue = {
|
|
1165
|
-
path: this.node.path,
|
|
1166
|
-
options: this.mergedOptions(),
|
|
1167
|
-
};
|
|
1168
|
-
this.widgetInjector = Injector.create({
|
|
1169
|
-
parent: this.injector,
|
|
1170
|
-
providers: [
|
|
1171
|
-
{
|
|
1172
|
-
provide: AXP_WIDGET_COLUMN_TOKEN,
|
|
1173
|
-
useValue: tokenValue,
|
|
946
|
+
/**
|
|
947
|
+
* Dialog Container Builder - Specialized for dialog functionality
|
|
948
|
+
* Uses composition instead of inheritance for cleaner separation
|
|
949
|
+
*/
|
|
950
|
+
class DialogContainerBuilder {
|
|
951
|
+
constructor(popupService) {
|
|
952
|
+
this.dialogState = {
|
|
953
|
+
type: 'flex-layout', // This will be overridden when content layout exists
|
|
954
|
+
children: [],
|
|
955
|
+
mode: 'edit',
|
|
956
|
+
dialogOptions: {
|
|
957
|
+
title: '',
|
|
958
|
+
size: 'md',
|
|
959
|
+
closeButton: false,
|
|
960
|
+
},
|
|
961
|
+
actions: {
|
|
962
|
+
footer: {
|
|
963
|
+
prefix: [],
|
|
964
|
+
suffix: [],
|
|
1174
965
|
},
|
|
1175
|
-
|
|
1176
|
-
});
|
|
1177
|
-
this.width = this.customWidth ? this.customWidth : (this.mergedOptions().width ?? '200px');
|
|
1178
|
-
this.allowResizing = this.mergedOptions().allowResizing || true;
|
|
1179
|
-
this.cdr.detectChanges();
|
|
1180
|
-
}
|
|
1181
|
-
getInputs(data) {
|
|
1182
|
-
return {
|
|
1183
|
-
rawValue: getSmart(data, this.node.path),
|
|
1184
|
-
rowData: data,
|
|
966
|
+
},
|
|
1185
967
|
};
|
|
968
|
+
if (popupService) {
|
|
969
|
+
this.popupService = popupService;
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
this.popupService = inject(AXPopupService);
|
|
973
|
+
}
|
|
1186
974
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
975
|
+
setOptions(options) {
|
|
976
|
+
this.dialogState.dialogOptions = { ...this.dialogState.dialogOptions, ...options };
|
|
977
|
+
return this;
|
|
978
|
+
}
|
|
979
|
+
// Individual fluent methods for Dialog
|
|
980
|
+
setTitle(title) {
|
|
981
|
+
return this.setOptions({ title });
|
|
982
|
+
}
|
|
983
|
+
setMessage(message) {
|
|
984
|
+
return this.setOptions({ message });
|
|
985
|
+
}
|
|
986
|
+
setSize(size) {
|
|
987
|
+
return this.setOptions({ size });
|
|
988
|
+
}
|
|
989
|
+
setCloseButton(closeButton) {
|
|
990
|
+
return this.setOptions({ closeButton });
|
|
991
|
+
}
|
|
992
|
+
setContext(context) {
|
|
993
|
+
return this.setOptions({ context });
|
|
994
|
+
}
|
|
995
|
+
content(delegate) {
|
|
996
|
+
if (delegate) {
|
|
997
|
+
// Create a flex container directly instead of through LayoutBuilder
|
|
998
|
+
const flexContainer = new FlexContainerBuilder();
|
|
999
|
+
flexContainer.setDirection('column');
|
|
1000
|
+
flexContainer.setGap('10px');
|
|
1001
|
+
delegate(flexContainer);
|
|
1002
|
+
this.contentLayout = flexContainer.build();
|
|
1213
1003
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1004
|
+
return this;
|
|
1005
|
+
}
|
|
1006
|
+
setActions(delegate) {
|
|
1007
|
+
if (delegate) {
|
|
1008
|
+
const actionBuilder = new ActionBuilder(this);
|
|
1009
|
+
delegate(actionBuilder);
|
|
1010
|
+
}
|
|
1011
|
+
return this;
|
|
1012
|
+
}
|
|
1013
|
+
// Build method to create dialog node
|
|
1014
|
+
build() {
|
|
1015
|
+
// If we have content layout, use it directly to avoid extra wrapper
|
|
1016
|
+
if (this.contentLayout) {
|
|
1017
|
+
return {
|
|
1018
|
+
...this.contentLayout,
|
|
1019
|
+
// Add dialog-specific properties
|
|
1020
|
+
options: {
|
|
1021
|
+
...this.contentLayout.options,
|
|
1022
|
+
...this.dialogState.dialogOptions,
|
|
1023
|
+
},
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
// Fallback to dialog state structure if no content
|
|
1027
|
+
const result = {
|
|
1028
|
+
...this.dialogState,
|
|
1029
|
+
children: [],
|
|
1030
|
+
};
|
|
1031
|
+
// Add dialog-specific properties
|
|
1032
|
+
if (this.dialogState.dialogOptions) {
|
|
1033
|
+
result.options = { ...result.options, ...this.dialogState.dialogOptions };
|
|
1218
1034
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1035
|
+
return result;
|
|
1036
|
+
}
|
|
1037
|
+
// Dialog-specific methods
|
|
1038
|
+
async show() {
|
|
1039
|
+
const dialogNode = this.build();
|
|
1040
|
+
// Import the dialog renderer component dynamically
|
|
1041
|
+
const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
|
|
1042
|
+
// Create dialog configuration
|
|
1043
|
+
const dialogConfig = {
|
|
1044
|
+
title: this.dialogState.dialogOptions?.title || '',
|
|
1045
|
+
message: this.dialogState.dialogOptions?.message,
|
|
1046
|
+
context: this.dialogState.dialogOptions?.context || {},
|
|
1047
|
+
definition: dialogNode,
|
|
1048
|
+
actions: this.dialogState.actions,
|
|
1049
|
+
};
|
|
1050
|
+
// The Promise resolves when user clicks an action button
|
|
1051
|
+
return new Promise(async (resolve) => {
|
|
1052
|
+
this.popupService.open(AXPDialogRendererComponent, {
|
|
1053
|
+
title: dialogConfig.title,
|
|
1054
|
+
size: this.dialogState.dialogOptions?.size || 'md',
|
|
1055
|
+
closeButton: this.dialogState.dialogOptions?.closeButton || false,
|
|
1056
|
+
closeOnBackdropClick: false,
|
|
1057
|
+
draggable: false,
|
|
1058
|
+
data: {
|
|
1059
|
+
config: dialogConfig,
|
|
1060
|
+
callBack: (result) => {
|
|
1061
|
+
// Resolve with the dialog reference when user clicks an action
|
|
1062
|
+
resolve(result);
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1065
|
+
});
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1223
1068
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
@if (loadingRow() === row) {
|
|
1241
|
-
<i class="fas fa-spinner-third ax-animate-twSpin ax-animate-infinite"></i>
|
|
1242
|
-
} @else {
|
|
1243
|
-
@if (row.data?.__meta__?.expanded) {
|
|
1244
|
-
<i [class]="customCollapseIcon || 'far fa-minus-square ax-text-md ax-opacity-75'"></i>
|
|
1245
|
-
} @else {
|
|
1246
|
-
<i [class]="customExpandIcon || 'far fa-plus-square ax-text-md ax-opacity-75'"></i>
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
</div>
|
|
1250
|
-
}
|
|
1251
|
-
@if (component && widgetInjector && row?.data) {
|
|
1252
|
-
<ng-container
|
|
1253
|
-
*ngComponentOutlet="component; injector: widgetInjector; inputs: getInputs(row.data)"
|
|
1254
|
-
></ng-container>
|
|
1255
|
-
}
|
|
1256
|
-
</div>
|
|
1257
|
-
</ng-template>
|
|
1258
|
-
<ng-template #footer></ng-template>
|
|
1259
|
-
`,
|
|
1260
|
-
providers: [
|
|
1261
|
-
AXPLayoutBuilderService,
|
|
1262
|
-
{ provide: AXDataTableColumnComponent, useExisting: AXPWidgetColumnRendererComponent },
|
|
1263
|
-
],
|
|
1264
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1265
|
-
inputs: ['caption'],
|
|
1266
|
-
standalone: false,
|
|
1267
|
-
}]
|
|
1268
|
-
}], propDecorators: { customExpandIcon: [{
|
|
1269
|
-
type: Input
|
|
1270
|
-
}], customCollapseIcon: [{
|
|
1271
|
-
type: Input
|
|
1272
|
-
}], customWidth: [{
|
|
1273
|
-
type: Input
|
|
1274
|
-
}], node: [{
|
|
1275
|
-
type: Input,
|
|
1276
|
-
args: [{ required: true }]
|
|
1277
|
-
}], footerTemplate: [{
|
|
1278
|
-
type: Input
|
|
1279
|
-
}], _contentFooterTemplate: [{
|
|
1280
|
-
type: ViewChild,
|
|
1281
|
-
args: ['footer']
|
|
1282
|
-
}], expandHandler: [{
|
|
1283
|
-
type: Input
|
|
1284
|
-
}], cellTemplate: [{
|
|
1285
|
-
type: Input
|
|
1286
|
-
}], _contentCellTemplate: [{
|
|
1287
|
-
type: ViewChild,
|
|
1288
|
-
args: ['cell']
|
|
1289
|
-
}], headerTemplate: [{
|
|
1290
|
-
type: Input
|
|
1291
|
-
}], _contentHeaderTemplate: [{
|
|
1292
|
-
type: ViewChild,
|
|
1293
|
-
args: ['header']
|
|
1294
|
-
}] } });
|
|
1295
|
-
|
|
1296
|
-
class AXPWidgetContainerComponent {
|
|
1297
|
-
set context(value) {
|
|
1298
|
-
this.contextService.set(value);
|
|
1069
|
+
//#endregion
|
|
1070
|
+
//#region ---- Widget Builder Implementation ----
|
|
1071
|
+
/**
|
|
1072
|
+
* Widget Builder - Single Responsibility Principle
|
|
1073
|
+
* Handles individual widget configuration and building
|
|
1074
|
+
*/
|
|
1075
|
+
class WidgetBuilder {
|
|
1076
|
+
constructor(name) {
|
|
1077
|
+
this.widgetState = {
|
|
1078
|
+
type: 'widget',
|
|
1079
|
+
options: {},
|
|
1080
|
+
};
|
|
1081
|
+
this.inheritanceContext = {};
|
|
1082
|
+
if (name) {
|
|
1083
|
+
this.widgetState.name = name;
|
|
1084
|
+
}
|
|
1299
1085
|
}
|
|
1300
|
-
|
|
1301
|
-
this.
|
|
1086
|
+
type(type) {
|
|
1087
|
+
this.widgetState.type = type;
|
|
1088
|
+
return this;
|
|
1302
1089
|
}
|
|
1303
|
-
|
|
1304
|
-
this.
|
|
1305
|
-
this.
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1090
|
+
name(name) {
|
|
1091
|
+
this.widgetState.name = name;
|
|
1092
|
+
if (!this.widgetState.path) {
|
|
1093
|
+
this.widgetState.path = name;
|
|
1094
|
+
}
|
|
1095
|
+
return this;
|
|
1096
|
+
}
|
|
1097
|
+
path(path) {
|
|
1098
|
+
this.widgetState.path = path;
|
|
1099
|
+
return this;
|
|
1100
|
+
}
|
|
1101
|
+
options(options) {
|
|
1102
|
+
// Merge options instead of replacing to preserve inherited properties
|
|
1103
|
+
this.widgetState.options = { ...this.widgetState.options, ...options };
|
|
1104
|
+
return this;
|
|
1105
|
+
}
|
|
1106
|
+
layout(value) {
|
|
1107
|
+
if (typeof value === 'number') {
|
|
1108
|
+
this.widgetState.layout = {
|
|
1109
|
+
positions: {
|
|
1110
|
+
sm: { colSpan: 12 },
|
|
1111
|
+
md: { colSpan: 12 },
|
|
1112
|
+
lg: { colSpan: value },
|
|
1113
|
+
xl: { colSpan: value },
|
|
1114
|
+
xxl: { colSpan: value },
|
|
1115
|
+
},
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
this.widgetState.layout = value;
|
|
1120
|
+
}
|
|
1121
|
+
return this;
|
|
1318
1122
|
}
|
|
1319
|
-
|
|
1320
|
-
this.
|
|
1123
|
+
mode(mode) {
|
|
1124
|
+
this.widgetState.mode = mode;
|
|
1125
|
+
this.inheritanceContext.mode = mode;
|
|
1126
|
+
return this;
|
|
1321
1127
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1128
|
+
visible(condition) {
|
|
1129
|
+
if (!this.widgetState.options) {
|
|
1130
|
+
this.widgetState.options = {};
|
|
1131
|
+
}
|
|
1132
|
+
this.widgetState.options['visible'] = condition;
|
|
1133
|
+
this.inheritanceContext.visible = condition;
|
|
1134
|
+
return this;
|
|
1324
1135
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
template: `<ng-content></ng-content>`,
|
|
1333
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1334
|
-
host: { style: 'display: contents;' },
|
|
1335
|
-
providers: [AXPLayoutBuilderService, AXPLayoutBuilderContextStore],
|
|
1336
|
-
standalone: false,
|
|
1337
|
-
}]
|
|
1338
|
-
}], ctorParameters: () => [], propDecorators: { onContextChanged: [{
|
|
1339
|
-
type: Output
|
|
1340
|
-
}], context: [{
|
|
1341
|
-
type: Input
|
|
1342
|
-
}], functions: [{
|
|
1343
|
-
type: Input
|
|
1344
|
-
}] } });
|
|
1345
|
-
|
|
1346
|
-
class AXPWidgetPlaceholderComponent {
|
|
1347
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPWidgetPlaceholderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1348
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.8", type: AXPWidgetPlaceholderComponent, isStandalone: true, selector: "axp-widget-placeholder", ngImport: i0, template: `<div>
|
|
1349
|
-
<ax-skeleton class="ax-w-full ax-h-10 ax-rounded-md"></ax-skeleton>
|
|
1350
|
-
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i1$1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1351
|
-
}
|
|
1352
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPWidgetPlaceholderComponent, decorators: [{
|
|
1353
|
-
type: Component,
|
|
1354
|
-
args: [{
|
|
1355
|
-
selector: 'axp-widget-placeholder',
|
|
1356
|
-
template: `<div>
|
|
1357
|
-
<ax-skeleton class="ax-w-full ax-h-10 ax-rounded-md"></ax-skeleton>
|
|
1358
|
-
</div>`,
|
|
1359
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1360
|
-
imports: [AXSkeletonModule],
|
|
1361
|
-
standalone: true,
|
|
1362
|
-
}]
|
|
1363
|
-
}] });
|
|
1364
|
-
|
|
1365
|
-
class AXPWidgetRendererDirective {
|
|
1366
|
-
//#endregion
|
|
1367
|
-
constructor() {
|
|
1368
|
-
this.parentNode = input(...(ngDevMode ? [undefined, { debugName: "parentNode" }] : []));
|
|
1369
|
-
this.index = input(...(ngDevMode ? [undefined, { debugName: "index" }] : []));
|
|
1370
|
-
this.mode = input.required(...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
1371
|
-
this.node = input.required(...(ngDevMode ? [{ debugName: "node" }] : []));
|
|
1372
|
-
this._options = signal({}, ...(ngDevMode ? [{ debugName: "_options" }] : []));
|
|
1373
|
-
this.options = this._options.asReadonly();
|
|
1374
|
-
this.onOptionsChanged = output();
|
|
1375
|
-
this.onValueChanged = output();
|
|
1376
|
-
//#region ---- Properties ----
|
|
1377
|
-
this.mergedOptions = signal({}, ...(ngDevMode ? [{ debugName: "mergedOptions" }] : []));
|
|
1378
|
-
this.injector = inject(Injector);
|
|
1379
|
-
this.builderService = inject(AXPLayoutBuilderService);
|
|
1380
|
-
this.contextService = inject(AXPLayoutBuilderContextStore);
|
|
1381
|
-
this.widgetRegistery = inject(AXPWidgetRegistryService);
|
|
1382
|
-
this.unsubscriber = inject(AXUnsubscriber);
|
|
1383
|
-
this.translateService = inject(AXTranslationService);
|
|
1384
|
-
this.widgetService = inject(AXPWidgetRegistryService);
|
|
1385
|
-
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
1386
|
-
this.viewContainerRef = inject(ViewContainerRef);
|
|
1387
|
-
this.isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
1388
|
-
this.expressionEvaluators = new Map();
|
|
1389
|
-
this.renderTimeoutId = null;
|
|
1390
|
-
this.hasInitialRender = false;
|
|
1391
|
-
this.onContextChanged = new Subject();
|
|
1392
|
-
effect(async () => {
|
|
1393
|
-
const changed = this.contextService.changeEvent();
|
|
1394
|
-
// Don't trigger re-render during initial setup
|
|
1395
|
-
if (!this.hasInitialRender) {
|
|
1396
|
-
return;
|
|
1397
|
-
}
|
|
1398
|
-
if ((await this.updateOptionsBasedOnContext()) > 0) {
|
|
1399
|
-
this.applyOptions();
|
|
1400
|
-
}
|
|
1401
|
-
if (this.checkFormulaForUpdate(this.node().formula, changed.path)) {
|
|
1402
|
-
await this.updateValueBasedOnFormula();
|
|
1403
|
-
}
|
|
1404
|
-
//
|
|
1405
|
-
if (changed.path) {
|
|
1406
|
-
this.onContextChanged.next({ path: changed.path });
|
|
1407
|
-
}
|
|
1408
|
-
});
|
|
1409
|
-
this.builderService.onRefresh.pipe(this.unsubscriber.takeUntilDestroy).subscribe(async () => {
|
|
1410
|
-
if ((await this.updateOptionsBasedOnContext()) > 0) {
|
|
1411
|
-
this.applyOptions();
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1136
|
+
disabled(condition) {
|
|
1137
|
+
if (!this.widgetState.options) {
|
|
1138
|
+
this.widgetState.options = {};
|
|
1139
|
+
}
|
|
1140
|
+
this.widgetState.options['disabled'] = condition;
|
|
1141
|
+
this.inheritanceContext.disabled = condition;
|
|
1142
|
+
return this;
|
|
1414
1143
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
rerenderComponent() {
|
|
1423
|
-
// Clear any pending render operation to prevent double rendering
|
|
1424
|
-
if (this.renderTimeoutId) {
|
|
1425
|
-
clearTimeout(this.renderTimeoutId);
|
|
1426
|
-
this.renderTimeoutId = null;
|
|
1427
|
-
}
|
|
1428
|
-
// Reset loading state to allow re-rendering
|
|
1429
|
-
this.isLoading.set(false);
|
|
1430
|
-
// Schedule the component loading
|
|
1431
|
-
this.renderTimeoutId = setTimeout(async () => {
|
|
1432
|
-
await this.loadComponent();
|
|
1433
|
-
this.renderTimeoutId = null;
|
|
1434
|
-
});
|
|
1144
|
+
readonly(condition) {
|
|
1145
|
+
if (!this.widgetState.options) {
|
|
1146
|
+
this.widgetState.options = {};
|
|
1147
|
+
}
|
|
1148
|
+
this.widgetState.options['readonly'] = condition;
|
|
1149
|
+
this.inheritanceContext.readonly = condition;
|
|
1150
|
+
return this;
|
|
1435
1151
|
}
|
|
1436
|
-
|
|
1437
|
-
if (this.
|
|
1438
|
-
|
|
1152
|
+
direction(direction) {
|
|
1153
|
+
if (!this.widgetState.options) {
|
|
1154
|
+
this.widgetState.options = {};
|
|
1439
1155
|
}
|
|
1440
|
-
|
|
1441
|
-
|
|
1156
|
+
this.widgetState.options['direction'] = direction;
|
|
1157
|
+
this.inheritanceContext.direction = direction;
|
|
1158
|
+
return this;
|
|
1159
|
+
}
|
|
1160
|
+
// Inheritance context methods
|
|
1161
|
+
withInheritanceContext(context) {
|
|
1162
|
+
this.inheritanceContext = mergeInheritanceContext(context);
|
|
1163
|
+
// Apply inherited properties to widget state
|
|
1164
|
+
const resolved = resolveInheritedProperties(context, this.inheritanceContext);
|
|
1165
|
+
// Always apply inherited properties (remove the conditions that check if already set)
|
|
1166
|
+
// This allows properties to be updated when inheritance context changes
|
|
1167
|
+
if (resolved.mode) {
|
|
1168
|
+
this.widgetState.mode = resolved.mode;
|
|
1442
1169
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
if (
|
|
1446
|
-
|
|
1170
|
+
if (!this.widgetState.options)
|
|
1171
|
+
this.widgetState.options = {};
|
|
1172
|
+
if (resolved.disabled !== undefined) {
|
|
1173
|
+
this.widgetState.options['disabled'] = resolved.disabled;
|
|
1447
1174
|
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
const propertiesToProcess = [
|
|
1459
|
-
...(widget?.properties ?? []),
|
|
1460
|
-
...(widget?.components[this.mode()]?.properties ?? []),
|
|
1461
|
-
]?.filter((c) => c.schema.defaultValue != null);
|
|
1462
|
-
// Process default values (evaluate expressions if needed)
|
|
1463
|
-
const props = {};
|
|
1464
|
-
for (const property of propertiesToProcess) {
|
|
1465
|
-
const defaultValue = property.schema.defaultValue;
|
|
1466
|
-
if (typeof defaultValue === 'string' && this.expressionEvaluator.isExpression(defaultValue)) {
|
|
1467
|
-
// Evaluate expression for default value
|
|
1468
|
-
try {
|
|
1469
|
-
const evaluatedValue = await this.evaluateExpression(defaultValue);
|
|
1470
|
-
props[property.name] = evaluatedValue;
|
|
1471
|
-
}
|
|
1472
|
-
catch (error) {
|
|
1473
|
-
console.error(`Error evaluating default value expression for property ${property.name}:`, error);
|
|
1474
|
-
props[property.name] = cloneDeep(defaultValue); // Fallback to original value
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
else {
|
|
1478
|
-
// Use static default value
|
|
1479
|
-
props[property.name] = cloneDeep(defaultValue);
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
//
|
|
1483
|
-
this.mergedOptions.set(merge(props, widget?.options, this.node().options) || {});
|
|
1484
|
-
this.preprocessAndInitialOptions(cloneDeep(this.node().options));
|
|
1485
|
-
await this.updateOptionsBasedOnContext();
|
|
1486
|
-
//
|
|
1487
|
-
this._options.update((val) => ({ ...val, ...this.mergedOptions() }));
|
|
1488
|
-
// Evaluate default value
|
|
1489
|
-
let defaultValue = this.node().defaultValue;
|
|
1490
|
-
if (defaultValue && this.expressionEvaluator.isExpression(defaultValue)) {
|
|
1491
|
-
defaultValue = await this.evaluateExpression(defaultValue);
|
|
1492
|
-
}
|
|
1493
|
-
//
|
|
1494
|
-
const tokenValue = {
|
|
1495
|
-
node: this.node(),
|
|
1496
|
-
defaultValue: defaultValue,
|
|
1497
|
-
options: this.mergedOptions(),
|
|
1498
|
-
config: widget,
|
|
1499
|
-
};
|
|
1500
|
-
const token = Injector.create({
|
|
1501
|
-
parent: this.injector,
|
|
1502
|
-
providers: [
|
|
1503
|
-
{
|
|
1504
|
-
provide: AXP_WIDGET_TOKEN,
|
|
1505
|
-
useValue: tokenValue,
|
|
1506
|
-
},
|
|
1507
|
-
],
|
|
1508
|
-
});
|
|
1509
|
-
//
|
|
1510
|
-
const loadingRef = this.viewContainerRef.createComponent(AXPWidgetPlaceholderComponent);
|
|
1511
|
-
//
|
|
1512
|
-
const com = await widget?.components[this.mode()]?.component();
|
|
1513
|
-
if (!com) {
|
|
1514
|
-
console.error(`${this.node().type} widget component not found with mode: ${this.mode()}`);
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
this.componentRef = this.viewContainerRef.createComponent(com, { injector: token });
|
|
1518
|
-
this.instance = this.componentRef.instance;
|
|
1519
|
-
this.instance.setStatus(AXPWidgetStatus.Rendering);
|
|
1520
|
-
this.instance.parent = this.parentNode();
|
|
1521
|
-
this.instance.index = this.index();
|
|
1522
|
-
this.instance.mode = this.mode();
|
|
1523
|
-
this.instance.setStatus(AXPWidgetStatus.Rendered);
|
|
1524
|
-
this.instance?.onOptionsChanged?.pipe(this.unsubscriber.takeUntilDestroy).subscribe((c) => {
|
|
1525
|
-
this.onOptionsChanged.emit({ sender: this, widget: c.sender });
|
|
1526
|
-
});
|
|
1527
|
-
this.instance?.onValueChanged?.pipe(this.unsubscriber.takeUntilDestroy).subscribe((c) => {
|
|
1528
|
-
this.onValueChanged.emit({ sender: this, widget: c.sender });
|
|
1529
|
-
});
|
|
1530
|
-
await this.updateValueBasedOnFormula();
|
|
1531
|
-
await this.assignTriggers();
|
|
1532
|
-
//
|
|
1533
|
-
loadingRef.destroy();
|
|
1534
|
-
// Mark that initial render is complete
|
|
1535
|
-
this.hasInitialRender = true;
|
|
1536
|
-
}
|
|
1537
|
-
catch (error) {
|
|
1538
|
-
console.error('Error loading component:', error);
|
|
1539
|
-
}
|
|
1540
|
-
finally {
|
|
1541
|
-
this.isLoading.set(false);
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
applyOptions() {
|
|
1545
|
-
if (!this.instance)
|
|
1546
|
-
return;
|
|
1547
|
-
this._options.update((val) => ({ ...val, ...this.mergedOptions() }));
|
|
1548
|
-
this.instance.setOptions(this.mergedOptions());
|
|
1549
|
-
}
|
|
1550
|
-
checkFormulaForUpdate(formula, path) {
|
|
1551
|
-
if (formula) {
|
|
1552
|
-
const regex = /context\.eval\('([^']+)'\)/g;
|
|
1553
|
-
const matches = formula.match(regex);
|
|
1554
|
-
const nodes = matches ? matches.map((match) => match.match(/'([^']+)'/)[1]) : [];
|
|
1555
|
-
return nodes.includes(path);
|
|
1556
|
-
}
|
|
1557
|
-
else
|
|
1558
|
-
return false;
|
|
1175
|
+
if (resolved.readonly !== undefined) {
|
|
1176
|
+
this.widgetState.options['readonly'] = resolved.readonly;
|
|
1177
|
+
}
|
|
1178
|
+
if (resolved.direction !== undefined) {
|
|
1179
|
+
this.widgetState.options['direction'] = resolved.direction;
|
|
1180
|
+
}
|
|
1181
|
+
if (resolved.visible !== undefined) {
|
|
1182
|
+
this.widgetState.options['visible'] = resolved.visible;
|
|
1183
|
+
}
|
|
1184
|
+
return this;
|
|
1559
1185
|
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
}
|
|
1589
|
-
if (typeof value === 'string' && this.expressionEvaluator.isExpression(value)) {
|
|
1590
|
-
// Cache dynamic expression for later evaluation
|
|
1591
|
-
this.expressionEvaluators.set(currentPath, () => this.evaluateExpression(value));
|
|
1592
|
-
}
|
|
1593
|
-
else if (typeof value === 'object' &&
|
|
1594
|
-
value !== null &&
|
|
1595
|
-
(value.constructor === Object || Array.isArray(value))) {
|
|
1596
|
-
// Recursively handle nested objects
|
|
1597
|
-
this.preprocessAndInitialOptions(value, currentPath);
|
|
1598
|
-
}
|
|
1599
|
-
else {
|
|
1600
|
-
// Apply static values directly
|
|
1601
|
-
this.mergedOptions.update((currentOptions) => {
|
|
1602
|
-
return set(currentOptions, currentPath, value);
|
|
1603
|
-
});
|
|
1604
|
-
}
|
|
1186
|
+
getInheritanceContext() {
|
|
1187
|
+
return { ...this.inheritanceContext };
|
|
1188
|
+
}
|
|
1189
|
+
build() {
|
|
1190
|
+
return {
|
|
1191
|
+
name: this.widgetState.name,
|
|
1192
|
+
type: this.widgetState.type,
|
|
1193
|
+
options: this.widgetState.options,
|
|
1194
|
+
mode: this.widgetState.mode,
|
|
1195
|
+
path: this.widgetState.path,
|
|
1196
|
+
defaultValue: this.widgetState.defaultValue,
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
//#region ---- Action Builder Implementation ----
|
|
1201
|
+
class ActionBuilder {
|
|
1202
|
+
constructor(dialogBuilder) {
|
|
1203
|
+
this.dialogBuilder = dialogBuilder;
|
|
1204
|
+
}
|
|
1205
|
+
cancel(text) {
|
|
1206
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1207
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1208
|
+
}
|
|
1209
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push({
|
|
1210
|
+
title: text || '@general:actions.cancel.title',
|
|
1211
|
+
icon: 'fa-times',
|
|
1212
|
+
color: 'default',
|
|
1213
|
+
command: { name: 'cancel' },
|
|
1605
1214
|
});
|
|
1215
|
+
return this;
|
|
1606
1216
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1217
|
+
submit(text) {
|
|
1218
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1219
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1220
|
+
}
|
|
1221
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push({
|
|
1222
|
+
title: text || '@general:actions.submit.title',
|
|
1223
|
+
icon: 'fa-check',
|
|
1224
|
+
color: 'primary',
|
|
1225
|
+
command: { name: 'submit', options: { validate: true } },
|
|
1611
1226
|
});
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
if (
|
|
1616
|
-
this.
|
|
1617
|
-
const updatedOptions = { ...o };
|
|
1618
|
-
updates.forEach(({ path, newValue }) => {
|
|
1619
|
-
// Set the new value in the updatedOptions object by path
|
|
1620
|
-
set(updatedOptions, path, newValue); // Assuming 'set' can handle paths like 'property.subproperty'
|
|
1621
|
-
});
|
|
1622
|
-
return updatedOptions;
|
|
1623
|
-
});
|
|
1227
|
+
return this;
|
|
1228
|
+
}
|
|
1229
|
+
custom(action) {
|
|
1230
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1231
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1624
1232
|
}
|
|
1625
|
-
|
|
1233
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
|
|
1234
|
+
return this;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
class AXPLayoutConversionService {
|
|
1239
|
+
constructor() {
|
|
1240
|
+
//#region ---- Caching ----
|
|
1241
|
+
this.widgetTreeCache = new Map();
|
|
1242
|
+
this.formDefinitionCache = new Map();
|
|
1626
1243
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1244
|
+
//#endregion
|
|
1245
|
+
//#region ---- Public Methods ----
|
|
1246
|
+
/**
|
|
1247
|
+
* Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
|
|
1248
|
+
* Groups become Fieldset Layouts with Form Field widgets as children
|
|
1249
|
+
* Fields become Form Field widgets with Editor widgets as children
|
|
1250
|
+
*/
|
|
1251
|
+
convertFormDefinition(formDefinition) {
|
|
1252
|
+
// Create cache key based on form definition content
|
|
1253
|
+
const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
|
|
1254
|
+
// Check cache first
|
|
1255
|
+
if (this.widgetTreeCache.has(cacheKey)) {
|
|
1256
|
+
return this.widgetTreeCache.get(cacheKey);
|
|
1631
1257
|
}
|
|
1258
|
+
// Generate widget tree
|
|
1259
|
+
const widgetTree = {
|
|
1260
|
+
type: 'grid-layout',
|
|
1261
|
+
name: 'dynamic-form-container',
|
|
1262
|
+
options: {
|
|
1263
|
+
title: 'Dynamic Form',
|
|
1264
|
+
grid: {
|
|
1265
|
+
default: {
|
|
1266
|
+
columns: 1,
|
|
1267
|
+
gap: '1rem'
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
1271
|
+
children: formDefinition.groups.map(group => this.createGroupAsFieldsetWidget(group))
|
|
1272
|
+
};
|
|
1273
|
+
// Cache the result
|
|
1274
|
+
this.widgetTreeCache.set(cacheKey, widgetTree);
|
|
1275
|
+
return widgetTree;
|
|
1632
1276
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1277
|
+
/**
|
|
1278
|
+
* Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
|
|
1279
|
+
* Parses Fieldset Layouts back to Groups
|
|
1280
|
+
* Parses Form Field widgets back to Fields
|
|
1281
|
+
*/
|
|
1282
|
+
convertWidgetTreeToFormDefinition(widgetTree) {
|
|
1283
|
+
// Create cache key based on widget tree content
|
|
1284
|
+
const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
|
|
1285
|
+
// Check cache first
|
|
1286
|
+
if (this.formDefinitionCache.has(cacheKey)) {
|
|
1287
|
+
return this.formDefinitionCache.get(cacheKey);
|
|
1288
|
+
}
|
|
1289
|
+
// Parse widget tree
|
|
1290
|
+
const groups = [];
|
|
1291
|
+
if (widgetTree.children) {
|
|
1292
|
+
widgetTree.children.forEach(child => {
|
|
1293
|
+
if (child.type === 'fieldset-layout') {
|
|
1294
|
+
const group = this.extractGroupFromFieldset(child);
|
|
1295
|
+
groups.push(group);
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1637
1298
|
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1299
|
+
const formDefinition = { groups };
|
|
1300
|
+
// Cache the result
|
|
1301
|
+
this.formDefinitionCache.set(cacheKey, formDefinition);
|
|
1302
|
+
return formDefinition;
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Validate that a widget tree represents a valid dynamic form structure
|
|
1306
|
+
*/
|
|
1307
|
+
validateFormWidgetTree(widgetTree) {
|
|
1308
|
+
if (!widgetTree || widgetTree.type !== 'grid-layout') {
|
|
1640
1309
|
return false;
|
|
1641
1310
|
}
|
|
1311
|
+
if (!widgetTree.children || widgetTree.children.length === 0) {
|
|
1312
|
+
return true; // Empty form is valid
|
|
1313
|
+
}
|
|
1314
|
+
// Check that all children are fieldset-layout widgets
|
|
1315
|
+
return widgetTree.children.every(child => child.type === 'fieldset-layout' &&
|
|
1316
|
+
child.children &&
|
|
1317
|
+
child.children.every(formField => formField.type === 'form-field' &&
|
|
1318
|
+
formField.children &&
|
|
1319
|
+
formField.children.length > 0));
|
|
1642
1320
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
vars: this.getVariablesScope(),
|
|
1650
|
-
};
|
|
1321
|
+
/**
|
|
1322
|
+
* Clear all caches
|
|
1323
|
+
*/
|
|
1324
|
+
clearCaches() {
|
|
1325
|
+
this.widgetTreeCache.clear();
|
|
1326
|
+
this.formDefinitionCache.clear();
|
|
1651
1327
|
}
|
|
1652
|
-
|
|
1328
|
+
/**
|
|
1329
|
+
* Get cache statistics
|
|
1330
|
+
*/
|
|
1331
|
+
getCacheStats() {
|
|
1653
1332
|
return {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
const fullPath = path.startsWith('>') ? `${this.instance?.parentPath()}.${path.substring(1)}` : path;
|
|
1657
|
-
const value = this.contextService.getValue(fullPath);
|
|
1658
|
-
return value;
|
|
1659
|
-
},
|
|
1660
|
-
set: (path, value) => {
|
|
1661
|
-
this.contextService.update(path, value);
|
|
1662
|
-
},
|
|
1663
|
-
data: () => {
|
|
1664
|
-
return this.contextService.data();
|
|
1665
|
-
},
|
|
1666
|
-
isDirty: () => {
|
|
1667
|
-
return this.contextService.isDirty();
|
|
1668
|
-
},
|
|
1333
|
+
widgetTreeCacheSize: this.widgetTreeCache.size,
|
|
1334
|
+
formDefinitionCacheSize: this.formDefinitionCache.size
|
|
1669
1335
|
};
|
|
1670
1336
|
}
|
|
1671
|
-
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region ---- Private Methods ----
|
|
1339
|
+
/**
|
|
1340
|
+
* Convert a single group to Fieldset widget structure
|
|
1341
|
+
*/
|
|
1342
|
+
createGroupAsFieldsetWidget(group) {
|
|
1343
|
+
// Determine columns count from layout or default to 1
|
|
1344
|
+
const columnsCount = 1;
|
|
1672
1345
|
return {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
// Ensure c.path exists
|
|
1680
|
-
if (!c.path) {
|
|
1681
|
-
return false;
|
|
1682
|
-
}
|
|
1683
|
-
// Pattern: "prefix*" - matches paths that start with prefix
|
|
1684
|
-
if (path.endsWith('*')) {
|
|
1685
|
-
const prefix = path.substring(0, path.length - 1);
|
|
1686
|
-
return c.path.startsWith(prefix);
|
|
1687
|
-
}
|
|
1688
|
-
// Pattern: "*suffix" - matches paths that end with suffix
|
|
1689
|
-
else if (path.startsWith('*')) {
|
|
1690
|
-
const suffix = path.substring(1);
|
|
1691
|
-
return c.path.endsWith(suffix);
|
|
1692
|
-
}
|
|
1693
|
-
// Exact match
|
|
1694
|
-
else {
|
|
1695
|
-
return c.path === path;
|
|
1696
|
-
}
|
|
1697
|
-
}));
|
|
1346
|
+
type: 'fieldset-layout',
|
|
1347
|
+
name: group.name,
|
|
1348
|
+
options: {
|
|
1349
|
+
title: group.title,
|
|
1350
|
+
description: group.description,
|
|
1351
|
+
cols: columnsCount
|
|
1698
1352
|
},
|
|
1699
|
-
|
|
1353
|
+
children: this.createFieldWidgets(group.parameters, columnsCount)
|
|
1700
1354
|
};
|
|
1701
1355
|
}
|
|
1702
|
-
|
|
1356
|
+
/**
|
|
1357
|
+
* Convert fields to Form Field widgets
|
|
1358
|
+
*/
|
|
1359
|
+
createFieldWidgets(fields, columnsCount) {
|
|
1360
|
+
return fields.map(field => this.createFormFieldWidget(field));
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Convert a single field to Form Field widget with editor as child
|
|
1364
|
+
*/
|
|
1365
|
+
createFormFieldWidget(field) {
|
|
1703
1366
|
return {
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
clear: () => {
|
|
1711
|
-
this.instance.setValue(undefined);
|
|
1712
|
-
},
|
|
1713
|
-
refresh: () => {
|
|
1714
|
-
const refresh = this.instance?.['refresh'];
|
|
1715
|
-
if (refresh && typeof refresh === 'function') {
|
|
1716
|
-
refresh.bind(this.instance)();
|
|
1717
|
-
}
|
|
1718
|
-
},
|
|
1719
|
-
output: (name) => {
|
|
1720
|
-
this.instance.output(name);
|
|
1721
|
-
},
|
|
1722
|
-
find: (id) => {
|
|
1723
|
-
return this.builderService.getWidget(id);
|
|
1367
|
+
type: 'form-field',
|
|
1368
|
+
name: field.path,
|
|
1369
|
+
options: {
|
|
1370
|
+
label: field.title,
|
|
1371
|
+
description: field.description,
|
|
1372
|
+
showLabel: true
|
|
1724
1373
|
},
|
|
1374
|
+
children: [field.widget] // The editor widget becomes a child of form-field
|
|
1725
1375
|
};
|
|
1726
1376
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1377
|
+
/**
|
|
1378
|
+
* Extract group information from Fieldset Layout widget
|
|
1379
|
+
*/
|
|
1380
|
+
extractGroupFromFieldset(fieldsetNode) {
|
|
1381
|
+
const columnsCount = fieldsetNode.options?.['cols'] || 1;
|
|
1382
|
+
// Extract fields directly from fieldset children
|
|
1383
|
+
const fields = [];
|
|
1384
|
+
if (fieldsetNode.children) {
|
|
1385
|
+
fieldsetNode.children.forEach(formField => {
|
|
1386
|
+
if (formField.type === 'form-field' && formField.children && formField.children.length > 0) {
|
|
1387
|
+
const field = this.extractFieldFromFormWidget(formField);
|
|
1388
|
+
if (field) {
|
|
1389
|
+
fields.push(field);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
return {
|
|
1395
|
+
name: fieldsetNode.name || `group-${Date.now()}`,
|
|
1396
|
+
title: fieldsetNode.options?.['title'],
|
|
1397
|
+
description: fieldsetNode.options?.['description'],
|
|
1398
|
+
parameters: fields,
|
|
1738
1399
|
};
|
|
1739
|
-
// Add custom functions from builder service
|
|
1740
|
-
Object.entries(this.builderService.functions).forEach(([key, fn]) => {
|
|
1741
|
-
scope[key] = (...args) => {
|
|
1742
|
-
return fn(...args);
|
|
1743
|
-
};
|
|
1744
|
-
});
|
|
1745
|
-
return scope;
|
|
1746
1400
|
}
|
|
1747
|
-
|
|
1401
|
+
/**
|
|
1402
|
+
* Extract field information from Form Field widget
|
|
1403
|
+
*/
|
|
1404
|
+
extractFieldFromFormWidget(formFieldNode) {
|
|
1405
|
+
if (!formFieldNode.children || formFieldNode.children.length === 0) {
|
|
1406
|
+
return null;
|
|
1407
|
+
}
|
|
1408
|
+
const editorWidget = formFieldNode.children[0];
|
|
1748
1409
|
return {
|
|
1749
|
-
|
|
1410
|
+
path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
|
|
1411
|
+
title: formFieldNode.options?.['label'],
|
|
1412
|
+
description: formFieldNode.options?.['description'],
|
|
1413
|
+
widget: editorWidget,
|
|
1414
|
+
mode: formFieldNode.mode
|
|
1750
1415
|
};
|
|
1751
1416
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
}
|
|
1768
|
-
};
|
|
1769
|
-
const actions = Array.isArray(trigger.action) ? trigger.action : [trigger.action];
|
|
1770
|
-
actions.forEach(async (a) => await exec(a));
|
|
1771
|
-
});
|
|
1772
|
-
}
|
|
1773
|
-
}
|
|
1774
|
-
catch (error) {
|
|
1775
|
-
console.error('Error assigning trigger:', error);
|
|
1776
|
-
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Create cache key for form definition
|
|
1419
|
+
*/
|
|
1420
|
+
createFormDefinitionCacheKey(formDefinition) {
|
|
1421
|
+
// Create a hash-like key instead of full JSON string
|
|
1422
|
+
const keyParts = [];
|
|
1423
|
+
keyParts.push(`groups:${formDefinition.groups.length}`);
|
|
1424
|
+
formDefinition.groups.forEach((group, groupIndex) => {
|
|
1425
|
+
keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
|
|
1426
|
+
group.parameters.forEach((param, paramIndex) => {
|
|
1427
|
+
keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
|
|
1428
|
+
});
|
|
1429
|
+
});
|
|
1430
|
+
if (formDefinition.mode) {
|
|
1431
|
+
keyParts.push(`mode:${formDefinition.mode}`);
|
|
1777
1432
|
}
|
|
1433
|
+
// Join with delimiter and create a shorter hash
|
|
1434
|
+
const keyString = keyParts.join('|');
|
|
1435
|
+
// If still too long, create a simple hash
|
|
1436
|
+
if (keyString.length > 100) {
|
|
1437
|
+
return this.createSimpleHash(keyString);
|
|
1438
|
+
}
|
|
1439
|
+
return keyString;
|
|
1778
1440
|
}
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
return null;
|
|
1789
|
-
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Create cache key for widget tree
|
|
1443
|
+
*/
|
|
1444
|
+
createWidgetTreeCacheKey(widgetTree) {
|
|
1445
|
+
// Create a hash-like key instead of full JSON string
|
|
1446
|
+
const keyParts = [];
|
|
1447
|
+
keyParts.push(`type:${widgetTree.type}`);
|
|
1448
|
+
if (widgetTree.name) {
|
|
1449
|
+
keyParts.push(`name:${widgetTree.name}`);
|
|
1790
1450
|
}
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1451
|
+
if (widgetTree.children) {
|
|
1452
|
+
keyParts.push(`children:${widgetTree.children.length}`);
|
|
1453
|
+
widgetTree.children.forEach((child, index) => {
|
|
1454
|
+
keyParts.push(`c${index}:${child.type}`);
|
|
1455
|
+
if (child.children) {
|
|
1456
|
+
keyParts.push(`cc${index}:${child.children.length}`);
|
|
1457
|
+
child.children.forEach((grandChild, gIndex) => {
|
|
1458
|
+
keyParts.push(`gc${index}.${gIndex}:${grandChild.type}`);
|
|
1459
|
+
if (grandChild.children) {
|
|
1460
|
+
keyParts.push(`gcc${index}.${gIndex}:${grandChild.children.length}`);
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
});
|
|
1794
1465
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1466
|
+
// Join with delimiter and create a shorter hash
|
|
1467
|
+
const keyString = keyParts.join('|');
|
|
1468
|
+
// If still too long, create a simple hash
|
|
1469
|
+
if (keyString.length > 100) {
|
|
1470
|
+
return this.createSimpleHash(keyString);
|
|
1800
1471
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1472
|
+
return keyString;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Create a simple hash from a string
|
|
1476
|
+
*/
|
|
1477
|
+
createSimpleHash(str) {
|
|
1478
|
+
let hash = 0;
|
|
1479
|
+
if (str.length === 0)
|
|
1480
|
+
return hash.toString();
|
|
1481
|
+
for (let i = 0; i < str.length; i++) {
|
|
1482
|
+
const char = str.charCodeAt(i);
|
|
1483
|
+
hash = ((hash << 5) - hash) + char;
|
|
1484
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
1803
1485
|
}
|
|
1486
|
+
return Math.abs(hash).toString(36); // Convert to base36 for shorter string
|
|
1804
1487
|
}
|
|
1805
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.
|
|
1806
|
-
static { this.ɵ
|
|
1807
|
-
{
|
|
1808
|
-
provide: AXUnsubscriber,
|
|
1809
|
-
},
|
|
1810
|
-
], exportAs: ["widgetRenderer"], usesOnChanges: true, ngImport: i0 }); }
|
|
1488
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1489
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
|
|
1811
1490
|
}
|
|
1812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
1813
|
-
type:
|
|
1491
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
|
|
1492
|
+
type: Injectable,
|
|
1814
1493
|
args: [{
|
|
1815
|
-
|
|
1816
|
-
exportAs: 'widgetRenderer',
|
|
1817
|
-
providers: [
|
|
1818
|
-
{
|
|
1819
|
-
provide: AXUnsubscriber,
|
|
1820
|
-
},
|
|
1821
|
-
],
|
|
1822
|
-
standalone: false,
|
|
1494
|
+
providedIn: 'root'
|
|
1823
1495
|
}]
|
|
1824
|
-
}]
|
|
1496
|
+
}] });
|
|
1825
1497
|
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1498
|
+
class AXPLayoutRendererComponent {
|
|
1499
|
+
constructor() {
|
|
1500
|
+
this.evaluatorService = inject(AXPExpressionEvaluatorService);
|
|
1501
|
+
this.conversionService = inject(AXPLayoutConversionService);
|
|
1502
|
+
/**
|
|
1503
|
+
* Tracks the latest scheduled evaluation to ensure last-write-wins for async evaluate
|
|
1504
|
+
*/
|
|
1505
|
+
this.evaluationRunId = 0;
|
|
1506
|
+
/**
|
|
1507
|
+
* RxJS subjects for context management
|
|
1508
|
+
*/
|
|
1509
|
+
this.contextUpdateSubject = new Subject();
|
|
1510
|
+
this.contextChangeSubject = new Subject();
|
|
1511
|
+
/**
|
|
1512
|
+
* Cache for expression evaluation results
|
|
1513
|
+
*/
|
|
1514
|
+
this.expressionCache = new Map();
|
|
1515
|
+
/**
|
|
1516
|
+
* Cache for widget tree comparisons
|
|
1517
|
+
*/
|
|
1518
|
+
this.widgetTreeCache = new Map();
|
|
1519
|
+
/**
|
|
1520
|
+
* Last layout hash for change detection
|
|
1521
|
+
*/
|
|
1522
|
+
this.lastLayoutHash = '';
|
|
1523
|
+
//#region ---- Inputs ----
|
|
1524
|
+
/**
|
|
1525
|
+
* Form definition containing groups and fields OR widget tree
|
|
1526
|
+
*/
|
|
1527
|
+
this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : []));
|
|
1528
|
+
/**
|
|
1529
|
+
* Form context/model data
|
|
1530
|
+
*/
|
|
1531
|
+
this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
1532
|
+
/**
|
|
1533
|
+
* Form appearance and density styling (normal, compact, spacious)
|
|
1534
|
+
*/
|
|
1535
|
+
this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : []));
|
|
1536
|
+
/**
|
|
1537
|
+
* Default form mode. Can be overridden by section/group and field.
|
|
1538
|
+
*/
|
|
1539
|
+
this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
1540
|
+
//#endregion
|
|
1541
|
+
//#region ---- Widget Tree Conversion ----
|
|
1542
|
+
this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : []));
|
|
1543
|
+
/**
|
|
1544
|
+
* Convert and evaluate data when inputs change (optimized with RxJS)
|
|
1545
|
+
*/
|
|
1546
|
+
this.conversionEffect = effect(() => {
|
|
1547
|
+
const inputData = this.layout();
|
|
1548
|
+
const ctx = this.internalContext();
|
|
1549
|
+
const look = this.look();
|
|
1550
|
+
const runId = ++this.evaluationRunId;
|
|
1551
|
+
// Generate layout hash for change detection
|
|
1552
|
+
const layoutHash = this.generateLayoutHash(inputData, look);
|
|
1553
|
+
// Skip if layout hasn't changed
|
|
1554
|
+
if (layoutHash === this.lastLayoutHash && this.widgetTree()) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
this.lastLayoutHash = layoutHash;
|
|
1558
|
+
(async () => {
|
|
1559
|
+
// First evaluate expressions if needed
|
|
1560
|
+
const evaluated = await this.expressionEvaluator(inputData, ctx);
|
|
1561
|
+
// Ignore stale results
|
|
1562
|
+
if (runId !== this.evaluationRunId) {
|
|
1563
|
+
return;
|
|
1564
|
+
}
|
|
1565
|
+
// Convert to widget tree (this will also apply the layout look)
|
|
1566
|
+
const tree = evaluated;
|
|
1567
|
+
// Update widget tree
|
|
1568
|
+
const prev = this.widgetTree();
|
|
1569
|
+
if (!isEqual(prev, tree)) {
|
|
1570
|
+
tree.mode = this.mode();
|
|
1571
|
+
this.widgetTree.set(tree);
|
|
1572
|
+
}
|
|
1573
|
+
})();
|
|
1574
|
+
}, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : []));
|
|
1575
|
+
//#endregion
|
|
1576
|
+
//#region ---- Outputs ----
|
|
1577
|
+
/**
|
|
1578
|
+
* Emitted when context change is initiated
|
|
1579
|
+
*/
|
|
1580
|
+
this.contextInitiated = output();
|
|
1581
|
+
/**
|
|
1582
|
+
* Emitted when form becomes valid/invalid
|
|
1583
|
+
*/
|
|
1584
|
+
this.validityChange = output();
|
|
1585
|
+
//#endregion
|
|
1586
|
+
//#region ---- Properties ----
|
|
1587
|
+
this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
1588
|
+
this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
|
|
1589
|
+
/**
|
|
1590
|
+
* Internal context signal for reactivity
|
|
1591
|
+
*/
|
|
1592
|
+
this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : []));
|
|
1593
|
+
/**
|
|
1594
|
+
* Initial context for reset functionality
|
|
1595
|
+
*/
|
|
1596
|
+
this.initialContext = {};
|
|
1597
|
+
//#endregion
|
|
1598
|
+
//#region ---- Effects ----
|
|
1599
|
+
/**
|
|
1600
|
+
* Effect to sync context changes from external to internal (optimized with RxJS)
|
|
1601
|
+
*/
|
|
1602
|
+
this.#contextSyncEffect = effect(() => {
|
|
1603
|
+
const ctx = this.context() ?? {};
|
|
1604
|
+
this.contextUpdateSubject.next(ctx);
|
|
1605
|
+
}, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : []));
|
|
1606
|
+
/**
|
|
1607
|
+
* Effect to handle widget tree status changes
|
|
1608
|
+
*/
|
|
1609
|
+
this.#widgetStatusEffect = effect(() => {
|
|
1610
|
+
const widgetTree = this.widgetTree();
|
|
1611
|
+
if (widgetTree) {
|
|
1612
|
+
this.container()?.builderService.setStatus(AXPPageStatus.Rendered);
|
|
1613
|
+
}
|
|
1614
|
+
}, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : []));
|
|
1615
|
+
}
|
|
1616
|
+
async expressionEvaluator(expression, context) {
|
|
1617
|
+
// Check if it's a form definition that needs conversion
|
|
1618
|
+
if (this.isFormDefinition(expression)) {
|
|
1619
|
+
return this.conversionService.convertFormDefinition(expression);
|
|
1620
|
+
}
|
|
1621
|
+
// Generate cache key using a more efficient method
|
|
1622
|
+
const cacheKey = this.generateCacheKey(expression, context);
|
|
1623
|
+
// Check cache first
|
|
1624
|
+
if (this.expressionCache.has(cacheKey)) {
|
|
1625
|
+
return this.expressionCache.get(cacheKey);
|
|
1626
|
+
}
|
|
1627
|
+
const scope = {
|
|
1628
|
+
context: {
|
|
1629
|
+
eval: (path) => get(context, path),
|
|
1630
|
+
},
|
|
1842
1631
|
};
|
|
1632
|
+
const result = await this.evaluatorService.evaluate(expression, scope);
|
|
1633
|
+
// Cache result with LRU-like behavior
|
|
1634
|
+
if (this.expressionCache.size > 50) {
|
|
1635
|
+
// Clear half the cache when it gets too large
|
|
1636
|
+
const keysToDelete = Array.from(this.expressionCache.keys()).slice(0, 25);
|
|
1637
|
+
keysToDelete.forEach(key => this.expressionCache.delete(key));
|
|
1638
|
+
}
|
|
1639
|
+
this.expressionCache.set(cacheKey, result);
|
|
1640
|
+
return result;
|
|
1641
|
+
}
|
|
1642
|
+
//#endregion
|
|
1643
|
+
//#region ---- Lifecycle Methods ----
|
|
1644
|
+
ngOnInit() {
|
|
1645
|
+
// Initialize internal context with input context
|
|
1646
|
+
const ctx = this.context() ?? {};
|
|
1647
|
+
this.internalContext.set(ctx);
|
|
1648
|
+
// Store initial context for reset functionality
|
|
1649
|
+
this.initialContext = cloneDeep(ctx);
|
|
1650
|
+
// Setup RxJS streams for context management
|
|
1651
|
+
this.setupContextStreams();
|
|
1652
|
+
}
|
|
1653
|
+
//#endregion
|
|
1654
|
+
//#region ---- Effects ----
|
|
1655
|
+
/**
|
|
1656
|
+
* Effect to sync context changes from external to internal (optimized with RxJS)
|
|
1657
|
+
*/
|
|
1658
|
+
#contextSyncEffect;
|
|
1659
|
+
/**
|
|
1660
|
+
* Effect to handle widget tree status changes
|
|
1661
|
+
*/
|
|
1662
|
+
#widgetStatusEffect;
|
|
1663
|
+
//#endregion
|
|
1664
|
+
//#region ---- Event Handlers ----
|
|
1665
|
+
/**
|
|
1666
|
+
* Handle context change events from widget container (optimized with RxJS)
|
|
1667
|
+
*/
|
|
1668
|
+
handleContextChanged(event) {
|
|
1669
|
+
if (event.state === 'initiated') {
|
|
1670
|
+
this.contextInitiated.emit(event.data);
|
|
1671
|
+
}
|
|
1672
|
+
else {
|
|
1673
|
+
this.contextChangeSubject.next(event.data ?? {});
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
//#endregion
|
|
1677
|
+
//#region ---- Public Methods ----
|
|
1678
|
+
/**
|
|
1679
|
+
* Get the form component instance
|
|
1680
|
+
*/
|
|
1681
|
+
getForm() {
|
|
1682
|
+
return this.form();
|
|
1683
|
+
}
|
|
1684
|
+
/**
|
|
1685
|
+
* Get the widget container component instance
|
|
1686
|
+
*/
|
|
1687
|
+
getContainer() {
|
|
1688
|
+
return this.container();
|
|
1689
|
+
}
|
|
1690
|
+
/**
|
|
1691
|
+
* Get current form context
|
|
1692
|
+
*/
|
|
1693
|
+
getContext() {
|
|
1694
|
+
return this.internalContext();
|
|
1695
|
+
}
|
|
1696
|
+
/**
|
|
1697
|
+
* Update form context programmatically
|
|
1698
|
+
*/
|
|
1699
|
+
updateContext(context) {
|
|
1700
|
+
this.internalContext.set(context);
|
|
1843
1701
|
}
|
|
1844
|
-
|
|
1702
|
+
/**
|
|
1703
|
+
* Get the current widget tree
|
|
1704
|
+
*/
|
|
1705
|
+
getWidgetTree() {
|
|
1706
|
+
return this.widgetTree();
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Validate the form
|
|
1710
|
+
*/
|
|
1711
|
+
async validate() {
|
|
1712
|
+
const form = this.form();
|
|
1713
|
+
if (form) {
|
|
1714
|
+
const isValid = await form.validate();
|
|
1715
|
+
this.validityChange.emit(isValid.result);
|
|
1716
|
+
return isValid;
|
|
1717
|
+
}
|
|
1845
1718
|
return {
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
provide: 'AXPLayoutBuilderModuleFactory',
|
|
1850
|
-
useFactory: (registry) => async () => {
|
|
1851
|
-
await Promise.all(config?.widgets?.map((w) => Promise.resolve(registry.register(w))) || []);
|
|
1852
|
-
await Promise.all(config?.extendedWidgets?.map((ew) => Promise.resolve(registry.extend(ew.parentName, ew.widget))) || []);
|
|
1853
|
-
},
|
|
1854
|
-
deps: [AXPWidgetRegistryService],
|
|
1855
|
-
multi: true,
|
|
1856
|
-
},
|
|
1857
|
-
],
|
|
1719
|
+
result: false,
|
|
1720
|
+
messages: [],
|
|
1721
|
+
rules: [],
|
|
1858
1722
|
};
|
|
1859
1723
|
}
|
|
1860
1724
|
/**
|
|
1861
|
-
*
|
|
1725
|
+
* Clear the form context
|
|
1862
1726
|
*/
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1727
|
+
clear() {
|
|
1728
|
+
// Clear internal context
|
|
1729
|
+
this.internalContext.set({});
|
|
1730
|
+
// Update the model signal
|
|
1731
|
+
this.context.set({});
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Reset the form to its initial state
|
|
1735
|
+
*/
|
|
1736
|
+
reset() {
|
|
1737
|
+
// Reset to initial context
|
|
1738
|
+
const resetContext = cloneDeep(this.initialContext);
|
|
1739
|
+
this.internalContext.set(resetContext);
|
|
1740
|
+
// Update the model signal
|
|
1741
|
+
this.context.set(resetContext);
|
|
1742
|
+
}
|
|
1743
|
+
//#endregion
|
|
1744
|
+
//#region ---- RxJS Stream Setup ----
|
|
1745
|
+
/**
|
|
1746
|
+
* Setup RxJS streams for context management
|
|
1747
|
+
*/
|
|
1748
|
+
setupContextStreams() {
|
|
1749
|
+
// Debounced context updates from external source
|
|
1750
|
+
this.contextUpdateSubject
|
|
1751
|
+
.pipe(debounceTime(16), // ~60fps
|
|
1752
|
+
distinctUntilChanged((prev, curr) => isEqual(prev, curr)), startWith(this.context() ?? {}))
|
|
1753
|
+
.subscribe(ctx => {
|
|
1754
|
+
this.internalContext.set(ctx);
|
|
1866
1755
|
});
|
|
1756
|
+
// Debounced context changes from widgets
|
|
1757
|
+
this.contextChangeSubject
|
|
1758
|
+
.pipe(debounceTime(16), // ~60fps
|
|
1759
|
+
distinctUntilChanged((prev, curr) => isEqual(prev, curr)))
|
|
1760
|
+
.subscribe(ctx => {
|
|
1761
|
+
this.internalContext.set(ctx);
|
|
1762
|
+
// Update the model signal directly - it will emit change events automatically
|
|
1763
|
+
this.context.set(this.internalContext());
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
//#endregion
|
|
1767
|
+
//#region ---- Type Guards ----
|
|
1768
|
+
/**
|
|
1769
|
+
* Type guard to check if the input is a form definition
|
|
1770
|
+
*/
|
|
1771
|
+
isFormDefinition(data) {
|
|
1772
|
+
return data &&
|
|
1773
|
+
typeof data === 'object' &&
|
|
1774
|
+
'groups' in data &&
|
|
1775
|
+
Array.isArray(data.groups);
|
|
1776
|
+
}
|
|
1777
|
+
//#endregion
|
|
1778
|
+
//#region ---- Utility Methods ----
|
|
1779
|
+
/**
|
|
1780
|
+
* Generate layout hash for change detection (short hash)
|
|
1781
|
+
*/
|
|
1782
|
+
generateLayoutHash(layout, look) {
|
|
1783
|
+
if (!layout)
|
|
1784
|
+
return '';
|
|
1785
|
+
// Generate short hash for large layout strings
|
|
1786
|
+
const layoutStr = typeof layout === 'string' ? layout : JSON.stringify(layout);
|
|
1787
|
+
const layoutHash = this.simpleHash(layoutStr);
|
|
1788
|
+
return `${layoutHash}|${look}`;
|
|
1789
|
+
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Generate cache key for expression evaluation (short hash)
|
|
1792
|
+
*/
|
|
1793
|
+
generateCacheKey(expression, context) {
|
|
1794
|
+
// Use short hash for better performance
|
|
1795
|
+
const exprStr = typeof expression === 'string' ? expression : JSON.stringify(expression);
|
|
1796
|
+
const exprHash = this.simpleHash(exprStr);
|
|
1797
|
+
const ctxHash = this.generateContextHash(context);
|
|
1798
|
+
return `${exprHash}|${ctxHash}`;
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Generate a simple hash for context change detection
|
|
1802
|
+
*/
|
|
1803
|
+
generateContextHash(context) {
|
|
1804
|
+
if (!context || typeof context !== 'object') {
|
|
1805
|
+
return String(context);
|
|
1806
|
+
}
|
|
1807
|
+
// Generate short hash for context
|
|
1808
|
+
const keys = Object.keys(context).sort();
|
|
1809
|
+
const contextStr = keys.map(key => `${key}:${context[key]}`).join('|');
|
|
1810
|
+
return this.simpleHash(contextStr);
|
|
1867
1811
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1812
|
+
/**
|
|
1813
|
+
* Simple hash function for generating short keys
|
|
1814
|
+
*/
|
|
1815
|
+
simpleHash(str) {
|
|
1816
|
+
let hash = 0;
|
|
1817
|
+
if (str.length === 0)
|
|
1818
|
+
return hash.toString();
|
|
1819
|
+
for (let i = 0; i < str.length; i++) {
|
|
1820
|
+
const char = str.charCodeAt(i);
|
|
1821
|
+
hash = ((hash << 5) - hash) + char;
|
|
1822
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
1823
|
+
}
|
|
1824
|
+
// Convert to positive hex string
|
|
1825
|
+
return Math.abs(hash).toString(16);
|
|
1826
|
+
}
|
|
1827
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1828
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.3", 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: `
|
|
1829
|
+
<ax-form>
|
|
1830
|
+
<axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
|
|
1831
|
+
@if (widgetTree()) {
|
|
1832
|
+
<ng-container axp-widget-renderer [node]="widgetTree()!" [mode]="mode()"></ng-container>
|
|
1833
|
+
}
|
|
1834
|
+
</axp-widgets-container>
|
|
1835
|
+
</ax-form>
|
|
1836
|
+
`, 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: ["labelMode", "look", "messageStyle", "updateOn"], outputs: ["onValidate", "updateOnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1837
|
+
}
|
|
1838
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
|
|
1839
|
+
type: Component,
|
|
1840
|
+
args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [CommonModule, AXPWidgetCoreModule, AXFormModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
1841
|
+
<ax-form>
|
|
1842
|
+
<axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
|
|
1843
|
+
@if (widgetTree()) {
|
|
1844
|
+
<ng-container axp-widget-renderer [node]="widgetTree()!" [mode]="mode()"></ng-container>
|
|
1845
|
+
}
|
|
1846
|
+
</axp-widgets-container>
|
|
1847
|
+
</ax-form>
|
|
1848
|
+
`, styles: [":host{display:block;width:100%}\n"] }]
|
|
1849
|
+
}] });
|
|
1850
|
+
|
|
1851
|
+
class LayoutBuilderModule {
|
|
1852
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: LayoutBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1853
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.3", ngImport: i0, type: LayoutBuilderModule, imports: [CommonModule, AXPLayoutRendererComponent], exports: [AXPLayoutRendererComponent] }); }
|
|
1854
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: LayoutBuilderModule, providers: [AXPLayoutBuilderService], imports: [CommonModule, AXPLayoutRendererComponent] }); }
|
|
1871
1855
|
}
|
|
1872
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
1856
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: LayoutBuilderModule, decorators: [{
|
|
1873
1857
|
type: NgModule,
|
|
1874
1858
|
args: [{
|
|
1875
|
-
imports: [CommonModule,
|
|
1876
|
-
|
|
1877
|
-
|
|
1859
|
+
imports: [CommonModule, AXPLayoutRendererComponent],
|
|
1860
|
+
providers: [AXPLayoutBuilderService],
|
|
1861
|
+
exports: [AXPLayoutRendererComponent],
|
|
1878
1862
|
}]
|
|
1879
|
-
}]
|
|
1880
|
-
type: Optional
|
|
1881
|
-
}, {
|
|
1882
|
-
type: Inject,
|
|
1883
|
-
args: ['AXPLayoutBuilderModuleFactory']
|
|
1884
|
-
}] }] });
|
|
1863
|
+
}] });
|
|
1885
1864
|
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
return values;
|
|
1897
|
-
default:
|
|
1898
|
-
throw new Error(`Invalid shorthand value count. Input: ${values}`);
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
static condenseShorthand(values) {
|
|
1902
|
-
if (values.length !== 4) {
|
|
1903
|
-
throw new Error('Expected 4 values for condensation.');
|
|
1904
|
-
}
|
|
1905
|
-
if (values[0] === values[1] && values[1] === values[2] && values[2] === values[3]) {
|
|
1906
|
-
return `${values[0]}`;
|
|
1907
|
-
}
|
|
1908
|
-
else if (values[0] === values[2] && values[1] === values[3]) {
|
|
1909
|
-
return `${values[0]} ${values[1]}`;
|
|
1910
|
-
}
|
|
1911
|
-
else if (values[1] === values[3]) {
|
|
1912
|
-
return `${values[0]} ${values[1]} ${values[2]}`;
|
|
1913
|
-
}
|
|
1914
|
-
else {
|
|
1915
|
-
return `${values[0]} ${values[1]} ${values[2]} ${values[3]}`;
|
|
1916
|
-
}
|
|
1865
|
+
//#endregion
|
|
1866
|
+
|
|
1867
|
+
class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
1868
|
+
constructor() {
|
|
1869
|
+
super(...arguments);
|
|
1870
|
+
this.result = new EventEmitter();
|
|
1871
|
+
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
1872
|
+
// This will be set by the popup service automatically - same as dynamic-dialog
|
|
1873
|
+
this.callBack = () => { };
|
|
1874
|
+
this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : []));
|
|
1917
1875
|
}
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1876
|
+
ngOnInit() {
|
|
1877
|
+
// Initialize context with provided context
|
|
1878
|
+
this.context.set(this.config?.context || {});
|
|
1921
1879
|
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
return {
|
|
1925
|
-
top: AXPPropertyEditorHelper.getValueWithUnit(values[0]).value,
|
|
1926
|
-
right: AXPPropertyEditorHelper.getValueWithUnit(values[1]).value,
|
|
1927
|
-
bottom: AXPPropertyEditorHelper.getValueWithUnit(values[2]).value,
|
|
1928
|
-
left: AXPPropertyEditorHelper.getValueWithUnit(values[3]).value,
|
|
1929
|
-
};
|
|
1880
|
+
handleContextChanged(event) {
|
|
1881
|
+
this.context.set(event);
|
|
1930
1882
|
}
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
return {
|
|
1934
|
-
'top-left': AXPPropertyEditorHelper.getValueWithUnit(values[0]).value,
|
|
1935
|
-
'top-right': AXPPropertyEditorHelper.getValueWithUnit(values[1]).value,
|
|
1936
|
-
'bottom-left': AXPPropertyEditorHelper.getValueWithUnit(values[2]).value,
|
|
1937
|
-
'bottom-right': AXPPropertyEditorHelper.getValueWithUnit(values[3]).value,
|
|
1938
|
-
};
|
|
1883
|
+
handleContextInitiated(event) {
|
|
1884
|
+
this.context.set(event);
|
|
1939
1885
|
}
|
|
1940
|
-
|
|
1941
|
-
return
|
|
1942
|
-
margin: this.parseSidesWithUnits(input.margin),
|
|
1943
|
-
padding: this.parseSidesWithUnits(input.padding),
|
|
1944
|
-
};
|
|
1886
|
+
visibleFooterPrefixActions() {
|
|
1887
|
+
return this.config?.actions?.footer?.prefix || [];
|
|
1945
1888
|
}
|
|
1946
|
-
|
|
1947
|
-
return
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
style: this.parseSides(input.style),
|
|
1952
|
-
};
|
|
1889
|
+
visibleFooterSuffixActions() {
|
|
1890
|
+
return this.config?.actions?.footer?.suffix || [
|
|
1891
|
+
{ title: 'Cancel', color: 'secondary', command: { name: 'cancel' } },
|
|
1892
|
+
{ title: 'Confirm', color: 'primary', command: { name: 'confirm' } }
|
|
1893
|
+
];
|
|
1953
1894
|
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
return {
|
|
1957
|
-
margin: AXPPropertyEditorHelper.condenseShorthand([
|
|
1958
|
-
format(input.margin.top, units.margin.top),
|
|
1959
|
-
format(input.margin.right, units.margin.right),
|
|
1960
|
-
format(input.margin.bottom, units.margin.bottom),
|
|
1961
|
-
format(input.margin.left, units.margin.left),
|
|
1962
|
-
]),
|
|
1963
|
-
padding: AXPPropertyEditorHelper.condenseShorthand([
|
|
1964
|
-
format(input.padding.top, units.padding.top),
|
|
1965
|
-
format(input.padding.right, units.padding.right),
|
|
1966
|
-
format(input.padding.bottom, units.padding.bottom),
|
|
1967
|
-
format(input.padding.left, units.padding.left),
|
|
1968
|
-
]),
|
|
1969
|
-
};
|
|
1895
|
+
isFormLoading() {
|
|
1896
|
+
return this.isDialogLoading();
|
|
1970
1897
|
}
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
return {
|
|
1974
|
-
width: AXPPropertyEditorHelper.condenseShorthand([
|
|
1975
|
-
format(input.width.top, units.width.top),
|
|
1976
|
-
format(input.width.right, units.width.right),
|
|
1977
|
-
format(input.width.bottom, units.width.bottom),
|
|
1978
|
-
format(input.width.left, units.width.left),
|
|
1979
|
-
]),
|
|
1980
|
-
radius: AXPPropertyEditorHelper.condenseShorthand([
|
|
1981
|
-
format(input.radius['top-left'], units.radius['top-left']),
|
|
1982
|
-
format(input.radius['top-right'], units.radius['top-right']),
|
|
1983
|
-
format(input.radius['bottom-right'], units.radius['bottom-right']),
|
|
1984
|
-
format(input.radius['bottom-left'], units.radius['bottom-left']),
|
|
1985
|
-
]),
|
|
1986
|
-
color: AXPPropertyEditorHelper.condenseShorthand([
|
|
1987
|
-
`${input.color.top}${units.color.top}`,
|
|
1988
|
-
`${input.color.right}${units.color.right}`,
|
|
1989
|
-
`${input.color.bottom}${units.color.bottom}`,
|
|
1990
|
-
`${input.color.left}${units.color.left}`,
|
|
1991
|
-
]),
|
|
1992
|
-
style: AXPPropertyEditorHelper.condenseShorthand([
|
|
1993
|
-
`${input.style.top}${units.style.top}`,
|
|
1994
|
-
`${input.style.right}${units.style.right}`,
|
|
1995
|
-
`${input.style.bottom}${units.style.bottom}`,
|
|
1996
|
-
`${input.style.left}${units.style.left}`,
|
|
1997
|
-
]),
|
|
1998
|
-
};
|
|
1898
|
+
isSubmitting() {
|
|
1899
|
+
return this.isDialogLoading();
|
|
1999
1900
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
if (!match)
|
|
2007
|
-
throw new Error(`Invalid unit format: ${input}`);
|
|
2008
|
-
return { value: parseFloat(match[1]), unit: match[2] || '' };
|
|
2009
|
-
}
|
|
2010
|
-
static getValueFromUnit(value, unit) {
|
|
2011
|
-
return unit ? `${value}${unit}` : `${value}`;
|
|
2012
|
-
}
|
|
2013
|
-
static parseGap(gap) {
|
|
2014
|
-
const parts = gap.split(/\s+/);
|
|
2015
|
-
const match = parts[0].match(/^(\d+\.?\d*)([a-z%]+)$/);
|
|
2016
|
-
if (!match) {
|
|
2017
|
-
throw new Error('Invalid gap format');
|
|
2018
|
-
}
|
|
2019
|
-
const [, xValue, unit] = match;
|
|
2020
|
-
let yValue = parseFloat(xValue);
|
|
2021
|
-
if (parts.length === 2) {
|
|
2022
|
-
const secondMatch = parts[1].match(/^(\d+\.?\d*)[a-z%]+$/);
|
|
2023
|
-
if (!secondMatch) {
|
|
2024
|
-
throw new Error('Invalid gap format');
|
|
2025
|
-
}
|
|
2026
|
-
yValue = parseFloat(secondMatch[1]);
|
|
2027
|
-
}
|
|
2028
|
-
return {
|
|
2029
|
-
values: {
|
|
2030
|
-
x: parseFloat(xValue),
|
|
2031
|
-
y: yValue,
|
|
2032
|
-
},
|
|
2033
|
-
unit,
|
|
1901
|
+
async executeAction(action) {
|
|
1902
|
+
const actionName = action.command?.name || action.title?.toLowerCase();
|
|
1903
|
+
// Store the action and context - same pattern as dynamic-dialog
|
|
1904
|
+
const result = {
|
|
1905
|
+
context: this.context(),
|
|
1906
|
+
action: actionName
|
|
2034
1907
|
};
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
if (
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
return parseInt(match[1], 10);
|
|
2042
|
-
}
|
|
2043
|
-
static createGridTemplate(repetitionCount) {
|
|
2044
|
-
if (repetitionCount <= 0) {
|
|
2045
|
-
throw new Error('Repetition count must be a positive integer.');
|
|
1908
|
+
// Store result in component property
|
|
1909
|
+
this.dialogResult = result;
|
|
1910
|
+
// Store in popup data for DialogRef access
|
|
1911
|
+
if (this.data) {
|
|
1912
|
+
this.data.context = result.context;
|
|
1913
|
+
this.data.action = result.action;
|
|
2046
1914
|
}
|
|
2047
|
-
|
|
1915
|
+
// Call the callback with DialogRef - same pattern as dynamic-dialog
|
|
1916
|
+
this.callBack({
|
|
1917
|
+
close: (result) => {
|
|
1918
|
+
this.close(result);
|
|
1919
|
+
},
|
|
1920
|
+
context: () => {
|
|
1921
|
+
return this.context();
|
|
1922
|
+
},
|
|
1923
|
+
action: () => {
|
|
1924
|
+
return result.action;
|
|
1925
|
+
},
|
|
1926
|
+
setLoading: (loading) => {
|
|
1927
|
+
this.isDialogLoading.set(loading);
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
2048
1930
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
const nonEmptyBreakpoints = [];
|
|
2053
|
-
for (const breakpoint of breakpoints) {
|
|
2054
|
-
if (values[breakpoint] !== undefined) {
|
|
2055
|
-
nonEmptyBreakpoints.push(breakpoint);
|
|
1931
|
+
close(result) {
|
|
1932
|
+
if (result) {
|
|
1933
|
+
this.result.emit(result);
|
|
2056
1934
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
1935
|
+
super.close(result);
|
|
1936
|
+
}
|
|
1937
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPDialogRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
1938
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.3", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", inputs: { config: "config" }, outputs: { result: "result" }, usesInheritance: true, ngImport: i0, template: `
|
|
1939
|
+
<div class="ax-p-4">
|
|
1940
|
+
<axp-layout-renderer
|
|
1941
|
+
[layout]="config.definition"
|
|
1942
|
+
[context]="context()"
|
|
1943
|
+
(contextChange)="handleContextChanged($event)"
|
|
1944
|
+
(contextInitiated)="handleContextInitiated($event)"
|
|
1945
|
+
>
|
|
1946
|
+
</axp-layout-renderer>
|
|
1947
|
+
</div>
|
|
1948
|
+
|
|
1949
|
+
<ax-footer>
|
|
1950
|
+
<ax-prefix>
|
|
1951
|
+
<ng-container *ngTemplateOutlet="footerPrefixActions"></ng-container>
|
|
1952
|
+
</ax-prefix>
|
|
1953
|
+
<ax-suffix>
|
|
1954
|
+
<ng-container *ngTemplateOutlet="footerSuffixActions"></ng-container>
|
|
1955
|
+
</ax-suffix>
|
|
1956
|
+
</ax-footer>
|
|
1957
|
+
|
|
1958
|
+
<!-- Footer Prefix Actions -->
|
|
1959
|
+
<ng-template #footerPrefixActions>
|
|
1960
|
+
@for (action of visibleFooterPrefixActions(); track $index) {
|
|
1961
|
+
<ax-button
|
|
1962
|
+
[disabled]="action.disabled || isFormLoading()"
|
|
1963
|
+
[text]="(action.title | translate | async)!"
|
|
1964
|
+
[look]="'outline'"
|
|
1965
|
+
[color]="action.color"
|
|
1966
|
+
(onClick)="executeAction(action)"
|
|
1967
|
+
>
|
|
1968
|
+
@if (isFormLoading() && action.command?.name != 'cancel') {
|
|
1969
|
+
<ax-loading></ax-loading>
|
|
1970
|
+
}
|
|
1971
|
+
<ax-prefix>
|
|
1972
|
+
<i class="{{ action.icon }}"></i>
|
|
1973
|
+
</ax-prefix>
|
|
1974
|
+
</ax-button>
|
|
1975
|
+
}
|
|
1976
|
+
</ng-template>
|
|
1977
|
+
|
|
1978
|
+
<!-- Footer Suffix Actions -->
|
|
1979
|
+
<ng-template #footerSuffixActions>
|
|
1980
|
+
@for (action of visibleFooterSuffixActions(); track $index) {
|
|
1981
|
+
<ax-button
|
|
1982
|
+
[disabled]="action.disabled || isSubmitting()"
|
|
1983
|
+
[text]="(action.title | translate | async)!"
|
|
1984
|
+
[look]="'solid'"
|
|
1985
|
+
[color]="action.color"
|
|
1986
|
+
(onClick)="executeAction(action)"
|
|
1987
|
+
>
|
|
1988
|
+
@if (action.icon) {
|
|
1989
|
+
<ax-prefix>
|
|
1990
|
+
<ax-icon icon="{{ action.icon }}"></ax-icon>
|
|
1991
|
+
</ax-prefix>
|
|
1992
|
+
}
|
|
1993
|
+
</ax-button>
|
|
1994
|
+
}
|
|
1995
|
+
</ng-template>
|
|
1996
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: AXPLayoutRendererComponent, selector: "axp-layout-renderer", inputs: ["layout", "context", "look", "mode"], outputs: ["contextChange", "contextInitiated", "validityChange"] }, { kind: "ngmodule", type: AXButtonModule }, { kind: "component", type: i2$1.AXButtonComponent, selector: "ax-button", inputs: ["disabled", "size", "tabIndex", "color", "look", "text", "toggleable", "selected", "iconOnly", "type", "loadingText"], outputs: ["onBlur", "onFocus", "onClick", "selectedChange", "toggleableChange", "lookChange", "colorChange", "disabledChange", "loadingTextChange"] }, { kind: "ngmodule", type: AXDecoratorModule }, { kind: "component", type: i3.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i3.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-subtitle, ax-placeholder, ax-overlay" }, { kind: "ngmodule", type: AXLoadingModule }, { kind: "component", type: i4.AXLoadingComponent, selector: "ax-loading", inputs: ["visible", "type", "context"], outputs: ["visibleChange"] }, { kind: "ngmodule", type: AXTranslationModule }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.AXTranslatorPipe, name: "translate" }] }); }
|
|
2059
1997
|
}
|
|
1998
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXPDialogRendererComponent, decorators: [{
|
|
1999
|
+
type: Component,
|
|
2000
|
+
args: [{
|
|
2001
|
+
selector: 'axp-dialog-renderer',
|
|
2002
|
+
standalone: true,
|
|
2003
|
+
imports: [CommonModule, AXPLayoutRendererComponent, AXButtonModule, AXDecoratorModule, AXLoadingModule, AXTranslationModule],
|
|
2004
|
+
template: `
|
|
2005
|
+
<div class="ax-p-4">
|
|
2006
|
+
<axp-layout-renderer
|
|
2007
|
+
[layout]="config.definition"
|
|
2008
|
+
[context]="context()"
|
|
2009
|
+
(contextChange)="handleContextChanged($event)"
|
|
2010
|
+
(contextInitiated)="handleContextInitiated($event)"
|
|
2011
|
+
>
|
|
2012
|
+
</axp-layout-renderer>
|
|
2013
|
+
</div>
|
|
2014
|
+
|
|
2015
|
+
<ax-footer>
|
|
2016
|
+
<ax-prefix>
|
|
2017
|
+
<ng-container *ngTemplateOutlet="footerPrefixActions"></ng-container>
|
|
2018
|
+
</ax-prefix>
|
|
2019
|
+
<ax-suffix>
|
|
2020
|
+
<ng-container *ngTemplateOutlet="footerSuffixActions"></ng-container>
|
|
2021
|
+
</ax-suffix>
|
|
2022
|
+
</ax-footer>
|
|
2023
|
+
|
|
2024
|
+
<!-- Footer Prefix Actions -->
|
|
2025
|
+
<ng-template #footerPrefixActions>
|
|
2026
|
+
@for (action of visibleFooterPrefixActions(); track $index) {
|
|
2027
|
+
<ax-button
|
|
2028
|
+
[disabled]="action.disabled || isFormLoading()"
|
|
2029
|
+
[text]="(action.title | translate | async)!"
|
|
2030
|
+
[look]="'outline'"
|
|
2031
|
+
[color]="action.color"
|
|
2032
|
+
(onClick)="executeAction(action)"
|
|
2033
|
+
>
|
|
2034
|
+
@if (isFormLoading() && action.command?.name != 'cancel') {
|
|
2035
|
+
<ax-loading></ax-loading>
|
|
2036
|
+
}
|
|
2037
|
+
<ax-prefix>
|
|
2038
|
+
<i class="{{ action.icon }}"></i>
|
|
2039
|
+
</ax-prefix>
|
|
2040
|
+
</ax-button>
|
|
2041
|
+
}
|
|
2042
|
+
</ng-template>
|
|
2060
2043
|
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
}
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
}
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
];
|
|
2044
|
+
<!-- Footer Suffix Actions -->
|
|
2045
|
+
<ng-template #footerSuffixActions>
|
|
2046
|
+
@for (action of visibleFooterSuffixActions(); track $index) {
|
|
2047
|
+
<ax-button
|
|
2048
|
+
[disabled]="action.disabled || isSubmitting()"
|
|
2049
|
+
[text]="(action.title | translate | async)!"
|
|
2050
|
+
[look]="'solid'"
|
|
2051
|
+
[color]="action.color"
|
|
2052
|
+
(onClick)="executeAction(action)"
|
|
2053
|
+
>
|
|
2054
|
+
@if (action.icon) {
|
|
2055
|
+
<ax-prefix>
|
|
2056
|
+
<ax-icon icon="{{ action.icon }}"></ax-icon>
|
|
2057
|
+
</ax-prefix>
|
|
2058
|
+
}
|
|
2059
|
+
</ax-button>
|
|
2060
|
+
}
|
|
2061
|
+
</ng-template>
|
|
2062
|
+
`
|
|
2063
|
+
}]
|
|
2064
|
+
}], propDecorators: { config: [{
|
|
2065
|
+
type: Input
|
|
2066
|
+
}], result: [{
|
|
2067
|
+
type: Output
|
|
2068
|
+
}] } });
|
|
2087
2069
|
|
|
2088
|
-
var
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
AXPWidgetGroupEnum["FormTemplate"] = "form-template";
|
|
2093
|
-
AXPWidgetGroupEnum["PropertyEditor"] = "property-editor";
|
|
2094
|
-
AXPWidgetGroupEnum["MetaData"] = "meta-data";
|
|
2095
|
-
AXPWidgetGroupEnum["SettingWidget"] = "setting-widget";
|
|
2096
|
-
AXPWidgetGroupEnum["EntityWidget"] = "entity-widget";
|
|
2097
|
-
})(AXPWidgetGroupEnum || (AXPWidgetGroupEnum = {}));
|
|
2070
|
+
var dialogRenderer_component = /*#__PURE__*/Object.freeze({
|
|
2071
|
+
__proto__: null,
|
|
2072
|
+
AXPDialogRendererComponent: AXPDialogRendererComponent
|
|
2073
|
+
});
|
|
2098
2074
|
|
|
2099
2075
|
/**
|
|
2100
2076
|
* Generated bundle index. Do not edit.
|
|
2101
2077
|
*/
|
|
2102
2078
|
|
|
2103
|
-
export {
|
|
2079
|
+
export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, LayoutBuilderModule };
|
|
2104
2080
|
//# sourceMappingURL=acorex-platform-layout-builder.mjs.map
|