@acorex/platform 20.3.0-next.2 → 20.3.0-next.21
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 +576 -46
- package/fesm2022/acorex-platform-auth.mjs +19 -19
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/acorex-platform-common.mjs +152 -231
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +657 -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 +1946 -1947
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +2094 -477
- 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-DyXF9zAh.mjs +52 -0
- package/fesm2022/acorex-platform-layout-entity-create-entity.command-DyXF9zAh.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-C_3IWNkj.mjs} +6 -6
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-C_3IWNkj.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-CJltEgut.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-edit.component-CJltEgut.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-pM-TIuk0.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-schema-widget-view.component-pM-TIuk0.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-BqI96-fU.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-edit.component-BqI96-fU.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-C-AhenaM.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-values-widget-view.component-C-AhenaM.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-DCAya5ne.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-edit.component-DCAya5ne.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-D-PnBqLb.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-extra-properties-widget-view.component-D-PnBqLb.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-file-list-popup.component-rW2RD35f.mjs → acorex-platform-layout-widgets-file-list-popup.component-DuuFHWvB.mjs} +10 -10
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-DuuFHWvB.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets-page-widget-designer.component-DNvnQ4Mc.mjs → acorex-platform-layout-widgets-page-widget-designer.component-Bss0xUcu.mjs} +8 -8
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-Bss0xUcu.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-Cy9mHnNP.mjs} +14 -14
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Cy9mHnNP.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-DznLtuer.mjs} +6 -5
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-DznLtuer.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-ndOUSFi9.mjs} +6 -7
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-ndOUSFi9.mjs.map +1 -0
- package/fesm2022/{acorex-platform-widgets.mjs → acorex-platform-layout-widgets.mjs} +8836 -8103
- 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-Fnj54AxV.mjs +115 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Fnj54AxV.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-C60W6UnN.mjs +753 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-C60W6UnN.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-B3NyKGIG.mjs +101 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-B3NyKGIG.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-B8gx5cG7.mjs} +17 -17
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-B8gx5cG7.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-error-401.component-DrO1PEOH.mjs → acorex-platform-themes-default-error-401.component-CcvGfdhu.mjs} +4 -4
- package/fesm2022/{acorex-platform-themes-default-error-401.component-DrO1PEOH.mjs.map → acorex-platform-themes-default-error-401.component-CcvGfdhu.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-themes-default-error-404.component-DqVq0oHX.mjs → acorex-platform-themes-default-error-404.component-4-CaEsnV.mjs} +4 -4
- package/fesm2022/{acorex-platform-themes-default-error-404.component-DqVq0oHX.mjs.map → acorex-platform-themes-default-error-404.component-4-CaEsnV.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-themes-default-error-offline.component-Bt2PTL7_.mjs → acorex-platform-themes-default-error-offline.component-BNecbFEj.mjs} +4 -4
- package/fesm2022/{acorex-platform-themes-default-error-offline.component-Bt2PTL7_.mjs.map → acorex-platform-themes-default-error-offline.component-BNecbFEj.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-Dc_Txe32.mjs} +25 -15
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-Dc_Txe32.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-hgWLhhle.mjs} +24 -9
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-hgWLhhle.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-CY3JZK_W.mjs} +24 -9
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-CY3JZK_W.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 +1577 -3
- package/layout/builder/index.d.ts +735 -814
- package/layout/components/index.d.ts +443 -214
- 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 +1908 -770
- package/package.json +22 -18
- 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 +0 -708
- 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,2103 @@
|
|
|
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 i2 from '@acorex/components/form';
|
|
7
|
+
import { AXFormComponent, AXFormModule } from '@acorex/components/form';
|
|
8
|
+
import { AXPExpressionEvaluatorService } from '@acorex/platform/core';
|
|
9
|
+
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
10
|
+
import { AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule } from '@acorex/platform/layout/widget-core';
|
|
11
|
+
import { isEqual, get, cloneDeep } from 'lodash-es';
|
|
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.4", ngImport: i0, type: AXPLayoutBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
90
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", 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.4", 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);
|
|
159
|
+
}
|
|
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);
|
|
516
168
|
}
|
|
517
|
-
|
|
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
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
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
|
-
}
|
|
348
|
+
/**
|
|
349
|
+
* Layout container mixin - Interface Segregation Principle
|
|
350
|
+
* Provides layout-specific operations
|
|
351
|
+
*/
|
|
352
|
+
class LayoutContainerMixin extends BaseContainerMixin {
|
|
353
|
+
layout(value) {
|
|
354
|
+
// Map layout intent to grid item sizing so containers like `form-field`
|
|
355
|
+
// can span multiple columns inside grid/fieldset layouts.
|
|
356
|
+
if (!this.containerState.options)
|
|
357
|
+
this.containerState.options = {};
|
|
358
|
+
if (typeof value === 'number') {
|
|
359
|
+
// Direct numeric shorthand → colSpan
|
|
360
|
+
this.containerState.options.colSpan = value;
|
|
361
|
+
}
|
|
362
|
+
else if (value) {
|
|
363
|
+
// Try to extract a reasonable colSpan from breakpoint positions
|
|
364
|
+
const positions = value.positions;
|
|
365
|
+
if (positions) {
|
|
366
|
+
const colSpan = positions?.lg?.colSpan ??
|
|
367
|
+
positions?.xl?.colSpan ??
|
|
368
|
+
positions?.xxl?.colSpan ??
|
|
369
|
+
positions?.md?.colSpan ??
|
|
370
|
+
positions?.sm?.colSpan;
|
|
371
|
+
if (colSpan != null) {
|
|
372
|
+
this.containerState.options.colSpan = colSpan;
|
|
712
373
|
}
|
|
713
374
|
}
|
|
714
|
-
|
|
715
|
-
|
|
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" }] : []));
|
|
375
|
+
}
|
|
376
|
+
return this;
|
|
730
377
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Child container mixin - Interface Segregation Principle
|
|
381
|
+
* Provides child container management
|
|
382
|
+
*/
|
|
383
|
+
class ChildContainerMixin extends LayoutContainerMixin {
|
|
384
|
+
grid(delegate) {
|
|
385
|
+
const container = new GridContainerBuilder();
|
|
386
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
387
|
+
if (delegate) {
|
|
388
|
+
delegate(container);
|
|
734
389
|
}
|
|
735
|
-
|
|
736
|
-
|
|
390
|
+
this.ensureChildren();
|
|
391
|
+
this.containerState.children.push(container.build());
|
|
392
|
+
return this;
|
|
393
|
+
}
|
|
394
|
+
flex(delegate) {
|
|
395
|
+
const container = new FlexContainerBuilder();
|
|
396
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
397
|
+
if (delegate) {
|
|
398
|
+
delegate(container);
|
|
737
399
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
400
|
+
this.ensureChildren();
|
|
401
|
+
this.containerState.children.push(container.build());
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
panel(delegate) {
|
|
405
|
+
const container = new PanelContainerBuilder();
|
|
406
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
407
|
+
if (delegate) {
|
|
408
|
+
delegate(container);
|
|
745
409
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
410
|
+
this.ensureChildren();
|
|
411
|
+
this.containerState.children.push(container.build());
|
|
412
|
+
return this;
|
|
413
|
+
}
|
|
414
|
+
page(delegate) {
|
|
415
|
+
const container = new PageContainerBuilder();
|
|
416
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
417
|
+
if (delegate) {
|
|
418
|
+
delegate(container);
|
|
419
|
+
}
|
|
420
|
+
this.ensureChildren();
|
|
421
|
+
this.containerState.children.push(container.build());
|
|
422
|
+
return this;
|
|
423
|
+
}
|
|
424
|
+
tabset(delegate) {
|
|
425
|
+
const container = new TabsetContainerBuilder();
|
|
426
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
427
|
+
if (delegate) {
|
|
428
|
+
delegate(container);
|
|
429
|
+
}
|
|
430
|
+
this.ensureChildren();
|
|
431
|
+
this.containerState.children.push(container.build());
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
fieldset(delegate) {
|
|
435
|
+
const container = new FieldsetContainerBuilder();
|
|
436
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
437
|
+
if (delegate) {
|
|
438
|
+
delegate(container);
|
|
439
|
+
}
|
|
440
|
+
this.ensureChildren();
|
|
441
|
+
this.containerState.children.push(container.build());
|
|
442
|
+
return this;
|
|
443
|
+
}
|
|
444
|
+
dialog(delegate) {
|
|
445
|
+
const container = new DialogContainerBuilder(); // Will use inject() fallback
|
|
446
|
+
if (delegate) {
|
|
447
|
+
delegate(container);
|
|
448
|
+
}
|
|
449
|
+
return container;
|
|
450
|
+
}
|
|
451
|
+
formField(label, delegate) {
|
|
452
|
+
const field = new FormFieldBuilder(label);
|
|
453
|
+
field.withInheritanceContext(this.inheritanceContext);
|
|
454
|
+
if (delegate) {
|
|
455
|
+
delegate(field);
|
|
456
|
+
}
|
|
457
|
+
this.ensureChildren();
|
|
458
|
+
this.containerState.children.push(field.build());
|
|
459
|
+
return this;
|
|
752
460
|
}
|
|
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
461
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
this.
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
this.
|
|
767
|
-
this
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
462
|
+
/**
|
|
463
|
+
* Widget container mixin - Interface Segregation Principle
|
|
464
|
+
* Provides widget creation operations
|
|
465
|
+
*/
|
|
466
|
+
class WidgetContainerMixin extends ChildContainerMixin {
|
|
467
|
+
textBox(options) {
|
|
468
|
+
this.addWidget('text-editor', options);
|
|
469
|
+
return this;
|
|
470
|
+
}
|
|
471
|
+
largeTextBox(options) {
|
|
472
|
+
this.addWidget('large-text-editor', options);
|
|
473
|
+
return this;
|
|
474
|
+
}
|
|
475
|
+
richText(options) {
|
|
476
|
+
this.addWidget('rich-text-editor', options);
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
passwordBox(options) {
|
|
480
|
+
this.addWidget('password-editor', options);
|
|
481
|
+
return this;
|
|
482
|
+
}
|
|
483
|
+
numberBox(options) {
|
|
484
|
+
this.addWidget('number-editor', options);
|
|
485
|
+
return this;
|
|
486
|
+
}
|
|
487
|
+
selectBox(options) {
|
|
488
|
+
this.addWidget('select-editor', options);
|
|
489
|
+
return this;
|
|
490
|
+
}
|
|
491
|
+
lookupBox(options) {
|
|
492
|
+
this.addWidget('lookup-editor', options);
|
|
493
|
+
return this;
|
|
494
|
+
}
|
|
495
|
+
selectionList(options) {
|
|
496
|
+
this.addWidget('selection-list-editor', options);
|
|
497
|
+
return this;
|
|
498
|
+
}
|
|
499
|
+
dateTimeBox(options) {
|
|
500
|
+
this.addWidget('date-time-editor', options);
|
|
501
|
+
return this;
|
|
502
|
+
}
|
|
503
|
+
toggleSwitch(options) {
|
|
504
|
+
this.addWidget('toggle-editor', options);
|
|
505
|
+
return this;
|
|
506
|
+
}
|
|
507
|
+
colorBox(options) {
|
|
508
|
+
this.addWidget('color-editor', options);
|
|
509
|
+
return this;
|
|
510
|
+
}
|
|
511
|
+
list(delegate) {
|
|
512
|
+
const container = new ListWidgetBuilder();
|
|
513
|
+
container.withInheritanceContext(this.inheritanceContext);
|
|
514
|
+
if (delegate) {
|
|
515
|
+
delegate(container);
|
|
516
|
+
}
|
|
517
|
+
this.ensureChildren();
|
|
518
|
+
this.containerState.children.push(container.build());
|
|
519
|
+
return this;
|
|
520
|
+
}
|
|
521
|
+
customWidget(type, options) {
|
|
522
|
+
this.addWidget(type, options);
|
|
523
|
+
return this;
|
|
773
524
|
}
|
|
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
525
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
class
|
|
526
|
+
/**
|
|
527
|
+
* Flex Container Builder - Liskov Substitution Principle
|
|
528
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
529
|
+
*/
|
|
530
|
+
class FlexContainerBuilder extends WidgetContainerMixin {
|
|
782
531
|
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" }] : []));
|
|
532
|
+
super('flex-layout');
|
|
533
|
+
}
|
|
534
|
+
setOptions(options) {
|
|
535
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
536
|
+
return this;
|
|
537
|
+
}
|
|
538
|
+
// Individual fluent methods for Flex
|
|
539
|
+
setDirection(direction) {
|
|
540
|
+
return this.setOptions({ flexDirection: direction });
|
|
541
|
+
}
|
|
542
|
+
setWrap(wrap) {
|
|
543
|
+
return this.setOptions({ flexWrap: wrap });
|
|
544
|
+
}
|
|
545
|
+
setJustifyContent(justify) {
|
|
546
|
+
return this.setOptions({ justifyContent: justify });
|
|
547
|
+
}
|
|
548
|
+
setAlignItems(align) {
|
|
549
|
+
return this.setOptions({ alignItems: align });
|
|
550
|
+
}
|
|
551
|
+
setGap(gap) {
|
|
552
|
+
return this.setOptions({ gap });
|
|
553
|
+
}
|
|
554
|
+
setBackgroundColor(color) {
|
|
555
|
+
return this.setOptions({ backgroundColor: color });
|
|
556
|
+
}
|
|
557
|
+
setPadding(padding) {
|
|
558
|
+
return this.setOptions({ spacing: { padding } });
|
|
559
|
+
}
|
|
560
|
+
setMargin(margin) {
|
|
561
|
+
return this.setOptions({ spacing: { margin } });
|
|
839
562
|
}
|
|
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
563
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
class
|
|
564
|
+
/**
|
|
565
|
+
* Grid Container Builder - Liskov Substitution Principle
|
|
566
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
567
|
+
*/
|
|
568
|
+
class GridContainerBuilder extends WidgetContainerMixin {
|
|
848
569
|
constructor() {
|
|
849
|
-
super(
|
|
850
|
-
|
|
851
|
-
|
|
570
|
+
super('grid-layout');
|
|
571
|
+
}
|
|
572
|
+
setOptions(options) {
|
|
573
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
574
|
+
return this;
|
|
575
|
+
}
|
|
576
|
+
// Individual fluent methods for Grid
|
|
577
|
+
setColumns(columns) {
|
|
578
|
+
return this.setOptions({ grid: { default: { columns } } });
|
|
579
|
+
}
|
|
580
|
+
setRows(rows) {
|
|
581
|
+
return this.setOptions({ grid: { default: { rows } } });
|
|
582
|
+
}
|
|
583
|
+
setGap(gap) {
|
|
584
|
+
return this.setOptions({ grid: { default: { gap } } });
|
|
585
|
+
}
|
|
586
|
+
setJustifyItems(justify) {
|
|
587
|
+
return this.setOptions({ grid: { default: { justifyItems: justify } } });
|
|
588
|
+
}
|
|
589
|
+
setAlignItems(align) {
|
|
590
|
+
return this.setOptions({ grid: { default: { alignItems: align } } });
|
|
591
|
+
}
|
|
592
|
+
setAutoFlow(flow) {
|
|
593
|
+
return this.setOptions({ grid: { default: { autoFlow: flow } } });
|
|
594
|
+
}
|
|
595
|
+
setBackgroundColor(color) {
|
|
596
|
+
return this.setOptions({ backgroundColor: color });
|
|
597
|
+
}
|
|
598
|
+
setPadding(padding) {
|
|
599
|
+
return this.setOptions({ spacing: { padding } });
|
|
600
|
+
}
|
|
601
|
+
setMargin(margin) {
|
|
602
|
+
return this.setOptions({ spacing: { margin } });
|
|
852
603
|
}
|
|
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
604
|
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
class
|
|
605
|
+
/**
|
|
606
|
+
* Panel Container Builder - Liskov Substitution Principle
|
|
607
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
608
|
+
*/
|
|
609
|
+
class PanelContainerBuilder extends WidgetContainerMixin {
|
|
861
610
|
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 }); }
|
|
611
|
+
super('panel-layout');
|
|
612
|
+
}
|
|
613
|
+
setOptions(options) {
|
|
614
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
615
|
+
return this;
|
|
616
|
+
}
|
|
617
|
+
// Individual fluent methods for Panel
|
|
618
|
+
setCaption(caption) {
|
|
619
|
+
return this.setOptions({ caption });
|
|
620
|
+
}
|
|
621
|
+
setIcon(icon) {
|
|
622
|
+
return this.setOptions({ icon });
|
|
623
|
+
}
|
|
624
|
+
setLook(look) {
|
|
625
|
+
return this.setOptions({ look });
|
|
626
|
+
}
|
|
627
|
+
setShowHeader(show) {
|
|
628
|
+
return this.setOptions({ showHeader: show });
|
|
629
|
+
}
|
|
630
|
+
setCollapsed(collapsed) {
|
|
631
|
+
return this.setOptions({ collapsed });
|
|
632
|
+
}
|
|
919
633
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
class
|
|
634
|
+
/**
|
|
635
|
+
* Page Container Builder - Liskov Substitution Principle
|
|
636
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
637
|
+
*/
|
|
638
|
+
class PageContainerBuilder extends WidgetContainerMixin {
|
|
925
639
|
constructor() {
|
|
926
|
-
super(
|
|
927
|
-
|
|
928
|
-
|
|
640
|
+
super('page-layout');
|
|
641
|
+
}
|
|
642
|
+
setOptions(options) {
|
|
643
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
644
|
+
return this;
|
|
645
|
+
}
|
|
646
|
+
// Individual fluent methods for Page
|
|
647
|
+
setBackgroundColor(color) {
|
|
648
|
+
return this.setOptions({ backgroundColor: color });
|
|
649
|
+
}
|
|
650
|
+
setTheme(theme) {
|
|
651
|
+
return this.setOptions({ theme });
|
|
652
|
+
}
|
|
653
|
+
setHasHeader(hasHeader) {
|
|
654
|
+
return this.setOptions({ hasHeader });
|
|
655
|
+
}
|
|
656
|
+
setHasFooter(hasFooter) {
|
|
657
|
+
return this.setOptions({ hasFooter });
|
|
658
|
+
}
|
|
659
|
+
setDirection(direction) {
|
|
660
|
+
return this.setOptions({ direction });
|
|
929
661
|
}
|
|
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
662
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
class
|
|
663
|
+
/**
|
|
664
|
+
* Tabset Container Builder - Liskov Substitution Principle
|
|
665
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
666
|
+
*/
|
|
667
|
+
class TabsetContainerBuilder extends WidgetContainerMixin {
|
|
938
668
|
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 }); }
|
|
669
|
+
super('tabset-layout');
|
|
670
|
+
}
|
|
671
|
+
setOptions(options) {
|
|
672
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
673
|
+
return this;
|
|
674
|
+
}
|
|
675
|
+
// Individual fluent methods for Tabset
|
|
676
|
+
setLook(look) {
|
|
677
|
+
return this.setOptions({ look });
|
|
678
|
+
}
|
|
679
|
+
setOrientation(orientation) {
|
|
680
|
+
return this.setOptions({ orientation });
|
|
681
|
+
}
|
|
682
|
+
setActiveIndex(index) {
|
|
683
|
+
return this.setOptions({ activeIndex: index });
|
|
684
|
+
}
|
|
991
685
|
}
|
|
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
|
-
|
|
686
|
+
/**
|
|
687
|
+
* Form Field Builder - Liskov Substitution Principle
|
|
688
|
+
* Can only contain ONE widget with automatic path generation
|
|
689
|
+
*/
|
|
690
|
+
class FormFieldBuilder extends LayoutContainerMixin {
|
|
691
|
+
constructor(label) {
|
|
692
|
+
super('form-field');
|
|
693
|
+
this.hasWidget = false;
|
|
694
|
+
this.containerState.options = { label, showLabel: true };
|
|
695
|
+
}
|
|
696
|
+
setOptions(options) {
|
|
697
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
698
|
+
return this;
|
|
699
|
+
}
|
|
700
|
+
setLabel(label) {
|
|
701
|
+
return this.setOptions({ label });
|
|
702
|
+
}
|
|
703
|
+
setShowLabel(showLabel) {
|
|
704
|
+
return this.setOptions({ showLabel });
|
|
705
|
+
}
|
|
706
|
+
// Single widget methods with automatic path generation
|
|
707
|
+
addSingleWidget(type, options) {
|
|
708
|
+
if (this.hasWidget) {
|
|
709
|
+
throw new Error('Form field can only contain one widget');
|
|
710
|
+
}
|
|
711
|
+
const formFieldName = this.containerState.name;
|
|
712
|
+
const formFieldPath = this.containerState.path; // Get explicit path from form field
|
|
713
|
+
const formFieldLabel = this.containerState.options?.['label'];
|
|
714
|
+
const widgetName = options?.name;
|
|
715
|
+
// Generate widget path: explicit path -> widget name -> form field name -> label -> random
|
|
716
|
+
let widgetPath;
|
|
717
|
+
if (formFieldPath) {
|
|
718
|
+
widgetPath = formFieldPath; // Use explicit form field path first
|
|
719
|
+
}
|
|
720
|
+
else if (widgetName) {
|
|
721
|
+
widgetPath = widgetName;
|
|
722
|
+
}
|
|
723
|
+
else if (formFieldName) {
|
|
724
|
+
widgetPath = formFieldName; // Use form field name as default path
|
|
725
|
+
}
|
|
726
|
+
else if (formFieldLabel) {
|
|
727
|
+
widgetPath = labelToPath(formFieldLabel);
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
widgetPath = generateRandomId();
|
|
731
|
+
}
|
|
732
|
+
const finalName = widgetName || formFieldName || widgetPath;
|
|
733
|
+
const child = new WidgetBuilder();
|
|
734
|
+
child.type(type);
|
|
735
|
+
child.name(finalName);
|
|
736
|
+
child.path(widgetPath);
|
|
737
|
+
// Remove name from options since it's now in state
|
|
738
|
+
const { name: _, ...cleanOptions } = (options || {});
|
|
739
|
+
child.withInheritanceContext(this.inheritanceContext);
|
|
740
|
+
child.options(cleanOptions);
|
|
741
|
+
// IMPORTANT: Store the widget builder, don't build it yet!
|
|
742
|
+
// This allows properties set after this method (like disabled, readonly) to be applied
|
|
743
|
+
this.childWidget = child;
|
|
744
|
+
this.hasWidget = true;
|
|
745
|
+
return this;
|
|
746
|
+
}
|
|
747
|
+
textBox(options) {
|
|
748
|
+
return this.addSingleWidget('text-editor', options);
|
|
749
|
+
}
|
|
750
|
+
largeTextBox(options) {
|
|
751
|
+
return this.addSingleWidget('large-text-editor', options);
|
|
752
|
+
}
|
|
753
|
+
richText(options) {
|
|
754
|
+
return this.addSingleWidget('rich-text-editor', options);
|
|
755
|
+
}
|
|
756
|
+
passwordBox(options) {
|
|
757
|
+
return this.addSingleWidget('password-editor', options);
|
|
758
|
+
}
|
|
759
|
+
numberBox(options) {
|
|
760
|
+
return this.addSingleWidget('number-editor', options);
|
|
761
|
+
}
|
|
762
|
+
selectBox(options) {
|
|
763
|
+
return this.addSingleWidget('select-editor', options);
|
|
764
|
+
}
|
|
765
|
+
lookupBox(options) {
|
|
766
|
+
return this.addSingleWidget('lookup-editor', options);
|
|
767
|
+
}
|
|
768
|
+
selectionList(options) {
|
|
769
|
+
return this.addSingleWidget('selection-list-editor', options);
|
|
770
|
+
}
|
|
771
|
+
dateTimeBox(options) {
|
|
772
|
+
return this.addSingleWidget('date-time-editor', options);
|
|
773
|
+
}
|
|
774
|
+
toggleSwitch(options) {
|
|
775
|
+
return this.addSingleWidget('toggle-editor', options);
|
|
776
|
+
}
|
|
777
|
+
colorBox(options) {
|
|
778
|
+
return this.addSingleWidget('color-editor', options);
|
|
779
|
+
}
|
|
780
|
+
customWidget(type, options) {
|
|
781
|
+
return this.addSingleWidget(type, options);
|
|
782
|
+
}
|
|
783
|
+
// Override property setters to propagate changes to child widget
|
|
784
|
+
disabled(condition) {
|
|
785
|
+
super.disabled(condition);
|
|
786
|
+
if (this.childWidget) {
|
|
787
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
788
|
+
}
|
|
789
|
+
return this;
|
|
790
|
+
}
|
|
791
|
+
readonly(condition) {
|
|
792
|
+
super.readonly(condition);
|
|
793
|
+
if (this.childWidget) {
|
|
794
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
795
|
+
}
|
|
796
|
+
return this;
|
|
797
|
+
}
|
|
798
|
+
visible(condition) {
|
|
799
|
+
super.visible(condition);
|
|
800
|
+
if (this.childWidget) {
|
|
801
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
802
|
+
}
|
|
803
|
+
return this;
|
|
804
|
+
}
|
|
805
|
+
direction(direction) {
|
|
806
|
+
super.direction(direction);
|
|
807
|
+
if (this.childWidget) {
|
|
808
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
809
|
+
}
|
|
810
|
+
return this;
|
|
811
|
+
}
|
|
812
|
+
mode(mode) {
|
|
813
|
+
super.mode(mode);
|
|
814
|
+
if (this.childWidget) {
|
|
815
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
816
|
+
}
|
|
817
|
+
return this;
|
|
818
|
+
}
|
|
819
|
+
// Override withInheritanceContext to pass it to the child widget if it exists
|
|
820
|
+
withInheritanceContext(context) {
|
|
821
|
+
// Call parent implementation first
|
|
822
|
+
super.withInheritanceContext(context);
|
|
823
|
+
// If we have a child widget, update its inheritance context too
|
|
824
|
+
if (this.childWidget) {
|
|
825
|
+
this.childWidget.withInheritanceContext(this.inheritanceContext);
|
|
826
|
+
}
|
|
827
|
+
return this;
|
|
828
|
+
}
|
|
829
|
+
// Override build() to build the child widget at the last moment
|
|
830
|
+
build() {
|
|
831
|
+
// Build the child widget and add it to children before building the form field
|
|
832
|
+
if (this.childWidget) {
|
|
833
|
+
this.ensureChildren();
|
|
834
|
+
this.containerState.children.push(this.childWidget.build());
|
|
835
|
+
}
|
|
836
|
+
// Call parent build
|
|
837
|
+
return super.build();
|
|
838
|
+
}
|
|
1030
839
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
840
|
+
/**
|
|
841
|
+
* Fieldset Container Builder - Liskov Substitution Principle
|
|
842
|
+
* Extends LayoutContainerMixin to inherit layout functionality
|
|
843
|
+
* Specialized for form fields only
|
|
844
|
+
*/
|
|
845
|
+
class FieldsetContainerBuilder extends LayoutContainerMixin {
|
|
1036
846
|
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
|
-
|
|
847
|
+
super('fieldset-layout');
|
|
848
|
+
this.containerState.options = {};
|
|
849
|
+
}
|
|
850
|
+
setOptions(options) {
|
|
851
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
852
|
+
return this;
|
|
853
|
+
}
|
|
854
|
+
// Individual fluent methods for Fieldset
|
|
855
|
+
setTitle(title) {
|
|
856
|
+
return this.setOptions({ title });
|
|
857
|
+
}
|
|
858
|
+
setDescription(description) {
|
|
859
|
+
return this.setOptions({ description });
|
|
860
|
+
}
|
|
861
|
+
setIcon(icon) {
|
|
862
|
+
return this.setOptions({ icon });
|
|
863
|
+
}
|
|
864
|
+
setCollapsible(collapsible) {
|
|
865
|
+
return this.setOptions({ collapsible });
|
|
866
|
+
}
|
|
867
|
+
setIsOpen(isOpen) {
|
|
868
|
+
return this.setOptions({ isOpen });
|
|
869
|
+
}
|
|
870
|
+
setLook(look) {
|
|
871
|
+
return this.setOptions({ look });
|
|
872
|
+
}
|
|
873
|
+
setShowHeader(showHeader) {
|
|
874
|
+
return this.setOptions({ showHeader });
|
|
875
|
+
}
|
|
876
|
+
setCols(cols) {
|
|
877
|
+
return this.setOptions({ cols });
|
|
878
|
+
}
|
|
879
|
+
// Only form fields are allowed in fieldset
|
|
880
|
+
formField(label, delegate) {
|
|
881
|
+
const field = new FormFieldBuilder(label);
|
|
882
|
+
field.withInheritanceContext(this.inheritanceContext);
|
|
883
|
+
if (delegate) {
|
|
884
|
+
delegate(field);
|
|
885
|
+
}
|
|
886
|
+
this.ensureChildren();
|
|
887
|
+
this.containerState.children.push(field.build());
|
|
888
|
+
return this;
|
|
889
|
+
}
|
|
1070
890
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
class
|
|
1076
|
-
/**
|
|
1077
|
-
*
|
|
1078
|
-
*/
|
|
891
|
+
/**
|
|
892
|
+
* List Widget Builder - Liskov Substitution Principle
|
|
893
|
+
* Extends WidgetContainerMixin to inherit all common functionality
|
|
894
|
+
*/
|
|
895
|
+
class ListWidgetBuilder extends WidgetContainerMixin {
|
|
1079
896
|
constructor() {
|
|
1080
|
-
|
|
1081
|
-
AXPWidgetRegistryService.instance = this;
|
|
897
|
+
super('list');
|
|
1082
898
|
}
|
|
1083
|
-
|
|
1084
|
-
this.
|
|
899
|
+
setOptions(options) {
|
|
900
|
+
this.containerState.options = { ...this.containerState.options, ...options };
|
|
901
|
+
return this;
|
|
1085
902
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
newWidget.name = widget.name;
|
|
1090
|
-
this.register(newWidget);
|
|
903
|
+
// Individual fluent methods for List Widget
|
|
904
|
+
setDataSource(dataSource) {
|
|
905
|
+
return this.setOptions({ dataSource });
|
|
1091
906
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
return
|
|
907
|
+
setColumns(columns) {
|
|
908
|
+
return this.setOptions({ columns });
|
|
909
|
+
}
|
|
910
|
+
// Event handlers
|
|
911
|
+
setOnRowClick(handler) {
|
|
912
|
+
return this.setOptions({ onRowClick: handler });
|
|
913
|
+
}
|
|
914
|
+
setOnRowDoubleClick(handler) {
|
|
915
|
+
return this.setOptions({ onRowDoubleClick: handler });
|
|
916
|
+
}
|
|
917
|
+
setOnSelectionChange(handler) {
|
|
918
|
+
return this.setOptions({ onSelectionChange: handler });
|
|
919
|
+
}
|
|
920
|
+
setOnRowCommand(handler) {
|
|
921
|
+
return this.setOptions({ onRowCommand: handler });
|
|
922
|
+
}
|
|
923
|
+
// Table features
|
|
924
|
+
setPaging(paging) {
|
|
925
|
+
return this.setOptions({ paging });
|
|
926
|
+
}
|
|
927
|
+
setShowHeader(show) {
|
|
928
|
+
return this.setOptions({ showHeader: show });
|
|
929
|
+
}
|
|
930
|
+
setShowFooter(show) {
|
|
931
|
+
return this.setOptions({ showFooter: show });
|
|
932
|
+
}
|
|
933
|
+
setFixHeader(fix) {
|
|
934
|
+
return this.setOptions({ fixHeader: fix });
|
|
935
|
+
}
|
|
936
|
+
setFixFooter(fix) {
|
|
937
|
+
return this.setOptions({ fixFooter: fix });
|
|
938
|
+
}
|
|
939
|
+
setFetchDataMode(mode) {
|
|
940
|
+
return this.setOptions({ fetchDataMode: mode });
|
|
941
|
+
}
|
|
942
|
+
setParentField(field) {
|
|
943
|
+
return this.setOptions({ parentField: field });
|
|
1098
944
|
}
|
|
1099
|
-
|
|
1100
|
-
return
|
|
945
|
+
setMinHeight(height) {
|
|
946
|
+
return this.setOptions({ minHeight: height });
|
|
947
|
+
}
|
|
948
|
+
// Selection & Index
|
|
949
|
+
setShowIndex(show) {
|
|
950
|
+
return this.setOptions({ showIndex: show });
|
|
951
|
+
}
|
|
952
|
+
setAllowSelection(allow) {
|
|
953
|
+
return this.setOptions({ allowSelection: allow });
|
|
954
|
+
}
|
|
955
|
+
// Commands
|
|
956
|
+
setPrimaryCommands(commands) {
|
|
957
|
+
return this.setOptions({ primaryCommands: commands });
|
|
958
|
+
}
|
|
959
|
+
setSecondaryCommands(commands) {
|
|
960
|
+
return this.setOptions({ secondaryCommands: commands });
|
|
961
|
+
}
|
|
962
|
+
// Loading
|
|
963
|
+
setLoading(loading) {
|
|
964
|
+
return this.setOptions({ loading });
|
|
1101
965
|
}
|
|
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
966
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
this.
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
return this.
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
return
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
return
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
.
|
|
1159
|
-
.
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
967
|
+
/**
|
|
968
|
+
* Dialog Container Builder - Specialized for dialog functionality
|
|
969
|
+
* Uses composition instead of inheritance for cleaner separation
|
|
970
|
+
*/
|
|
971
|
+
class DialogContainerBuilder {
|
|
972
|
+
constructor(popupService) {
|
|
973
|
+
this.dialogState = {
|
|
974
|
+
type: 'flex-layout', // This will be overridden when content layout exists
|
|
975
|
+
children: [],
|
|
976
|
+
mode: 'edit',
|
|
977
|
+
dialogOptions: {
|
|
978
|
+
title: '',
|
|
979
|
+
size: 'md',
|
|
980
|
+
closeButton: false,
|
|
981
|
+
},
|
|
982
|
+
actions: {
|
|
983
|
+
footer: {
|
|
984
|
+
prefix: [],
|
|
985
|
+
suffix: [],
|
|
986
|
+
},
|
|
987
|
+
},
|
|
988
|
+
};
|
|
989
|
+
if (popupService) {
|
|
990
|
+
this.popupService = popupService;
|
|
991
|
+
}
|
|
992
|
+
else {
|
|
993
|
+
this.popupService = inject(AXPopupService);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
setOptions(options) {
|
|
997
|
+
this.dialogState.dialogOptions = { ...this.dialogState.dialogOptions, ...options };
|
|
998
|
+
return this;
|
|
999
|
+
}
|
|
1000
|
+
// Individual fluent methods for Dialog
|
|
1001
|
+
setTitle(title) {
|
|
1002
|
+
return this.setOptions({ title });
|
|
1003
|
+
}
|
|
1004
|
+
setMessage(message) {
|
|
1005
|
+
return this.setOptions({ message });
|
|
1006
|
+
}
|
|
1007
|
+
setSize(size) {
|
|
1008
|
+
return this.setOptions({ size });
|
|
1009
|
+
}
|
|
1010
|
+
setCloseButton(closeButton) {
|
|
1011
|
+
return this.setOptions({ closeButton });
|
|
1012
|
+
}
|
|
1013
|
+
setContext(context) {
|
|
1014
|
+
return this.setOptions({ context });
|
|
1015
|
+
}
|
|
1016
|
+
content(delegate) {
|
|
1017
|
+
if (delegate) {
|
|
1018
|
+
// Create a flex container directly instead of through LayoutBuilder
|
|
1019
|
+
const flexContainer = new FlexContainerBuilder();
|
|
1020
|
+
flexContainer.setDirection('column');
|
|
1021
|
+
flexContainer.setGap('10px');
|
|
1022
|
+
delegate(flexContainer);
|
|
1023
|
+
this.contentLayout = flexContainer.build();
|
|
1024
|
+
}
|
|
1025
|
+
return this;
|
|
1026
|
+
}
|
|
1027
|
+
setActions(delegate) {
|
|
1028
|
+
if (delegate) {
|
|
1029
|
+
const actionBuilder = new ActionBuilder(this);
|
|
1030
|
+
delegate(actionBuilder);
|
|
1031
|
+
}
|
|
1032
|
+
return this;
|
|
1033
|
+
}
|
|
1034
|
+
// Build method to create dialog node
|
|
1035
|
+
build() {
|
|
1036
|
+
// If we have content layout, use it directly to avoid extra wrapper
|
|
1037
|
+
if (this.contentLayout) {
|
|
1038
|
+
return {
|
|
1039
|
+
...this.contentLayout,
|
|
1040
|
+
// Add dialog-specific properties
|
|
1041
|
+
options: {
|
|
1042
|
+
...this.contentLayout.options,
|
|
1043
|
+
...this.dialogState.dialogOptions,
|
|
1044
|
+
},
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
// Fallback to dialog state structure if no content
|
|
1048
|
+
const result = {
|
|
1049
|
+
...this.dialogState,
|
|
1050
|
+
children: [],
|
|
1167
1051
|
};
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1052
|
+
// Add dialog-specific properties
|
|
1053
|
+
if (this.dialogState.dialogOptions) {
|
|
1054
|
+
result.options = { ...result.options, ...this.dialogState.dialogOptions };
|
|
1055
|
+
}
|
|
1056
|
+
return result;
|
|
1057
|
+
}
|
|
1058
|
+
// Dialog-specific methods
|
|
1059
|
+
async show() {
|
|
1060
|
+
const dialogNode = this.build();
|
|
1061
|
+
// Import the dialog renderer component dynamically
|
|
1062
|
+
const { AXPDialogRendererComponent } = await Promise.resolve().then(function () { return dialogRenderer_component; });
|
|
1063
|
+
// Create dialog configuration
|
|
1064
|
+
const dialogConfig = {
|
|
1065
|
+
title: this.dialogState.dialogOptions?.title || '',
|
|
1066
|
+
message: this.dialogState.dialogOptions?.message,
|
|
1067
|
+
context: this.dialogState.dialogOptions?.context || {},
|
|
1068
|
+
definition: dialogNode,
|
|
1069
|
+
actions: this.dialogState.actions,
|
|
1070
|
+
};
|
|
1071
|
+
// The Promise resolves when user clicks an action button
|
|
1072
|
+
return new Promise(async (resolve) => {
|
|
1073
|
+
this.popupService.open(AXPDialogRendererComponent, {
|
|
1074
|
+
title: dialogConfig.title,
|
|
1075
|
+
size: this.dialogState.dialogOptions?.size || 'md',
|
|
1076
|
+
closeButton: this.dialogState.dialogOptions?.closeButton || false,
|
|
1077
|
+
closeOnBackdropClick: false,
|
|
1078
|
+
draggable: false,
|
|
1079
|
+
data: {
|
|
1080
|
+
config: dialogConfig,
|
|
1081
|
+
callBack: (result) => {
|
|
1082
|
+
// Resolve with the dialog reference when user clicks an action
|
|
1083
|
+
resolve(result);
|
|
1084
|
+
},
|
|
1174
1085
|
},
|
|
1175
|
-
|
|
1086
|
+
});
|
|
1176
1087
|
});
|
|
1177
|
-
this.width = this.customWidth ? this.customWidth : (this.mergedOptions().width ?? '200px');
|
|
1178
|
-
this.allowResizing = this.mergedOptions().allowResizing || true;
|
|
1179
|
-
this.cdr.detectChanges();
|
|
1180
1088
|
}
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1089
|
+
}
|
|
1090
|
+
//#endregion
|
|
1091
|
+
//#region ---- Widget Builder Implementation ----
|
|
1092
|
+
/**
|
|
1093
|
+
* Widget Builder - Single Responsibility Principle
|
|
1094
|
+
* Handles individual widget configuration and building
|
|
1095
|
+
*/
|
|
1096
|
+
class WidgetBuilder {
|
|
1097
|
+
constructor(name) {
|
|
1098
|
+
this.widgetState = {
|
|
1099
|
+
type: 'widget',
|
|
1100
|
+
options: {},
|
|
1185
1101
|
};
|
|
1102
|
+
this.inheritanceContext = {};
|
|
1103
|
+
if (name) {
|
|
1104
|
+
this.widgetState.name = name;
|
|
1105
|
+
}
|
|
1186
1106
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
@if (expandHandler) {
|
|
1196
|
-
<div
|
|
1197
|
-
(click)="handleExpandRow(row)"
|
|
1198
|
-
class="ax-expand-handler"
|
|
1199
|
-
[class.ax-invisible]="row.data.hasChild === false"
|
|
1200
|
-
id="ax-expand-handler-container"
|
|
1201
|
-
[style.padding-inline-start.rem]="row.data?.__meta__?.level * 2"
|
|
1202
|
-
>
|
|
1203
|
-
@if (loadingRow() === row) {
|
|
1204
|
-
<i class="fas fa-spinner-third ax-animate-twSpin ax-animate-infinite"></i>
|
|
1205
|
-
} @else {
|
|
1206
|
-
@if (row.data?.__meta__?.expanded) {
|
|
1207
|
-
<i [class]="customCollapseIcon || 'far fa-minus-square ax-text-md ax-opacity-75'"></i>
|
|
1208
|
-
} @else {
|
|
1209
|
-
<i [class]="customExpandIcon || 'far fa-plus-square ax-text-md ax-opacity-75'"></i>
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
</div>
|
|
1107
|
+
type(type) {
|
|
1108
|
+
this.widgetState.type = type;
|
|
1109
|
+
return this;
|
|
1110
|
+
}
|
|
1111
|
+
name(name) {
|
|
1112
|
+
this.widgetState.name = name;
|
|
1113
|
+
if (!this.widgetState.path) {
|
|
1114
|
+
this.widgetState.path = name;
|
|
1213
1115
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1116
|
+
return this;
|
|
1117
|
+
}
|
|
1118
|
+
path(path) {
|
|
1119
|
+
this.widgetState.path = path;
|
|
1120
|
+
return this;
|
|
1121
|
+
}
|
|
1122
|
+
options(options) {
|
|
1123
|
+
// Merge options instead of replacing to preserve inherited properties
|
|
1124
|
+
this.widgetState.options = { ...this.widgetState.options, ...options };
|
|
1125
|
+
return this;
|
|
1126
|
+
}
|
|
1127
|
+
layout(value) {
|
|
1128
|
+
if (typeof value === 'number') {
|
|
1129
|
+
this.widgetState.layout = {
|
|
1130
|
+
positions: {
|
|
1131
|
+
sm: { colSpan: 12 },
|
|
1132
|
+
md: { colSpan: 12 },
|
|
1133
|
+
lg: { colSpan: value },
|
|
1134
|
+
xl: { colSpan: value },
|
|
1135
|
+
xxl: { colSpan: value },
|
|
1136
|
+
},
|
|
1137
|
+
};
|
|
1218
1138
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
<ng-template #footer></ng-template>
|
|
1222
|
-
`, isInline: true, dependencies: [{ kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.AXTranslatorPipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1223
|
-
}
|
|
1224
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXPWidgetColumnRendererComponent, decorators: [{
|
|
1225
|
-
type: Component,
|
|
1226
|
-
args: [{
|
|
1227
|
-
selector: 'axp-widget-column-renderer',
|
|
1228
|
-
template: `
|
|
1229
|
-
<ng-template #header>{{ caption | translate | async }}</ng-template>
|
|
1230
|
-
<ng-template #cell let-row>
|
|
1231
|
-
<div class="ax-flex ax-gap-2 ax-items-center">
|
|
1232
|
-
@if (expandHandler) {
|
|
1233
|
-
<div
|
|
1234
|
-
(click)="handleExpandRow(row)"
|
|
1235
|
-
class="ax-expand-handler"
|
|
1236
|
-
[class.ax-invisible]="row.data.hasChild === false"
|
|
1237
|
-
id="ax-expand-handler-container"
|
|
1238
|
-
[style.padding-inline-start.rem]="row.data?.__meta__?.level * 2"
|
|
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>
|
|
1139
|
+
else {
|
|
1140
|
+
this.widgetState.layout = value;
|
|
1250
1141
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1142
|
+
return this;
|
|
1143
|
+
}
|
|
1144
|
+
mode(mode) {
|
|
1145
|
+
this.widgetState.mode = mode;
|
|
1146
|
+
this.inheritanceContext.mode = mode;
|
|
1147
|
+
return this;
|
|
1148
|
+
}
|
|
1149
|
+
visible(condition) {
|
|
1150
|
+
if (!this.widgetState.options) {
|
|
1151
|
+
this.widgetState.options = {};
|
|
1255
1152
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
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);
|
|
1153
|
+
this.widgetState.options['visible'] = condition;
|
|
1154
|
+
this.inheritanceContext.visible = condition;
|
|
1155
|
+
return this;
|
|
1299
1156
|
}
|
|
1300
|
-
|
|
1301
|
-
this.
|
|
1157
|
+
disabled(condition) {
|
|
1158
|
+
if (!this.widgetState.options) {
|
|
1159
|
+
this.widgetState.options = {};
|
|
1160
|
+
}
|
|
1161
|
+
this.widgetState.options['disabled'] = condition;
|
|
1162
|
+
this.inheritanceContext.disabled = condition;
|
|
1163
|
+
return this;
|
|
1302
1164
|
}
|
|
1303
|
-
|
|
1304
|
-
this.
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
this.
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
this.isBusy = computed(() => {
|
|
1311
|
-
return this.builderService.isBusy();
|
|
1312
|
-
}, ...(ngDevMode ? [{ debugName: "isBusy" }] : []));
|
|
1313
|
-
effect(() => {
|
|
1314
|
-
if (this.contextService.isChanged()) {
|
|
1315
|
-
this.onContextChanged.emit(this.contextService.changeEvent());
|
|
1316
|
-
}
|
|
1317
|
-
});
|
|
1165
|
+
readonly(condition) {
|
|
1166
|
+
if (!this.widgetState.options) {
|
|
1167
|
+
this.widgetState.options = {};
|
|
1168
|
+
}
|
|
1169
|
+
this.widgetState.options['readonly'] = condition;
|
|
1170
|
+
this.inheritanceContext.readonly = condition;
|
|
1171
|
+
return this;
|
|
1318
1172
|
}
|
|
1319
|
-
|
|
1320
|
-
this.
|
|
1173
|
+
direction(direction) {
|
|
1174
|
+
if (!this.widgetState.options) {
|
|
1175
|
+
this.widgetState.options = {};
|
|
1176
|
+
}
|
|
1177
|
+
this.widgetState.options['direction'] = direction;
|
|
1178
|
+
this.inheritanceContext.direction = direction;
|
|
1179
|
+
return this;
|
|
1180
|
+
}
|
|
1181
|
+
// Inheritance context methods
|
|
1182
|
+
withInheritanceContext(context) {
|
|
1183
|
+
this.inheritanceContext = mergeInheritanceContext(context);
|
|
1184
|
+
// Apply inherited properties to widget state
|
|
1185
|
+
const resolved = resolveInheritedProperties(context, this.inheritanceContext);
|
|
1186
|
+
// Always apply inherited properties (remove the conditions that check if already set)
|
|
1187
|
+
// This allows properties to be updated when inheritance context changes
|
|
1188
|
+
if (resolved.mode) {
|
|
1189
|
+
this.widgetState.mode = resolved.mode;
|
|
1190
|
+
}
|
|
1191
|
+
if (!this.widgetState.options)
|
|
1192
|
+
this.widgetState.options = {};
|
|
1193
|
+
if (resolved.disabled !== undefined) {
|
|
1194
|
+
this.widgetState.options['disabled'] = resolved.disabled;
|
|
1195
|
+
}
|
|
1196
|
+
if (resolved.readonly !== undefined) {
|
|
1197
|
+
this.widgetState.options['readonly'] = resolved.readonly;
|
|
1198
|
+
}
|
|
1199
|
+
if (resolved.direction !== undefined) {
|
|
1200
|
+
this.widgetState.options['direction'] = resolved.direction;
|
|
1201
|
+
}
|
|
1202
|
+
if (resolved.visible !== undefined) {
|
|
1203
|
+
this.widgetState.options['visible'] = resolved.visible;
|
|
1204
|
+
}
|
|
1205
|
+
return this;
|
|
1321
1206
|
}
|
|
1322
|
-
|
|
1323
|
-
return this.
|
|
1207
|
+
getInheritanceContext() {
|
|
1208
|
+
return { ...this.inheritanceContext };
|
|
1324
1209
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
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
|
-
});
|
|
1210
|
+
build() {
|
|
1211
|
+
return {
|
|
1212
|
+
name: this.widgetState.name,
|
|
1213
|
+
type: this.widgetState.type,
|
|
1214
|
+
options: this.widgetState.options,
|
|
1215
|
+
mode: this.widgetState.mode,
|
|
1216
|
+
path: this.widgetState.path,
|
|
1217
|
+
defaultValue: this.widgetState.defaultValue,
|
|
1218
|
+
};
|
|
1414
1219
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
// Schedule the component loading
|
|
1431
|
-
this.renderTimeoutId = setTimeout(async () => {
|
|
1432
|
-
await this.loadComponent();
|
|
1433
|
-
this.renderTimeoutId = null;
|
|
1220
|
+
}
|
|
1221
|
+
//#region ---- Action Builder Implementation ----
|
|
1222
|
+
class ActionBuilder {
|
|
1223
|
+
constructor(dialogBuilder) {
|
|
1224
|
+
this.dialogBuilder = dialogBuilder;
|
|
1225
|
+
}
|
|
1226
|
+
cancel(text) {
|
|
1227
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1228
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1229
|
+
}
|
|
1230
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push({
|
|
1231
|
+
title: text || '@general:actions.cancel.title',
|
|
1232
|
+
icon: 'fa-times',
|
|
1233
|
+
color: 'default',
|
|
1234
|
+
command: { name: 'cancel' },
|
|
1434
1235
|
});
|
|
1236
|
+
return this;
|
|
1435
1237
|
}
|
|
1436
|
-
|
|
1437
|
-
if (this.
|
|
1438
|
-
|
|
1439
|
-
}
|
|
1440
|
-
if (this.componentRef) {
|
|
1441
|
-
this.componentRef.destroy();
|
|
1238
|
+
submit(text) {
|
|
1239
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1240
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1442
1241
|
}
|
|
1242
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push({
|
|
1243
|
+
title: text || '@general:actions.submit.title',
|
|
1244
|
+
icon: 'fa-check',
|
|
1245
|
+
color: 'primary',
|
|
1246
|
+
command: { name: 'submit', options: { validate: true } },
|
|
1247
|
+
});
|
|
1248
|
+
return this;
|
|
1443
1249
|
}
|
|
1444
|
-
|
|
1445
|
-
if (this.
|
|
1446
|
-
|
|
1250
|
+
custom(action) {
|
|
1251
|
+
if (!this.dialogBuilder['dialogState'].actions.footer.suffix) {
|
|
1252
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix = [];
|
|
1447
1253
|
}
|
|
1448
|
-
this.
|
|
1449
|
-
|
|
1450
|
-
// Destroy the existing component if it exists
|
|
1451
|
-
if (this.componentRef) {
|
|
1452
|
-
this.componentRef.destroy();
|
|
1453
|
-
}
|
|
1454
|
-
this.viewContainerRef.clear();
|
|
1455
|
-
//
|
|
1456
|
-
const widget = this.widgetRegistery.resolve(this.node().type);
|
|
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;
|
|
1254
|
+
this.dialogBuilder['dialogState'].actions.footer.suffix.push(action);
|
|
1255
|
+
return this;
|
|
1559
1256
|
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
//
|
|
1568
|
-
// PROBLEM: Trigger actions were being evaluated immediately during widget setup/options processing,
|
|
1569
|
-
// causing them to execute before the actual trigger event occurred. This meant triggers would fire
|
|
1570
|
-
// during initialization instead of when the specified context path actually changed.
|
|
1571
|
-
//
|
|
1572
|
-
// ROOT CAUSE: The expression evaluator was processing trigger action expressions (like console.log
|
|
1573
|
-
// or widget.setValue calls) as part of the normal options preprocessing, treating them as dynamic
|
|
1574
|
-
// expressions that needed immediate evaluation.
|
|
1575
|
-
//
|
|
1576
|
-
// SOLUTION: Detect when we're processing trigger actions and store them as static values without
|
|
1577
|
-
// expression evaluation. This ensures trigger actions are only evaluated when the trigger's
|
|
1578
|
-
// subscription callback actually fires (when the event condition is met).
|
|
1579
|
-
//
|
|
1580
|
-
// RESULT: Triggers now only execute when their event filters pass (e.g., when the specified
|
|
1581
|
-
// context path changes), not during widget initialization.
|
|
1582
|
-
if (currentPath.includes('triggers') && (key === 'action' || currentPath.endsWith('.action'))) {
|
|
1583
|
-
// Apply static values directly without expression evaluation
|
|
1584
|
-
this.mergedOptions.update((currentOptions) => {
|
|
1585
|
-
return set(currentOptions, currentPath, value);
|
|
1586
|
-
});
|
|
1587
|
-
return;
|
|
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
|
-
}
|
|
1605
|
-
});
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
class AXPLayoutConversionService {
|
|
1260
|
+
constructor() {
|
|
1261
|
+
//#region ---- Caching ----
|
|
1262
|
+
this.widgetTreeCache = new Map();
|
|
1263
|
+
this.formDefinitionCache = new Map();
|
|
1606
1264
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
set(updatedOptions, path, newValue); // Assuming 'set' can handle paths like 'property.subproperty'
|
|
1621
|
-
});
|
|
1622
|
-
return updatedOptions;
|
|
1623
|
-
});
|
|
1265
|
+
//#endregion
|
|
1266
|
+
//#region ---- Public Methods ----
|
|
1267
|
+
/**
|
|
1268
|
+
* Convert AXPDynamicFormDefinition to AXPWidgetNode tree structure
|
|
1269
|
+
* Groups become Fieldset Layouts with Form Field widgets as children
|
|
1270
|
+
* Fields become Form Field widgets with Editor widgets as children
|
|
1271
|
+
*/
|
|
1272
|
+
convertFormDefinition(formDefinition) {
|
|
1273
|
+
// Create cache key based on form definition content
|
|
1274
|
+
const cacheKey = this.createFormDefinitionCacheKey(formDefinition);
|
|
1275
|
+
// Check cache first
|
|
1276
|
+
if (this.widgetTreeCache.has(cacheKey)) {
|
|
1277
|
+
return this.widgetTreeCache.get(cacheKey);
|
|
1624
1278
|
}
|
|
1625
|
-
|
|
1279
|
+
// Generate widget tree
|
|
1280
|
+
const widgetTree = {
|
|
1281
|
+
type: 'grid-layout',
|
|
1282
|
+
name: 'dynamic-form-container',
|
|
1283
|
+
options: {
|
|
1284
|
+
title: 'Dynamic Form',
|
|
1285
|
+
grid: {
|
|
1286
|
+
default: {
|
|
1287
|
+
columns: 1,
|
|
1288
|
+
gap: '1rem',
|
|
1289
|
+
},
|
|
1290
|
+
},
|
|
1291
|
+
},
|
|
1292
|
+
children: formDefinition.groups.map((group) => this.createGroupAsFieldsetWidget(group)),
|
|
1293
|
+
};
|
|
1294
|
+
// Cache the result
|
|
1295
|
+
this.widgetTreeCache.set(cacheKey, widgetTree);
|
|
1296
|
+
return widgetTree;
|
|
1626
1297
|
}
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1298
|
+
/**
|
|
1299
|
+
* Convert AXPWidgetNode tree back to AXPDynamicFormDefinition
|
|
1300
|
+
* Parses Fieldset Layouts back to Groups
|
|
1301
|
+
* Parses Form Field widgets back to Fields
|
|
1302
|
+
*/
|
|
1303
|
+
convertWidgetTreeToFormDefinition(widgetTree) {
|
|
1304
|
+
// Create cache key based on widget tree content
|
|
1305
|
+
const cacheKey = this.createWidgetTreeCacheKey(widgetTree);
|
|
1306
|
+
// Check cache first
|
|
1307
|
+
if (this.formDefinitionCache.has(cacheKey)) {
|
|
1308
|
+
return this.formDefinitionCache.get(cacheKey);
|
|
1631
1309
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1310
|
+
// Parse widget tree
|
|
1311
|
+
const groups = [];
|
|
1312
|
+
if (widgetTree.children) {
|
|
1313
|
+
widgetTree.children.forEach((child) => {
|
|
1314
|
+
if (child.type === 'fieldset-layout') {
|
|
1315
|
+
const group = this.extractGroupFromFieldset(child);
|
|
1316
|
+
groups.push(group);
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1637
1319
|
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1320
|
+
const formDefinition = { groups };
|
|
1321
|
+
// Cache the result
|
|
1322
|
+
this.formDefinitionCache.set(cacheKey, formDefinition);
|
|
1323
|
+
return formDefinition;
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Validate that a widget tree represents a valid dynamic form structure
|
|
1327
|
+
*/
|
|
1328
|
+
validateFormWidgetTree(widgetTree) {
|
|
1329
|
+
if (!widgetTree || widgetTree.type !== 'grid-layout') {
|
|
1640
1330
|
return false;
|
|
1641
1331
|
}
|
|
1332
|
+
if (!widgetTree.children || widgetTree.children.length === 0) {
|
|
1333
|
+
return true; // Empty form is valid
|
|
1334
|
+
}
|
|
1335
|
+
// Check that all children are fieldset-layout widgets
|
|
1336
|
+
return widgetTree.children.every((child) => child.type === 'fieldset-layout' &&
|
|
1337
|
+
child.children &&
|
|
1338
|
+
child.children.every((formField) => formField.type === 'form-field' && formField.children && formField.children.length > 0));
|
|
1642
1339
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
vars: this.getVariablesScope(),
|
|
1650
|
-
};
|
|
1340
|
+
/**
|
|
1341
|
+
* Clear all caches
|
|
1342
|
+
*/
|
|
1343
|
+
clearCaches() {
|
|
1344
|
+
this.widgetTreeCache.clear();
|
|
1345
|
+
this.formDefinitionCache.clear();
|
|
1651
1346
|
}
|
|
1652
|
-
|
|
1347
|
+
/**
|
|
1348
|
+
* Get cache statistics
|
|
1349
|
+
*/
|
|
1350
|
+
getCacheStats() {
|
|
1653
1351
|
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
|
-
},
|
|
1352
|
+
widgetTreeCacheSize: this.widgetTreeCache.size,
|
|
1353
|
+
formDefinitionCacheSize: this.formDefinitionCache.size,
|
|
1669
1354
|
};
|
|
1670
1355
|
}
|
|
1671
|
-
|
|
1356
|
+
//#endregion
|
|
1357
|
+
//#region ---- Private Methods ----
|
|
1358
|
+
/**
|
|
1359
|
+
* Convert a single group to Fieldset widget structure
|
|
1360
|
+
*/
|
|
1361
|
+
createGroupAsFieldsetWidget(group) {
|
|
1362
|
+
// Determine columns count from layout or default to 1
|
|
1363
|
+
const columnsCount = 1;
|
|
1672
1364
|
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
|
-
}));
|
|
1365
|
+
type: 'fieldset-layout',
|
|
1366
|
+
name: group.name,
|
|
1367
|
+
options: {
|
|
1368
|
+
title: group.title,
|
|
1369
|
+
description: group.description,
|
|
1370
|
+
cols: columnsCount,
|
|
1698
1371
|
},
|
|
1699
|
-
|
|
1372
|
+
children: this.createFieldWidgets(group.parameters, columnsCount),
|
|
1700
1373
|
};
|
|
1701
1374
|
}
|
|
1702
|
-
|
|
1375
|
+
/**
|
|
1376
|
+
* Convert fields to Form Field widgets
|
|
1377
|
+
*/
|
|
1378
|
+
createFieldWidgets(fields, columnsCount) {
|
|
1379
|
+
return fields.map((field) => this.createFormFieldWidget(field));
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Convert a single field to Form Field widget with editor as child
|
|
1383
|
+
*/
|
|
1384
|
+
createFormFieldWidget(field) {
|
|
1703
1385
|
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);
|
|
1386
|
+
type: 'form-field',
|
|
1387
|
+
name: field.path,
|
|
1388
|
+
options: {
|
|
1389
|
+
label: field.title,
|
|
1390
|
+
description: field.description,
|
|
1391
|
+
showLabel: true,
|
|
1724
1392
|
},
|
|
1393
|
+
children: [field.widget], // The editor widget becomes a child of form-field
|
|
1725
1394
|
};
|
|
1726
1395
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1396
|
+
/**
|
|
1397
|
+
* Extract group information from Fieldset Layout widget
|
|
1398
|
+
*/
|
|
1399
|
+
extractGroupFromFieldset(fieldsetNode) {
|
|
1400
|
+
const columnsCount = fieldsetNode.options?.['cols'] || 1;
|
|
1401
|
+
// Extract fields directly from fieldset children
|
|
1402
|
+
const fields = [];
|
|
1403
|
+
if (fieldsetNode.children) {
|
|
1404
|
+
fieldsetNode.children.forEach((formField) => {
|
|
1405
|
+
if (formField.type === 'form-field' && formField.children && formField.children.length > 0) {
|
|
1406
|
+
const field = this.extractFieldFromFormWidget(formField);
|
|
1407
|
+
if (field) {
|
|
1408
|
+
fields.push(field);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
return {
|
|
1414
|
+
name: fieldsetNode.name || `group-${Date.now()}`,
|
|
1415
|
+
title: fieldsetNode.options?.['title'],
|
|
1416
|
+
description: fieldsetNode.options?.['description'],
|
|
1417
|
+
parameters: fields,
|
|
1738
1418
|
};
|
|
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
1419
|
}
|
|
1747
|
-
|
|
1420
|
+
/**
|
|
1421
|
+
* Extract field information from Form Field widget
|
|
1422
|
+
*/
|
|
1423
|
+
extractFieldFromFormWidget(formFieldNode) {
|
|
1424
|
+
if (!formFieldNode.children || formFieldNode.children.length === 0) {
|
|
1425
|
+
return null;
|
|
1426
|
+
}
|
|
1427
|
+
const editorWidget = formFieldNode.children[0];
|
|
1748
1428
|
return {
|
|
1749
|
-
|
|
1429
|
+
path: formFieldNode.name || editorWidget.name || `field-${Date.now()}`,
|
|
1430
|
+
title: formFieldNode.options?.['label'],
|
|
1431
|
+
description: formFieldNode.options?.['description'],
|
|
1432
|
+
widget: editorWidget,
|
|
1433
|
+
mode: formFieldNode.mode,
|
|
1750
1434
|
};
|
|
1751
1435
|
}
|
|
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
|
-
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Create cache key for form definition
|
|
1438
|
+
*/
|
|
1439
|
+
createFormDefinitionCacheKey(formDefinition) {
|
|
1440
|
+
// Create a hash-like key instead of full JSON string
|
|
1441
|
+
const keyParts = [];
|
|
1442
|
+
keyParts.push(`groups:${formDefinition.groups.length}`);
|
|
1443
|
+
formDefinition.groups.forEach((group, groupIndex) => {
|
|
1444
|
+
keyParts.push(`g${groupIndex}:${group.name}:${group.parameters.length}`);
|
|
1445
|
+
group.parameters.forEach((param, paramIndex) => {
|
|
1446
|
+
keyParts.push(`p${groupIndex}.${paramIndex}:${param.path}:${param.widget.type}`);
|
|
1447
|
+
});
|
|
1448
|
+
});
|
|
1449
|
+
if (formDefinition.mode) {
|
|
1450
|
+
keyParts.push(`mode:${formDefinition.mode}`);
|
|
1777
1451
|
}
|
|
1452
|
+
// Join with delimiter and create a shorter hash
|
|
1453
|
+
const keyString = keyParts.join('|');
|
|
1454
|
+
// If still too long, create a simple hash
|
|
1455
|
+
if (keyString.length > 100) {
|
|
1456
|
+
return this.createSimpleHash(keyString);
|
|
1457
|
+
}
|
|
1458
|
+
return keyString;
|
|
1778
1459
|
}
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
return null;
|
|
1789
|
-
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Create cache key for widget tree
|
|
1462
|
+
*/
|
|
1463
|
+
createWidgetTreeCacheKey(widgetTree) {
|
|
1464
|
+
// Create a hash-like key instead of full JSON string
|
|
1465
|
+
const keyParts = [];
|
|
1466
|
+
keyParts.push(`type:${widgetTree.type}`);
|
|
1467
|
+
if (widgetTree.name) {
|
|
1468
|
+
keyParts.push(`name:${widgetTree.name}`);
|
|
1790
1469
|
}
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1470
|
+
if (widgetTree.children) {
|
|
1471
|
+
keyParts.push(`children:${widgetTree.children.length}`);
|
|
1472
|
+
widgetTree.children.forEach((child, index) => {
|
|
1473
|
+
keyParts.push(`c${index}:${child.type}`);
|
|
1474
|
+
if (child.children) {
|
|
1475
|
+
keyParts.push(`cc${index}:${child.children.length}`);
|
|
1476
|
+
child.children.forEach((grandChild, gIndex) => {
|
|
1477
|
+
keyParts.push(`gc${index}.${gIndex}:${grandChild.type}`);
|
|
1478
|
+
if (grandChild.children) {
|
|
1479
|
+
keyParts.push(`gcc${index}.${gIndex}:${grandChild.children.length}`);
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1794
1484
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1485
|
+
// Join with delimiter and create a shorter hash
|
|
1486
|
+
const keyString = keyParts.join('|');
|
|
1487
|
+
// If still too long, create a simple hash
|
|
1488
|
+
if (keyString.length > 100) {
|
|
1489
|
+
return this.createSimpleHash(keyString);
|
|
1800
1490
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1491
|
+
return keyString;
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Create a simple hash from a string
|
|
1495
|
+
*/
|
|
1496
|
+
createSimpleHash(str) {
|
|
1497
|
+
let hash = 0;
|
|
1498
|
+
if (str.length === 0)
|
|
1499
|
+
return hash.toString();
|
|
1500
|
+
for (let i = 0; i < str.length; i++) {
|
|
1501
|
+
const char = str.charCodeAt(i);
|
|
1502
|
+
hash = (hash << 5) - hash + char;
|
|
1503
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
1803
1504
|
}
|
|
1505
|
+
return Math.abs(hash).toString(36); // Convert to base36 for shorter string
|
|
1804
1506
|
}
|
|
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 }); }
|
|
1507
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPLayoutConversionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1508
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPLayoutConversionService, providedIn: 'root' }); }
|
|
1811
1509
|
}
|
|
1812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
1813
|
-
type:
|
|
1510
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPLayoutConversionService, decorators: [{
|
|
1511
|
+
type: Injectable,
|
|
1814
1512
|
args: [{
|
|
1815
|
-
|
|
1816
|
-
exportAs: 'widgetRenderer',
|
|
1817
|
-
providers: [
|
|
1818
|
-
{
|
|
1819
|
-
provide: AXUnsubscriber,
|
|
1820
|
-
},
|
|
1821
|
-
],
|
|
1822
|
-
standalone: false,
|
|
1513
|
+
providedIn: 'root',
|
|
1823
1514
|
}]
|
|
1824
|
-
}]
|
|
1515
|
+
}] });
|
|
1825
1516
|
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1517
|
+
class AXPLayoutRendererComponent {
|
|
1518
|
+
constructor() {
|
|
1519
|
+
this.evaluatorService = inject(AXPExpressionEvaluatorService);
|
|
1520
|
+
this.conversionService = inject(AXPLayoutConversionService);
|
|
1521
|
+
/**
|
|
1522
|
+
* Tracks the latest scheduled evaluation to ensure last-write-wins for async evaluate
|
|
1523
|
+
*/
|
|
1524
|
+
this.evaluationRunId = 0;
|
|
1525
|
+
/**
|
|
1526
|
+
* RxJS subjects for context management
|
|
1527
|
+
*/
|
|
1528
|
+
this.contextUpdateSubject = new Subject();
|
|
1529
|
+
this.contextChangeSubject = new Subject();
|
|
1530
|
+
/**
|
|
1531
|
+
* Cache for expression evaluation results
|
|
1532
|
+
*/
|
|
1533
|
+
this.expressionCache = new Map();
|
|
1534
|
+
/**
|
|
1535
|
+
* Cache for widget tree comparisons
|
|
1536
|
+
*/
|
|
1537
|
+
this.widgetTreeCache = new Map();
|
|
1538
|
+
/**
|
|
1539
|
+
* Last layout hash for change detection
|
|
1540
|
+
*/
|
|
1541
|
+
this.lastLayoutHash = '';
|
|
1542
|
+
//#region ---- Inputs ----
|
|
1543
|
+
/**
|
|
1544
|
+
* Form definition containing groups and fields OR widget tree
|
|
1545
|
+
*/
|
|
1546
|
+
this.layout = input.required(...(ngDevMode ? [{ debugName: "layout" }] : []));
|
|
1547
|
+
/**
|
|
1548
|
+
* Form context/model data
|
|
1549
|
+
*/
|
|
1550
|
+
this.context = model({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
1551
|
+
/**
|
|
1552
|
+
* Form appearance and density styling (normal, compact, spacious)
|
|
1553
|
+
*/
|
|
1554
|
+
this.look = input('fieldset', ...(ngDevMode ? [{ debugName: "look" }] : []));
|
|
1555
|
+
/**
|
|
1556
|
+
* Default form mode. Can be overridden by section/group and field.
|
|
1557
|
+
*/
|
|
1558
|
+
this.mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
1559
|
+
//#endregion
|
|
1560
|
+
//#region ---- Widget Tree Conversion ----
|
|
1561
|
+
this.widgetTree = signal(null, ...(ngDevMode ? [{ debugName: "widgetTree" }] : []));
|
|
1562
|
+
/**
|
|
1563
|
+
* Convert and evaluate data when inputs change (optimized with RxJS)
|
|
1564
|
+
*/
|
|
1565
|
+
this.conversionEffect = effect(() => {
|
|
1566
|
+
const inputData = this.layout();
|
|
1567
|
+
const ctx = this.internalContext();
|
|
1568
|
+
const look = this.look();
|
|
1569
|
+
const runId = ++this.evaluationRunId;
|
|
1570
|
+
// Generate layout hash for change detection
|
|
1571
|
+
const layoutHash = this.generateLayoutHash(inputData, look);
|
|
1572
|
+
// Skip if layout hasn't changed
|
|
1573
|
+
if (layoutHash === this.lastLayoutHash && this.widgetTree()) {
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
this.lastLayoutHash = layoutHash;
|
|
1577
|
+
(async () => {
|
|
1578
|
+
// First evaluate expressions if needed
|
|
1579
|
+
const evaluated = await this.expressionEvaluator(inputData, ctx);
|
|
1580
|
+
// Ignore stale results
|
|
1581
|
+
if (runId !== this.evaluationRunId) {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
// Convert to widget tree (this will also apply the layout look)
|
|
1585
|
+
const tree = evaluated;
|
|
1586
|
+
// Update widget tree
|
|
1587
|
+
const prev = this.widgetTree();
|
|
1588
|
+
if (!isEqual(prev, tree)) {
|
|
1589
|
+
tree.mode = this.mode();
|
|
1590
|
+
this.widgetTree.set(tree);
|
|
1591
|
+
}
|
|
1592
|
+
})();
|
|
1593
|
+
}, ...(ngDevMode ? [{ debugName: "conversionEffect" }] : []));
|
|
1594
|
+
//#endregion
|
|
1595
|
+
//#region ---- Outputs ----
|
|
1596
|
+
/**
|
|
1597
|
+
* Emitted when context change is initiated
|
|
1598
|
+
*/
|
|
1599
|
+
this.contextInitiated = output();
|
|
1600
|
+
/**
|
|
1601
|
+
* Emitted when form becomes valid/invalid
|
|
1602
|
+
*/
|
|
1603
|
+
this.validityChange = output();
|
|
1604
|
+
//#endregion
|
|
1605
|
+
//#region ---- Properties ----
|
|
1606
|
+
this.form = viewChild(AXFormComponent, ...(ngDevMode ? [{ debugName: "form" }] : []));
|
|
1607
|
+
this.container = viewChild(AXPWidgetContainerComponent, ...(ngDevMode ? [{ debugName: "container" }] : []));
|
|
1608
|
+
/**
|
|
1609
|
+
* Internal context signal for reactivity
|
|
1610
|
+
*/
|
|
1611
|
+
this.internalContext = signal({}, ...(ngDevMode ? [{ debugName: "internalContext" }] : []));
|
|
1612
|
+
/**
|
|
1613
|
+
* Initial context for reset functionality
|
|
1614
|
+
*/
|
|
1615
|
+
this.initialContext = {};
|
|
1616
|
+
//#endregion
|
|
1617
|
+
//#region ---- Effects ----
|
|
1618
|
+
/**
|
|
1619
|
+
* Effect to sync context changes from external to internal (optimized with RxJS)
|
|
1620
|
+
*/
|
|
1621
|
+
this.#contextSyncEffect = effect(() => {
|
|
1622
|
+
const ctx = this.context() ?? {};
|
|
1623
|
+
this.contextUpdateSubject.next(ctx);
|
|
1624
|
+
}, ...(ngDevMode ? [{ debugName: "#contextSyncEffect" }] : []));
|
|
1625
|
+
/**
|
|
1626
|
+
* Effect to handle widget tree status changes
|
|
1627
|
+
*/
|
|
1628
|
+
this.#widgetStatusEffect = effect(() => {
|
|
1629
|
+
const widgetTree = this.widgetTree();
|
|
1630
|
+
if (widgetTree) {
|
|
1631
|
+
this.container()?.builderService.setStatus(AXPPageStatus.Rendered);
|
|
1632
|
+
}
|
|
1633
|
+
}, ...(ngDevMode ? [{ debugName: "#widgetStatusEffect" }] : []));
|
|
1634
|
+
}
|
|
1635
|
+
async expressionEvaluator(expression, context) {
|
|
1636
|
+
// Check if it's a form definition that needs conversion
|
|
1637
|
+
if (this.isFormDefinition(expression)) {
|
|
1638
|
+
return this.conversionService.convertFormDefinition(expression);
|
|
1639
|
+
}
|
|
1640
|
+
// Generate cache key using a more efficient method
|
|
1641
|
+
const cacheKey = this.generateCacheKey(expression, context);
|
|
1642
|
+
// Check cache first
|
|
1643
|
+
if (this.expressionCache.has(cacheKey)) {
|
|
1644
|
+
return this.expressionCache.get(cacheKey);
|
|
1645
|
+
}
|
|
1646
|
+
const scope = {
|
|
1647
|
+
context: {
|
|
1648
|
+
eval: (path) => get(context, path),
|
|
1649
|
+
},
|
|
1842
1650
|
};
|
|
1651
|
+
const result = await this.evaluatorService.evaluate(expression, scope);
|
|
1652
|
+
// Cache result with LRU-like behavior
|
|
1653
|
+
if (this.expressionCache.size > 50) {
|
|
1654
|
+
// Clear half the cache when it gets too large
|
|
1655
|
+
const keysToDelete = Array.from(this.expressionCache.keys()).slice(0, 25);
|
|
1656
|
+
keysToDelete.forEach((key) => this.expressionCache.delete(key));
|
|
1657
|
+
}
|
|
1658
|
+
this.expressionCache.set(cacheKey, result);
|
|
1659
|
+
return result;
|
|
1660
|
+
}
|
|
1661
|
+
//#endregion
|
|
1662
|
+
//#region ---- Lifecycle Methods ----
|
|
1663
|
+
ngOnInit() {
|
|
1664
|
+
// Initialize internal context with input context
|
|
1665
|
+
const ctx = this.context() ?? {};
|
|
1666
|
+
this.internalContext.set(ctx);
|
|
1667
|
+
// Store initial context for reset functionality
|
|
1668
|
+
this.initialContext = cloneDeep(ctx);
|
|
1669
|
+
// Setup RxJS streams for context management
|
|
1670
|
+
this.setupContextStreams();
|
|
1671
|
+
}
|
|
1672
|
+
//#endregion
|
|
1673
|
+
//#region ---- Effects ----
|
|
1674
|
+
/**
|
|
1675
|
+
* Effect to sync context changes from external to internal (optimized with RxJS)
|
|
1676
|
+
*/
|
|
1677
|
+
#contextSyncEffect;
|
|
1678
|
+
/**
|
|
1679
|
+
* Effect to handle widget tree status changes
|
|
1680
|
+
*/
|
|
1681
|
+
#widgetStatusEffect;
|
|
1682
|
+
//#endregion
|
|
1683
|
+
//#region ---- Event Handlers ----
|
|
1684
|
+
/**
|
|
1685
|
+
* Handle context change events from widget container (optimized with RxJS)
|
|
1686
|
+
*/
|
|
1687
|
+
handleContextChanged(event) {
|
|
1688
|
+
if (event.state === 'initiated') {
|
|
1689
|
+
this.contextInitiated.emit(event.data);
|
|
1690
|
+
}
|
|
1691
|
+
else {
|
|
1692
|
+
this.contextChangeSubject.next(event.data ?? {});
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
//#endregion
|
|
1696
|
+
//#region ---- Public Methods ----
|
|
1697
|
+
/**
|
|
1698
|
+
* Get the form component instance
|
|
1699
|
+
*/
|
|
1700
|
+
getForm() {
|
|
1701
|
+
return this.form();
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Get the widget container component instance
|
|
1705
|
+
*/
|
|
1706
|
+
getContainer() {
|
|
1707
|
+
return this.container();
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Get current form context
|
|
1711
|
+
*/
|
|
1712
|
+
getContext() {
|
|
1713
|
+
return this.internalContext();
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Update form context programmatically
|
|
1717
|
+
*/
|
|
1718
|
+
updateContext(context) {
|
|
1719
|
+
this.internalContext.set(context);
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Get the current widget tree
|
|
1723
|
+
*/
|
|
1724
|
+
getWidgetTree() {
|
|
1725
|
+
return this.widgetTree();
|
|
1843
1726
|
}
|
|
1844
|
-
|
|
1727
|
+
/**
|
|
1728
|
+
* Validate the form
|
|
1729
|
+
*/
|
|
1730
|
+
async validate() {
|
|
1731
|
+
const form = this.form();
|
|
1732
|
+
if (form) {
|
|
1733
|
+
const isValid = await form.validate();
|
|
1734
|
+
this.validityChange.emit(isValid.result);
|
|
1735
|
+
return isValid;
|
|
1736
|
+
}
|
|
1845
1737
|
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
|
-
],
|
|
1738
|
+
result: false,
|
|
1739
|
+
messages: [],
|
|
1740
|
+
rules: [],
|
|
1858
1741
|
};
|
|
1859
1742
|
}
|
|
1860
1743
|
/**
|
|
1861
|
-
*
|
|
1744
|
+
* Clear the form context
|
|
1745
|
+
*/
|
|
1746
|
+
clear() {
|
|
1747
|
+
// Clear internal context
|
|
1748
|
+
this.internalContext.set({});
|
|
1749
|
+
// Update the model signal
|
|
1750
|
+
this.context.set({});
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Reset the form to its initial state
|
|
1754
|
+
*/
|
|
1755
|
+
reset() {
|
|
1756
|
+
// Reset to initial context
|
|
1757
|
+
const resetContext = cloneDeep(this.initialContext);
|
|
1758
|
+
this.internalContext.set(resetContext);
|
|
1759
|
+
// Update the model signal
|
|
1760
|
+
this.context.set(resetContext);
|
|
1761
|
+
}
|
|
1762
|
+
//#endregion
|
|
1763
|
+
//#region ---- RxJS Stream Setup ----
|
|
1764
|
+
/**
|
|
1765
|
+
* Setup RxJS streams for context management
|
|
1862
1766
|
*/
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1767
|
+
setupContextStreams() {
|
|
1768
|
+
// Debounced context updates from external source
|
|
1769
|
+
this.contextUpdateSubject
|
|
1770
|
+
.pipe(debounceTime(16), // ~60fps
|
|
1771
|
+
distinctUntilChanged((prev, curr) => isEqual(prev, curr)), startWith(this.context() ?? {}))
|
|
1772
|
+
.subscribe((ctx) => {
|
|
1773
|
+
this.internalContext.set(ctx);
|
|
1866
1774
|
});
|
|
1775
|
+
// Debounced context changes from widgets
|
|
1776
|
+
this.contextChangeSubject
|
|
1777
|
+
.pipe(debounceTime(16), // ~60fps
|
|
1778
|
+
distinctUntilChanged((prev, curr) => isEqual(prev, curr)))
|
|
1779
|
+
.subscribe((ctx) => {
|
|
1780
|
+
this.internalContext.set(ctx);
|
|
1781
|
+
// Update the model signal directly - it will emit change events automatically
|
|
1782
|
+
this.context.set(this.internalContext());
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
//#endregion
|
|
1786
|
+
//#region ---- Type Guards ----
|
|
1787
|
+
/**
|
|
1788
|
+
* Type guard to check if the input is a form definition
|
|
1789
|
+
*/
|
|
1790
|
+
isFormDefinition(data) {
|
|
1791
|
+
return data && typeof data === 'object' && 'groups' in data && Array.isArray(data.groups);
|
|
1792
|
+
}
|
|
1793
|
+
//#endregion
|
|
1794
|
+
//#region ---- Utility Methods ----
|
|
1795
|
+
/**
|
|
1796
|
+
* Generate layout hash for change detection (short hash)
|
|
1797
|
+
*/
|
|
1798
|
+
generateLayoutHash(layout, look) {
|
|
1799
|
+
if (!layout)
|
|
1800
|
+
return '';
|
|
1801
|
+
// Generate short hash for large layout strings
|
|
1802
|
+
const layoutStr = typeof layout === 'string' ? layout : JSON.stringify(layout);
|
|
1803
|
+
const layoutHash = this.simpleHash(layoutStr);
|
|
1804
|
+
return `${layoutHash}|${look}`;
|
|
1805
|
+
}
|
|
1806
|
+
/**
|
|
1807
|
+
* Generate cache key for expression evaluation (short hash)
|
|
1808
|
+
*/
|
|
1809
|
+
generateCacheKey(expression, context) {
|
|
1810
|
+
// Use short hash for better performance
|
|
1811
|
+
const exprStr = typeof expression === 'string' ? expression : JSON.stringify(expression);
|
|
1812
|
+
const exprHash = this.simpleHash(exprStr);
|
|
1813
|
+
const ctxHash = this.generateContextHash(context);
|
|
1814
|
+
return `${exprHash}|${ctxHash}`;
|
|
1815
|
+
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Generate a simple hash for context change detection
|
|
1818
|
+
*/
|
|
1819
|
+
generateContextHash(context) {
|
|
1820
|
+
if (!context || typeof context !== 'object') {
|
|
1821
|
+
return String(context);
|
|
1822
|
+
}
|
|
1823
|
+
// Generate short hash for context
|
|
1824
|
+
const keys = Object.keys(context).sort();
|
|
1825
|
+
const contextStr = keys.map((key) => `${key}:${context[key]}`).join('|');
|
|
1826
|
+
return this.simpleHash(contextStr);
|
|
1867
1827
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1828
|
+
/**
|
|
1829
|
+
* Simple hash function for generating short keys
|
|
1830
|
+
*/
|
|
1831
|
+
simpleHash(str) {
|
|
1832
|
+
let hash = 0;
|
|
1833
|
+
if (str.length === 0)
|
|
1834
|
+
return hash.toString();
|
|
1835
|
+
for (let i = 0; i < str.length; i++) {
|
|
1836
|
+
const char = str.charCodeAt(i);
|
|
1837
|
+
hash = (hash << 5) - hash + char;
|
|
1838
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
1839
|
+
}
|
|
1840
|
+
// Convert to positive hex string
|
|
1841
|
+
return Math.abs(hash).toString(16);
|
|
1842
|
+
}
|
|
1843
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPLayoutRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1844
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", 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: `
|
|
1845
|
+
<ax-form>
|
|
1846
|
+
<axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
|
|
1847
|
+
@if (widgetTree()) {
|
|
1848
|
+
<ng-container axp-widget-renderer [node]="widgetTree()!" [mode]="mode()"></ng-container>
|
|
1849
|
+
}
|
|
1850
|
+
</axp-widgets-container>
|
|
1851
|
+
</ax-form>
|
|
1852
|
+
`, 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 }); }
|
|
1853
|
+
}
|
|
1854
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPLayoutRendererComponent, decorators: [{
|
|
1855
|
+
type: Component,
|
|
1856
|
+
args: [{ selector: 'axp-layout-renderer', standalone: true, imports: [CommonModule, AXPWidgetCoreModule, AXFormModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
1857
|
+
<ax-form>
|
|
1858
|
+
<axp-widgets-container [context]="internalContext()" (onContextChanged)="handleContextChanged($event)">
|
|
1859
|
+
@if (widgetTree()) {
|
|
1860
|
+
<ng-container axp-widget-renderer [node]="widgetTree()!" [mode]="mode()"></ng-container>
|
|
1861
|
+
}
|
|
1862
|
+
</axp-widgets-container>
|
|
1863
|
+
</ax-form>
|
|
1864
|
+
`, styles: [":host{display:block;width:100%}\n"] }]
|
|
1865
|
+
}] });
|
|
1866
|
+
|
|
1867
|
+
class LayoutBuilderModule {
|
|
1868
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LayoutBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1869
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.4", ngImport: i0, type: LayoutBuilderModule, imports: [CommonModule, AXPLayoutRendererComponent], exports: [AXPLayoutRendererComponent] }); }
|
|
1870
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LayoutBuilderModule, providers: [AXPLayoutBuilderService], imports: [CommonModule, AXPLayoutRendererComponent] }); }
|
|
1871
1871
|
}
|
|
1872
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.
|
|
1872
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: LayoutBuilderModule, decorators: [{
|
|
1873
1873
|
type: NgModule,
|
|
1874
1874
|
args: [{
|
|
1875
|
-
imports: [CommonModule,
|
|
1876
|
-
|
|
1877
|
-
|
|
1875
|
+
imports: [CommonModule, AXPLayoutRendererComponent],
|
|
1876
|
+
providers: [AXPLayoutBuilderService],
|
|
1877
|
+
exports: [AXPLayoutRendererComponent],
|
|
1878
1878
|
}]
|
|
1879
|
-
}]
|
|
1880
|
-
type: Optional
|
|
1881
|
-
}, {
|
|
1882
|
-
type: Inject,
|
|
1883
|
-
args: ['AXPLayoutBuilderModuleFactory']
|
|
1884
|
-
}] }] });
|
|
1879
|
+
}] });
|
|
1885
1880
|
|
|
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
|
-
}
|
|
1881
|
+
//#endregion
|
|
1882
|
+
|
|
1883
|
+
class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
1884
|
+
constructor() {
|
|
1885
|
+
super(...arguments);
|
|
1886
|
+
this.result = new EventEmitter();
|
|
1887
|
+
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : []));
|
|
1888
|
+
// This will be set by the popup service automatically - same as dynamic-dialog
|
|
1889
|
+
this.callBack = () => { };
|
|
1890
|
+
this.isDialogLoading = signal(false, ...(ngDevMode ? [{ debugName: "isDialogLoading" }] : []));
|
|
1917
1891
|
}
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1892
|
+
ngOnInit() {
|
|
1893
|
+
// Initialize context with provided context
|
|
1894
|
+
this.context.set(this.config?.context || {});
|
|
1921
1895
|
}
|
|
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
|
-
};
|
|
1896
|
+
handleContextChanged(event) {
|
|
1897
|
+
this.context.set(event);
|
|
1930
1898
|
}
|
|
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
|
-
};
|
|
1899
|
+
handleContextInitiated(event) {
|
|
1900
|
+
this.context.set(event);
|
|
1939
1901
|
}
|
|
1940
|
-
|
|
1941
|
-
return
|
|
1942
|
-
margin: this.parseSidesWithUnits(input.margin),
|
|
1943
|
-
padding: this.parseSidesWithUnits(input.padding),
|
|
1944
|
-
};
|
|
1902
|
+
visibleFooterPrefixActions() {
|
|
1903
|
+
return this.config?.actions?.footer?.prefix || [];
|
|
1945
1904
|
}
|
|
1946
|
-
|
|
1947
|
-
return
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
style: this.parseSides(input.style),
|
|
1952
|
-
};
|
|
1905
|
+
visibleFooterSuffixActions() {
|
|
1906
|
+
return (this.config?.actions?.footer?.suffix || [
|
|
1907
|
+
{ title: 'Cancel', color: 'secondary', command: { name: 'cancel' } },
|
|
1908
|
+
{ title: 'Confirm', color: 'primary', command: { name: 'confirm' } },
|
|
1909
|
+
]);
|
|
1953
1910
|
}
|
|
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
|
-
};
|
|
1911
|
+
isFormLoading() {
|
|
1912
|
+
return this.isDialogLoading();
|
|
1970
1913
|
}
|
|
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
|
-
};
|
|
1914
|
+
isSubmitting() {
|
|
1915
|
+
return this.isDialogLoading();
|
|
1999
1916
|
}
|
|
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,
|
|
1917
|
+
async executeAction(action) {
|
|
1918
|
+
const actionName = action.command?.name || action.title?.toLowerCase();
|
|
1919
|
+
// Store the action and context - same pattern as dynamic-dialog
|
|
1920
|
+
const result = {
|
|
1921
|
+
context: this.context(),
|
|
1922
|
+
action: actionName,
|
|
2034
1923
|
};
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
if (
|
|
2039
|
-
|
|
1924
|
+
// Store result in component property
|
|
1925
|
+
this.dialogResult = result;
|
|
1926
|
+
// Store in popup data for DialogRef access
|
|
1927
|
+
if (this.data) {
|
|
1928
|
+
this.data.context = result.context;
|
|
1929
|
+
this.data.action = result.action;
|
|
2040
1930
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
1931
|
+
// Call the callback with DialogRef - same pattern as dynamic-dialog
|
|
1932
|
+
this.callBack({
|
|
1933
|
+
close: (result) => {
|
|
1934
|
+
this.close(result);
|
|
1935
|
+
},
|
|
1936
|
+
context: () => {
|
|
1937
|
+
return this.context();
|
|
1938
|
+
},
|
|
1939
|
+
action: () => {
|
|
1940
|
+
return result.action;
|
|
1941
|
+
},
|
|
1942
|
+
setLoading: (loading) => {
|
|
1943
|
+
this.isDialogLoading.set(loading);
|
|
1944
|
+
},
|
|
1945
|
+
});
|
|
2048
1946
|
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
const nonEmptyBreakpoints = [];
|
|
2053
|
-
for (const breakpoint of breakpoints) {
|
|
2054
|
-
if (values[breakpoint] !== undefined) {
|
|
2055
|
-
nonEmptyBreakpoints.push(breakpoint);
|
|
1947
|
+
close(result) {
|
|
1948
|
+
if (result) {
|
|
1949
|
+
this.result.emit(result);
|
|
2056
1950
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
1951
|
+
super.close(result);
|
|
1952
|
+
}
|
|
1953
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDialogRendererComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
1954
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.4", type: AXPDialogRendererComponent, isStandalone: true, selector: "axp-dialog-renderer", inputs: { config: "config" }, outputs: { result: "result" }, usesInheritance: true, ngImport: i0, template: `
|
|
1955
|
+
<div class="ax-p-4">
|
|
1956
|
+
<axp-layout-renderer
|
|
1957
|
+
[layout]="config.definition"
|
|
1958
|
+
[context]="context()"
|
|
1959
|
+
(contextChange)="handleContextChanged($event)"
|
|
1960
|
+
(contextInitiated)="handleContextInitiated($event)"
|
|
1961
|
+
>
|
|
1962
|
+
</axp-layout-renderer>
|
|
1963
|
+
</div>
|
|
1964
|
+
|
|
1965
|
+
<ax-footer>
|
|
1966
|
+
<ax-prefix>
|
|
1967
|
+
<ng-container *ngTemplateOutlet="footerPrefixActions"></ng-container>
|
|
1968
|
+
</ax-prefix>
|
|
1969
|
+
<ax-suffix>
|
|
1970
|
+
<ng-container *ngTemplateOutlet="footerSuffixActions"></ng-container>
|
|
1971
|
+
</ax-suffix>
|
|
1972
|
+
</ax-footer>
|
|
1973
|
+
|
|
1974
|
+
<!-- Footer Prefix Actions -->
|
|
1975
|
+
<ng-template #footerPrefixActions>
|
|
1976
|
+
@for (action of visibleFooterPrefixActions(); track $index) {
|
|
1977
|
+
<ax-button
|
|
1978
|
+
[disabled]="action.disabled || isFormLoading()"
|
|
1979
|
+
[text]="(action.title | translate | async)!"
|
|
1980
|
+
[look]="'outline'"
|
|
1981
|
+
[color]="action.color"
|
|
1982
|
+
(onClick)="executeAction(action)"
|
|
1983
|
+
>
|
|
1984
|
+
@if (isFormLoading() && action.command?.name != 'cancel') {
|
|
1985
|
+
<ax-loading></ax-loading>
|
|
1986
|
+
}
|
|
1987
|
+
<ax-prefix>
|
|
1988
|
+
<i class="{{ action.icon }}"></i>
|
|
1989
|
+
</ax-prefix>
|
|
1990
|
+
</ax-button>
|
|
1991
|
+
}
|
|
1992
|
+
</ng-template>
|
|
1993
|
+
|
|
1994
|
+
<!-- Footer Suffix Actions -->
|
|
1995
|
+
<ng-template #footerSuffixActions>
|
|
1996
|
+
@for (action of visibleFooterSuffixActions(); track $index) {
|
|
1997
|
+
<ax-button
|
|
1998
|
+
[disabled]="action.disabled || isSubmitting()"
|
|
1999
|
+
[text]="(action.title | translate | async)!"
|
|
2000
|
+
[look]="'solid'"
|
|
2001
|
+
[color]="action.color"
|
|
2002
|
+
(onClick)="executeAction(action)"
|
|
2003
|
+
>
|
|
2004
|
+
@if (action.icon) {
|
|
2005
|
+
<ax-prefix>
|
|
2006
|
+
<ax-icon icon="{{ action.icon }}"></ax-icon>
|
|
2007
|
+
</ax-prefix>
|
|
2008
|
+
}
|
|
2009
|
+
</ax-button>
|
|
2010
|
+
}
|
|
2011
|
+
</ng-template>
|
|
2012
|
+
`, 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
2013
|
}
|
|
2014
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: AXPDialogRendererComponent, decorators: [{
|
|
2015
|
+
type: Component,
|
|
2016
|
+
args: [{
|
|
2017
|
+
selector: 'axp-dialog-renderer',
|
|
2018
|
+
standalone: true,
|
|
2019
|
+
imports: [
|
|
2020
|
+
CommonModule,
|
|
2021
|
+
AXPLayoutRendererComponent,
|
|
2022
|
+
AXButtonModule,
|
|
2023
|
+
AXDecoratorModule,
|
|
2024
|
+
AXLoadingModule,
|
|
2025
|
+
AXTranslationModule,
|
|
2026
|
+
],
|
|
2027
|
+
template: `
|
|
2028
|
+
<div class="ax-p-4">
|
|
2029
|
+
<axp-layout-renderer
|
|
2030
|
+
[layout]="config.definition"
|
|
2031
|
+
[context]="context()"
|
|
2032
|
+
(contextChange)="handleContextChanged($event)"
|
|
2033
|
+
(contextInitiated)="handleContextInitiated($event)"
|
|
2034
|
+
>
|
|
2035
|
+
</axp-layout-renderer>
|
|
2036
|
+
</div>
|
|
2037
|
+
|
|
2038
|
+
<ax-footer>
|
|
2039
|
+
<ax-prefix>
|
|
2040
|
+
<ng-container *ngTemplateOutlet="footerPrefixActions"></ng-container>
|
|
2041
|
+
</ax-prefix>
|
|
2042
|
+
<ax-suffix>
|
|
2043
|
+
<ng-container *ngTemplateOutlet="footerSuffixActions"></ng-container>
|
|
2044
|
+
</ax-suffix>
|
|
2045
|
+
</ax-footer>
|
|
2060
2046
|
|
|
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
|
-
]
|
|
2047
|
+
<!-- Footer Prefix Actions -->
|
|
2048
|
+
<ng-template #footerPrefixActions>
|
|
2049
|
+
@for (action of visibleFooterPrefixActions(); track $index) {
|
|
2050
|
+
<ax-button
|
|
2051
|
+
[disabled]="action.disabled || isFormLoading()"
|
|
2052
|
+
[text]="(action.title | translate | async)!"
|
|
2053
|
+
[look]="'outline'"
|
|
2054
|
+
[color]="action.color"
|
|
2055
|
+
(onClick)="executeAction(action)"
|
|
2056
|
+
>
|
|
2057
|
+
@if (isFormLoading() && action.command?.name != 'cancel') {
|
|
2058
|
+
<ax-loading></ax-loading>
|
|
2059
|
+
}
|
|
2060
|
+
<ax-prefix>
|
|
2061
|
+
<i class="{{ action.icon }}"></i>
|
|
2062
|
+
</ax-prefix>
|
|
2063
|
+
</ax-button>
|
|
2064
|
+
}
|
|
2065
|
+
</ng-template>
|
|
2066
|
+
|
|
2067
|
+
<!-- Footer Suffix Actions -->
|
|
2068
|
+
<ng-template #footerSuffixActions>
|
|
2069
|
+
@for (action of visibleFooterSuffixActions(); track $index) {
|
|
2070
|
+
<ax-button
|
|
2071
|
+
[disabled]="action.disabled || isSubmitting()"
|
|
2072
|
+
[text]="(action.title | translate | async)!"
|
|
2073
|
+
[look]="'solid'"
|
|
2074
|
+
[color]="action.color"
|
|
2075
|
+
(onClick)="executeAction(action)"
|
|
2076
|
+
>
|
|
2077
|
+
@if (action.icon) {
|
|
2078
|
+
<ax-prefix>
|
|
2079
|
+
<ax-icon icon="{{ action.icon }}"></ax-icon>
|
|
2080
|
+
</ax-prefix>
|
|
2081
|
+
}
|
|
2082
|
+
</ax-button>
|
|
2083
|
+
}
|
|
2084
|
+
</ng-template>
|
|
2085
|
+
`,
|
|
2086
|
+
}]
|
|
2087
|
+
}], propDecorators: { config: [{
|
|
2088
|
+
type: Input
|
|
2089
|
+
}], result: [{
|
|
2090
|
+
type: Output
|
|
2091
|
+
}] } });
|
|
2087
2092
|
|
|
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 = {}));
|
|
2093
|
+
var dialogRenderer_component = /*#__PURE__*/Object.freeze({
|
|
2094
|
+
__proto__: null,
|
|
2095
|
+
AXPDialogRendererComponent: AXPDialogRendererComponent
|
|
2096
|
+
});
|
|
2098
2097
|
|
|
2099
2098
|
/**
|
|
2100
2099
|
* Generated bundle index. Do not edit.
|
|
2101
2100
|
*/
|
|
2102
2101
|
|
|
2103
|
-
export {
|
|
2102
|
+
export { AXPDialogRendererComponent, AXPLayoutBuilderService, AXPLayoutConversionService, AXPLayoutRendererComponent, LayoutBuilderModule };
|
|
2104
2103
|
//# sourceMappingURL=acorex-platform-layout-builder.mjs.map
|