@acorex/platform 21.0.0-next.71 → 21.0.0-next.72
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/fesm2022/acorex-platform-auth.mjs +10 -2
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-Bi1RYif5.mjs → acorex-platform-common-common-settings.provider-Ytey9uhY.mjs} +15 -1
- package/fesm2022/acorex-platform-common-common-settings.provider-Ytey9uhY.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +3792 -1679
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +1112 -103
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +53 -170
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components.mjs +70 -46
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +199 -126
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs → acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs} +6 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-B0EkdqvH.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-entity.mjs +341 -418
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +675 -301
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +115 -74
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-BcpRkpJp.mjs.map → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DjpZU6gz.mjs.map} +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs} +2 -2
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-DQtK4lxl.mjs.map → acorex-platform-layout-widgets-tabular-data-view-popup.component-gX-3Kx9I.mjs.map} +1 -1
- package/fesm2022/acorex-platform-layout-widgets.mjs +184 -655
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-B1nsdpTY.mjs +48 -0
- package/fesm2022/acorex-platform-themes-default-error-401.component-B1nsdpTY.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D4UvRe8u.mjs +42 -0
- package/fesm2022/acorex-platform-themes-default-error-404.component-D4UvRe8u.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +76 -32
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-platform-auth.d.ts +2 -0
- package/types/acorex-platform-common.d.ts +891 -259
- package/types/acorex-platform-core.d.ts +284 -40
- package/types/acorex-platform-layout-builder.d.ts +10 -22
- package/types/acorex-platform-layout-components.d.ts +9 -7
- package/types/acorex-platform-layout-entity.d.ts +37 -41
- package/types/acorex-platform-layout-views.d.ts +125 -67
- package/types/acorex-platform-layout-widget-core.d.ts +53 -61
- package/types/acorex-platform-layout-widgets.d.ts +33 -20
- package/types/acorex-platform-themes-default.d.ts +14 -4
- package/fesm2022/acorex-platform-common-common-settings.provider-Bi1RYif5.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-entity-attachments-page.component-D8iQnT-R.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs +0 -31
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs +0 -25
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +0 -1
|
@@ -5,7 +5,7 @@ import { Injectable, inject, input, model, signal, computed, effect, output, vie
|
|
|
5
5
|
import { provideCommandSetups, AXPCommandService } from '@acorex/platform/runtime';
|
|
6
6
|
import { AXPopupService } from '@acorex/components/popup';
|
|
7
7
|
import * as i4 from '@acorex/platform/core';
|
|
8
|
-
import { AXPHookService,
|
|
8
|
+
import { normalizeKeyboardShortcuts, AXPHookService, findOverlayContainerAncestor, getNestedVisibleOverlayPanes, getTopVisibleOverlayContainer, AXPExpressionEvaluatorService, AXPComponentSlotModule, AXPContextStore } from '@acorex/platform/core';
|
|
9
9
|
import * as i1 from '@acorex/platform/layout/widget-core';
|
|
10
10
|
import { AXPWidgetSerializationHelper, AXPWidgetContainerComponent, AXPPageStatus, AXPWidgetCoreModule, AXPWidgetRegistryService } from '@acorex/platform/layout/widget-core';
|
|
11
11
|
import { cloneDeep, isNil, set, isEqual, merge } from 'lodash-es';
|
|
@@ -15,7 +15,6 @@ import { Subject, debounceTime, distinctUntilChanged, startWith } from 'rxjs';
|
|
|
15
15
|
import { AXOverlayService } from '@acorex/cdk/overlay';
|
|
16
16
|
import * as i1$1 from '@acorex/components/button';
|
|
17
17
|
import { AXButtonModule } from '@acorex/components/button';
|
|
18
|
-
import { AXDialogService } from '@acorex/components/dialog';
|
|
19
18
|
import * as i2$1 from '@acorex/components/decorators';
|
|
20
19
|
import { AXDecoratorModule } from '@acorex/components/decorators';
|
|
21
20
|
import * as i3 from '@acorex/components/loading';
|
|
@@ -23,6 +22,7 @@ import { AXLoadingModule } from '@acorex/components/loading';
|
|
|
23
22
|
import { AXBasePageComponent } from '@acorex/components/page';
|
|
24
23
|
import * as i6 from '@acorex/core/translation';
|
|
25
24
|
import { AXTranslationService, AXTranslationModule } from '@acorex/core/translation';
|
|
25
|
+
import { AXPUnsavedChangesConfirmService } from '@acorex/platform/common';
|
|
26
26
|
import { AXP_ENTITY_DEFINITION_CRUD_SERVICE } from '@acorex/platform/domain';
|
|
27
27
|
|
|
28
28
|
//#region ---- Dialog Action Shortcut Utilities ----
|
|
@@ -75,9 +75,9 @@ function resolveDialogActionShortcuts(defaults, overrides) {
|
|
|
75
75
|
if (overrides.length === 0) {
|
|
76
76
|
return undefined;
|
|
77
77
|
}
|
|
78
|
-
return
|
|
78
|
+
return flattenDialogActionShortcutChords([...defaults, ...overrides]);
|
|
79
79
|
}
|
|
80
|
-
return defaults
|
|
80
|
+
return flattenDialogActionShortcutChords(defaults);
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* Applies built-in footer shortcuts when actions are declared without `shortcuts`
|
|
@@ -95,6 +95,11 @@ function resolveConfiguredFooterActionShortcuts(command, explicit) {
|
|
|
95
95
|
}
|
|
96
96
|
return undefined;
|
|
97
97
|
}
|
|
98
|
+
function flattenDialogActionShortcutChords(shortcuts) {
|
|
99
|
+
const chords = normalizeKeyboardShortcuts(shortcuts).flatMap((shortcut) => shortcut.keys);
|
|
100
|
+
const deduped = dedupeDialogActionShortcuts(chords);
|
|
101
|
+
return deduped.length ? deduped : undefined;
|
|
102
|
+
}
|
|
98
103
|
function dedupeDialogActionShortcuts(shortcuts) {
|
|
99
104
|
const seen = new Set();
|
|
100
105
|
const result = [];
|
|
@@ -2555,8 +2560,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2555
2560
|
}]
|
|
2556
2561
|
}] });
|
|
2557
2562
|
|
|
2558
|
-
const OVERLAY_CONTAINER_SELECTOR = '.ax-overlay-container';
|
|
2559
|
-
const OVERLAY_PANE_SELECTOR = '.ax-overlay-pane';
|
|
2560
2563
|
/**
|
|
2561
2564
|
* Returns true when a nested overlay is open and Esc should close it first.
|
|
2562
2565
|
* Returns false when only the dialog shell is on top.
|
|
@@ -2578,52 +2581,6 @@ function hasOpenNestedOverlayFromAcorexService(overlayService, dialogOverlay) {
|
|
|
2578
2581
|
}
|
|
2579
2582
|
return null;
|
|
2580
2583
|
}
|
|
2581
|
-
/**
|
|
2582
|
-
* Returns true when the overlay element is rendered and visible in the viewport.
|
|
2583
|
-
*/
|
|
2584
|
-
function isVisibleOverlayElement(element) {
|
|
2585
|
-
if (!(element instanceof HTMLElement)) {
|
|
2586
|
-
return false;
|
|
2587
|
-
}
|
|
2588
|
-
const style = getComputedStyle(element);
|
|
2589
|
-
if (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0) {
|
|
2590
|
-
return false;
|
|
2591
|
-
}
|
|
2592
|
-
const rect = element.getBoundingClientRect();
|
|
2593
|
-
return rect.width > 0 && rect.height > 0;
|
|
2594
|
-
}
|
|
2595
|
-
/**
|
|
2596
|
-
* Collects visible overlay containers in stacking order (later / higher z-index wins).
|
|
2597
|
-
*/
|
|
2598
|
-
function getVisibleOverlayContainers(document) {
|
|
2599
|
-
return Array.from(document.querySelectorAll(OVERLAY_CONTAINER_SELECTOR))
|
|
2600
|
-
.filter(isVisibleOverlayElement)
|
|
2601
|
-
.sort(compareOverlayStackOrder);
|
|
2602
|
-
}
|
|
2603
|
-
/**
|
|
2604
|
-
* Compares two overlay containers by z-index, then DOM order.
|
|
2605
|
-
*/
|
|
2606
|
-
function compareOverlayStackOrder(a, b) {
|
|
2607
|
-
const za = Number(getComputedStyle(a).zIndex) || 0;
|
|
2608
|
-
const zb = Number(getComputedStyle(b).zIndex) || 0;
|
|
2609
|
-
if (za !== zb) {
|
|
2610
|
-
return za - zb;
|
|
2611
|
-
}
|
|
2612
|
-
const position = a.compareDocumentPosition(b);
|
|
2613
|
-
if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
2614
|
-
return -1;
|
|
2615
|
-
}
|
|
2616
|
-
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
2617
|
-
return 1;
|
|
2618
|
-
}
|
|
2619
|
-
return 0;
|
|
2620
|
-
}
|
|
2621
|
-
/**
|
|
2622
|
-
* Returns visible anchored overlay panes that belong to widget popovers, not the dialog shell.
|
|
2623
|
-
*/
|
|
2624
|
-
function getNestedOverlayPanes(document, dialogOverlay) {
|
|
2625
|
-
return Array.from(document.querySelectorAll(OVERLAY_PANE_SELECTOR)).filter((pane) => isVisibleOverlayElement(pane) && !dialogOverlay?.contains(pane));
|
|
2626
|
-
}
|
|
2627
2584
|
/**
|
|
2628
2585
|
* DOM fallback until {@link AXOverlayService} exposes open-overlay queries.
|
|
2629
2586
|
*
|
|
@@ -2631,15 +2588,14 @@ function getNestedOverlayPanes(document, dialogOverlay) {
|
|
|
2631
2588
|
* Widget popovers (select, datetime, dropdown) use anchored containers with `.ax-overlay-pane`.
|
|
2632
2589
|
*/
|
|
2633
2590
|
function shouldDeferEscapeToNestedOverlayFromDom(document, dialogHost) {
|
|
2634
|
-
const dialogOverlay = dialogHost
|
|
2635
|
-
if (
|
|
2591
|
+
const dialogOverlay = findOverlayContainerAncestor(dialogHost);
|
|
2592
|
+
if (getNestedVisibleOverlayPanes(document, dialogOverlay).length > 0) {
|
|
2636
2593
|
return true;
|
|
2637
2594
|
}
|
|
2638
|
-
const
|
|
2639
|
-
if (!
|
|
2595
|
+
const topContainer = getTopVisibleOverlayContainer(document);
|
|
2596
|
+
if (!topContainer) {
|
|
2640
2597
|
return false;
|
|
2641
2598
|
}
|
|
2642
|
-
const topContainer = visibleContainers[visibleContainers.length - 1];
|
|
2643
2599
|
if (!dialogOverlay) {
|
|
2644
2600
|
return topContainer.contains(dialogHost) === false;
|
|
2645
2601
|
}
|
|
@@ -2650,7 +2606,7 @@ function shouldDeferEscapeToNestedOverlayFromDom(document, dialogHost) {
|
|
|
2650
2606
|
* should not run on the parent dialog.
|
|
2651
2607
|
*/
|
|
2652
2608
|
function shouldDeferDialogShortcutsToNestedOverlay(document, dialogHost, overlayService) {
|
|
2653
|
-
const dialogOverlay = dialogHost
|
|
2609
|
+
const dialogOverlay = findOverlayContainerAncestor(dialogHost);
|
|
2654
2610
|
if (overlayService) {
|
|
2655
2611
|
const fromService = hasOpenNestedOverlayFromAcorexService(overlayService, dialogOverlay);
|
|
2656
2612
|
if (fromService !== null) {
|
|
@@ -2687,10 +2643,6 @@ function shouldRouteOnActionCancelThroughDismissGate(confirmCloseWhenDirtyEnable
|
|
|
2687
2643
|
return confirmCloseWhenDirtyEnabled === true;
|
|
2688
2644
|
}
|
|
2689
2645
|
|
|
2690
|
-
/** Idle period after the last context change before capturing the clean baseline. */
|
|
2691
|
-
const DIALOG_DIRTY_BASELINE_IDLE_MS = 500;
|
|
2692
|
-
/** Hard fallback when idle detection never settles. */
|
|
2693
|
-
const DIALOG_DIRTY_BASELINE_FALLBACK_DELAY_MS = 2000;
|
|
2694
2646
|
/** Debounce after widget count stabilizes before re-evaluating footer actions. */
|
|
2695
2647
|
const DIALOG_WIDGET_COUNT_STABLE_DELAY_MS = 350;
|
|
2696
2648
|
class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
@@ -2700,17 +2652,17 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2700
2652
|
this.expressionEvaluator = inject(AXPExpressionEvaluatorService);
|
|
2701
2653
|
this.commandService = inject(AXPCommandService);
|
|
2702
2654
|
this.hookService = inject(AXPHookService, { optional: true });
|
|
2703
|
-
this.
|
|
2655
|
+
this.unsavedChangesConfirm = inject(AXPUnsavedChangesConfirmService);
|
|
2704
2656
|
this.overlayService = inject(AXOverlayService);
|
|
2705
2657
|
this.translationService = inject(AXTranslationService);
|
|
2706
2658
|
this.document = inject(DOCUMENT);
|
|
2707
2659
|
this.host = inject((ElementRef));
|
|
2708
2660
|
/** Ensures `show()` resolves once when the dialog closes (footer action or header close). */
|
|
2709
2661
|
this.callbackInvoked = false;
|
|
2710
|
-
/** True after the post-init baseline snapshot has been captured. */
|
|
2711
|
-
this.dirtyBaselineCaptured = false;
|
|
2712
2662
|
/** Skips dirty confirmation on the next {@link onClosing} (successful submit / programmatic close). */
|
|
2713
2663
|
this.skipNextOnClosingDirtyCheck = false;
|
|
2664
|
+
/** Blocks re-entrant {@link onClosing} while the first close gate is still resolving. */
|
|
2665
|
+
this.closeGateInProgress = false;
|
|
2714
2666
|
this.destroyRef = inject(DestroyRef);
|
|
2715
2667
|
this.context = signal({}, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
|
|
2716
2668
|
// This will be set by the popup service automatically - same as dynamic-dialog
|
|
@@ -2733,7 +2685,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2733
2685
|
return;
|
|
2734
2686
|
}
|
|
2735
2687
|
// Unsaved-changes confirm is modal — parent footer shortcuts must not run underneath it.
|
|
2736
|
-
if (this.
|
|
2688
|
+
if (this.unsavedChangesConfirm.isConfirmPending()) {
|
|
2737
2689
|
return;
|
|
2738
2690
|
}
|
|
2739
2691
|
if (shouldDeferDialogShortcutsToNestedOverlay(this.document, this.host.nativeElement, this.overlayService)) {
|
|
@@ -2784,36 +2736,15 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2784
2736
|
this.aggregateAndEvaluateActions();
|
|
2785
2737
|
}, DIALOG_WIDGET_COUNT_STABLE_DELAY_MS);
|
|
2786
2738
|
}, ...(ngDevMode ? [{ debugName: "#widgetActionsEffect" }] : /* istanbul ignore next */ []));
|
|
2787
|
-
this.#dirtyBaselineEffect = effect(() => {
|
|
2788
|
-
if (this.dirtyBaselineCaptured) {
|
|
2789
|
-
return;
|
|
2790
|
-
}
|
|
2791
|
-
const store = this.getWidgetContextStore();
|
|
2792
|
-
if (!store) {
|
|
2793
|
-
return;
|
|
2794
|
-
}
|
|
2795
|
-
store.data();
|
|
2796
|
-
this.widgetCoreService?.registeredWidgetsCount();
|
|
2797
|
-
this.scheduleDirtyBaselineCapture();
|
|
2798
|
-
}, ...(ngDevMode ? [{ debugName: "#dirtyBaselineEffect" }] : /* istanbul ignore next */ []));
|
|
2799
2739
|
}
|
|
2800
2740
|
//#endregion
|
|
2801
2741
|
//#region ---- Lifecycle ----
|
|
2802
2742
|
ngOnInit() {
|
|
2803
2743
|
const initialContext = this.config?.context || {};
|
|
2804
2744
|
this.context.set(initialContext);
|
|
2805
|
-
this.dirtyBaselineFallbackTimer = setTimeout(() => {
|
|
2806
|
-
this.captureDirtyBaselineIfNeeded();
|
|
2807
|
-
}, DIALOG_DIRTY_BASELINE_FALLBACK_DELAY_MS);
|
|
2808
2745
|
this.document.addEventListener('keydown', this.onDialogShortcutCapture, true);
|
|
2809
2746
|
this.destroyRef.onDestroy(() => {
|
|
2810
2747
|
this.document.removeEventListener('keydown', this.onDialogShortcutCapture, true);
|
|
2811
|
-
if (this.dirtyBaselineIdleTimer) {
|
|
2812
|
-
clearTimeout(this.dirtyBaselineIdleTimer);
|
|
2813
|
-
}
|
|
2814
|
-
if (this.dirtyBaselineFallbackTimer) {
|
|
2815
|
-
clearTimeout(this.dirtyBaselineFallbackTimer);
|
|
2816
|
-
}
|
|
2817
2748
|
});
|
|
2818
2749
|
void this.invokeLayoutContextChangedHooks();
|
|
2819
2750
|
}
|
|
@@ -2824,25 +2755,31 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2824
2755
|
* This is the only place that prompts for unsaved changes.
|
|
2825
2756
|
*/
|
|
2826
2757
|
async onClosing(e) {
|
|
2827
|
-
if (this.
|
|
2758
|
+
if (this.unsavedChangesConfirm.isConfirmPending() || this.closeGateInProgress) {
|
|
2828
2759
|
e.cancel = true;
|
|
2829
2760
|
return;
|
|
2830
2761
|
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
this.
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2762
|
+
this.closeGateInProgress = true;
|
|
2763
|
+
try {
|
|
2764
|
+
if (this.skipNextOnClosingDirtyCheck) {
|
|
2765
|
+
this.skipNextOnClosingDirtyCheck = false;
|
|
2766
|
+
this.completeDismissResolve();
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
if (!this.config?.confirmCloseWhenDirty?.enabled) {
|
|
2770
|
+
this.completeDismissResolve();
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
if (!(await this.confirmDismissIfDirty())) {
|
|
2774
|
+
e.cancel = true;
|
|
2775
|
+
this.pendingDismissResolvePayload = undefined;
|
|
2776
|
+
return;
|
|
2777
|
+
}
|
|
2837
2778
|
this.completeDismissResolve();
|
|
2838
|
-
return;
|
|
2839
2779
|
}
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
this.pendingDismissResolvePayload = undefined;
|
|
2843
|
-
return;
|
|
2780
|
+
finally {
|
|
2781
|
+
this.closeGateInProgress = false;
|
|
2844
2782
|
}
|
|
2845
|
-
this.completeDismissResolve();
|
|
2846
2783
|
}
|
|
2847
2784
|
/**
|
|
2848
2785
|
* Footer cancel and other in-app dismiss actions. Routes through `super.close()` so the
|
|
@@ -2866,50 +2803,10 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2866
2803
|
}
|
|
2867
2804
|
//#endregion
|
|
2868
2805
|
//#region ---- Dirty State ----
|
|
2869
|
-
|
|
2870
|
-
return this.layoutRenderer()?.getContainer()
|
|
2871
|
-
}
|
|
2872
|
-
scheduleDirtyBaselineCapture() {
|
|
2873
|
-
if (this.dirtyBaselineCaptured) {
|
|
2874
|
-
return;
|
|
2875
|
-
}
|
|
2876
|
-
if (this.dirtyBaselineIdleTimer) {
|
|
2877
|
-
clearTimeout(this.dirtyBaselineIdleTimer);
|
|
2878
|
-
}
|
|
2879
|
-
this.dirtyBaselineIdleTimer = setTimeout(() => {
|
|
2880
|
-
this.captureDirtyBaselineIfNeeded();
|
|
2881
|
-
}, DIALOG_DIRTY_BASELINE_IDLE_MS);
|
|
2882
|
-
}
|
|
2883
|
-
/**
|
|
2884
|
-
* Captures a dialog-local baseline once after widget init/normalization goes idle.
|
|
2885
|
-
*/
|
|
2886
|
-
captureDirtyBaselineIfNeeded() {
|
|
2887
|
-
if (this.dirtyBaselineCaptured) {
|
|
2888
|
-
return;
|
|
2889
|
-
}
|
|
2890
|
-
const store = this.getWidgetContextStore();
|
|
2891
|
-
if (!store) {
|
|
2892
|
-
return;
|
|
2893
|
-
}
|
|
2894
|
-
const widgetCount = this.widgetCoreService?.registeredWidgetsCount() ?? 0;
|
|
2895
|
-
if (widgetCount === 0) {
|
|
2896
|
-
return;
|
|
2897
|
-
}
|
|
2898
|
-
const snapshot = store.data();
|
|
2899
|
-
this.dirtyBaseline = captureFormContextBaseline(snapshot);
|
|
2900
|
-
store.commitBaseline();
|
|
2901
|
-
this.dirtyBaselineCaptured = true;
|
|
2902
|
-
if (this.dirtyBaselineIdleTimer) {
|
|
2903
|
-
clearTimeout(this.dirtyBaselineIdleTimer);
|
|
2904
|
-
this.dirtyBaselineIdleTimer = undefined;
|
|
2905
|
-
}
|
|
2906
|
-
if (this.dirtyBaselineFallbackTimer) {
|
|
2907
|
-
clearTimeout(this.dirtyBaselineFallbackTimer);
|
|
2908
|
-
this.dirtyBaselineFallbackTimer = undefined;
|
|
2909
|
-
}
|
|
2806
|
+
getWidgetContainer() {
|
|
2807
|
+
return this.layoutRenderer()?.getContainer();
|
|
2910
2808
|
}
|
|
2911
2809
|
#widgetActionsEffect;
|
|
2912
|
-
#dirtyBaselineEffect;
|
|
2913
2810
|
//#endregion
|
|
2914
2811
|
handleContextChanged(event) {
|
|
2915
2812
|
this.context.set(event);
|
|
@@ -2929,7 +2826,7 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
2929
2826
|
const payload = {
|
|
2930
2827
|
sessionKey: this.contextChangedHooksSessionKey,
|
|
2931
2828
|
getContext: () => {
|
|
2932
|
-
const store = this.
|
|
2829
|
+
const store = this.getWidgetContainer()?.contextService;
|
|
2933
2830
|
return (store?.data() ?? this.context() ?? {});
|
|
2934
2831
|
},
|
|
2935
2832
|
metadata: meta,
|
|
@@ -3037,43 +2934,29 @@ class AXPDialogRendererComponent extends AXBasePageComponent {
|
|
|
3037
2934
|
}
|
|
3038
2935
|
isDialogDirty() {
|
|
3039
2936
|
const confirmOptions = this.config?.confirmCloseWhenDirty;
|
|
3040
|
-
if (!confirmOptions?.enabled
|
|
2937
|
+
if (!confirmOptions?.enabled) {
|
|
3041
2938
|
return false;
|
|
3042
2939
|
}
|
|
3043
|
-
const
|
|
3044
|
-
if (!
|
|
2940
|
+
const container = this.getWidgetContainer();
|
|
2941
|
+
if (!container?.isSavedCommitted()) {
|
|
3045
2942
|
return false;
|
|
3046
2943
|
}
|
|
3047
|
-
const
|
|
3048
|
-
const baseline = this.dirtyBaseline ?? store.initial();
|
|
2944
|
+
const store = container.contextService;
|
|
3049
2945
|
if (typeof confirmOptions.isDirty === 'function') {
|
|
3050
|
-
return confirmOptions.isDirty(
|
|
2946
|
+
return confirmOptions.isDirty(store.data(), store.saved());
|
|
3051
2947
|
}
|
|
3052
|
-
return
|
|
3053
|
-
(this.widgetCoreService?.hasDirtyWidgets() ?? false) ||
|
|
3054
|
-
isFormContextDirty(current, baseline));
|
|
2948
|
+
return container.isFormDirty();
|
|
3055
2949
|
}
|
|
3056
|
-
|
|
3057
|
-
if (this.dismissConfirmPromise) {
|
|
3058
|
-
return this.dismissConfirmPromise;
|
|
3059
|
-
}
|
|
2950
|
+
confirmDismissIfDirty() {
|
|
3060
2951
|
const confirmOptions = this.config?.confirmCloseWhenDirty;
|
|
3061
2952
|
if (!confirmOptions?.enabled || !this.isDialogDirty()) {
|
|
3062
|
-
return true;
|
|
3063
|
-
}
|
|
3064
|
-
this.dismissConfirmPromise = this.promptUnsavedChangesConfirm(confirmOptions);
|
|
3065
|
-
try {
|
|
3066
|
-
return await this.dismissConfirmPromise;
|
|
2953
|
+
return Promise.resolve(true);
|
|
3067
2954
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
const title = await this.translationService.translateAsync(confirmOptions.title ?? '@general:messages.unsaved-changes.title');
|
|
3074
|
-
const message = await this.translationService.translateAsync(confirmOptions.message ?? '@general:messages.unsaved-changes.message');
|
|
3075
|
-
const dialogResult = await this.dialogService.confirm(title, message, 'warning', 'horizontal', false, 'cancel');
|
|
3076
|
-
return dialogResult.result === true;
|
|
2955
|
+
return this.unsavedChangesConfirm.confirmIfDirty(true, {
|
|
2956
|
+
enabled: confirmOptions.enabled,
|
|
2957
|
+
title: confirmOptions.title,
|
|
2958
|
+
message: confirmOptions.message,
|
|
2959
|
+
});
|
|
3077
2960
|
}
|
|
3078
2961
|
/** Whether the layout form should be validated before running this footer command. */
|
|
3079
2962
|
shouldValidateBeforeAction(cmd) {
|