@acorex/platform 21.0.0-next.3 → 21.0.0-next.34
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 +295 -45
- package/fesm2022/acorex-platform-auth.mjs.map +1 -1
- package/fesm2022/{acorex-platform-common-common-settings.provider-zhqNP3xb.mjs → acorex-platform-common-common-settings.provider-G9XcXXOG.mjs} +60 -4
- package/fesm2022/acorex-platform-common-common-settings.provider-G9XcXXOG.mjs.map +1 -0
- package/fesm2022/acorex-platform-common.mjs +960 -319
- package/fesm2022/acorex-platform-common.mjs.map +1 -1
- package/fesm2022/acorex-platform-core.mjs +1352 -832
- package/fesm2022/acorex-platform-core.mjs.map +1 -1
- package/fesm2022/acorex-platform-domain.mjs +554 -826
- package/fesm2022/acorex-platform-domain.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-builder.mjs +530 -154
- package/fesm2022/acorex-platform-layout-builder.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs +121 -0
- package/fesm2022/acorex-platform-layout-components-binding-expression-editor-popup.component-CXEdvDTf.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-components.mjs +5969 -2347
- package/fesm2022/acorex-platform-layout-components.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-designer.mjs +169 -154
- package/fesm2022/acorex-platform-layout-designer.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-entity.mjs +15380 -9274
- package/fesm2022/acorex-platform-layout-entity.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-views.mjs +393 -110
- package/fesm2022/acorex-platform-layout-views.mjs.map +1 -1
- package/fesm2022/acorex-platform-layout-widget-core.mjs +511 -450
- package/fesm2022/acorex-platform-layout-widget-core.mjs.map +1 -1
- package/fesm2022/{acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs → acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs} +10 -10
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-Dy7jF-oD.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs → acorex-platform-layout-widgets-file-list-popup.component-9uCkMxcc.mjs} +39 -16
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-9uCkMxcc.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs → acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs} +6 -7
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-C_EPAvCU.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs → acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs} +12 -12
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-D10yO28c.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BGQqY5Mw.mjs +111 -0
- package/fesm2022/acorex-platform-layout-widgets-repeater-widget-column.component-BGQqY5Mw.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs → acorex-platform-layout-widgets-tabular-data-edit-popup.component-DmzNTYiS.mjs} +6 -6
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-DmzNTYiS.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs → acorex-platform-layout-widgets-tabular-data-view-popup.component-BNG_588B.mjs} +5 -5
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-BNG_588B.mjs.map +1 -0
- package/fesm2022/{acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs → acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs} +6 -6
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Vo4fWHtX.mjs.map +1 -0
- package/fesm2022/acorex-platform-layout-widgets.mjs +7865 -4026
- package/fesm2022/acorex-platform-layout-widgets.mjs.map +1 -1
- package/fesm2022/acorex-platform-native.mjs +8 -7
- package/fesm2022/acorex-platform-native.mjs.map +1 -1
- package/fesm2022/acorex-platform-runtime.mjs +220 -169
- package/fesm2022/acorex-platform-runtime.mjs.map +1 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs +160 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-Cvvr4HnL.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs +120 -0
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-TYoLN1Jq.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs → acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs} +18 -25
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-C2z5Lq9y.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-error-401.component-cfREo88K.mjs → acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs} +4 -4
- package/fesm2022/acorex-platform-themes-default-error-401.component-C7EYJzSr.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs → acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs} +4 -4
- package/fesm2022/acorex-platform-themes-default-error-404.component-7MVLMwIa.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs +19 -0
- package/fesm2022/acorex-platform-themes-default-error-offline.component-DR6G8gPC.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-default.mjs +1717 -66
- package/fesm2022/acorex-platform-themes-default.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs → acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs} +6 -6
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-CqkWJYdv.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs → acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs} +6 -6
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-BOTuLdWN.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared-settings.provider-DSs1o1M6.mjs.map +1 -1
- package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs → acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs} +11 -11
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-CHfrTtol.mjs.map +1 -0
- package/fesm2022/{acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs → acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs} +9 -9
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-BSmvnUVq.mjs.map +1 -0
- package/fesm2022/acorex-platform-themes-shared.mjs +563 -561
- package/fesm2022/acorex-platform-themes-shared.mjs.map +1 -1
- package/fesm2022/acorex-platform-workflow.mjs +1735 -1750
- package/fesm2022/acorex-platform-workflow.mjs.map +1 -1
- package/fesm2022/acorex-platform.mjs.map +1 -1
- package/package.json +31 -31
- package/{auth/index.d.ts → types/acorex-platform-auth.d.ts} +247 -10
- package/{common/index.d.ts → types/acorex-platform-common.d.ts} +492 -31
- package/{core/index.d.ts → types/acorex-platform-core.d.ts} +606 -392
- package/{domain/index.d.ts → types/acorex-platform-domain.d.ts} +719 -413
- package/{layout/builder/index.d.ts → types/acorex-platform-layout-builder.d.ts} +128 -56
- package/types/acorex-platform-layout-components.d.ts +2927 -0
- package/{layout/designer/index.d.ts → types/acorex-platform-layout-designer.d.ts} +9 -3
- package/{layout/entity/index.d.ts → types/acorex-platform-layout-entity.d.ts} +1133 -237
- package/{layout/views/index.d.ts → types/acorex-platform-layout-views.d.ts} +90 -31
- package/{layout/widget-core/index.d.ts → types/acorex-platform-layout-widget-core.d.ts} +206 -102
- package/{layout/widgets/index.d.ts → types/acorex-platform-layout-widgets.d.ts} +942 -137
- package/{native/index.d.ts → types/acorex-platform-native.d.ts} +0 -7
- package/{runtime/index.d.ts → types/acorex-platform-runtime.d.ts} +237 -74
- package/{themes/default/index.d.ts → types/acorex-platform-themes-default.d.ts} +113 -5
- package/{themes/shared/index.d.ts → types/acorex-platform-themes-shared.d.ts} +1 -1
- package/types/acorex-platform-workflow.d.ts +1806 -0
- package/fesm2022/acorex-platform-common-common-settings.provider-zhqNP3xb.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-button-widget-designer.component-C3VoBb_b.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-file-list-popup.component-CxrsI6Hn.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-image-preview.popup-V31OpYah.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-page-widget-designer.component-BtZMBxYp.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-edit-popup.component-Ck7-wpT2.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-tabular-data-view-popup.component-y8vjUiVs.mjs.map +0 -1
- package/fesm2022/acorex-platform-layout-widgets-text-block-widget-designer.component-Df1BFkSa.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs +0 -157
- package/fesm2022/acorex-platform-themes-default-entity-master-create-view.component-VIGuU5M4.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs +0 -1542
- package/fesm2022/acorex-platform-themes-default-entity-master-list-view.component-DyDa_hyd.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs +0 -101
- package/fesm2022/acorex-platform-themes-default-entity-master-modify-view.component-Ua3ZA5hk.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-entity-master-single-view.component-eMBby9k4.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-401.component-cfREo88K.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-404.component-CdCV5ZoA.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs +0 -19
- package/fesm2022/acorex-platform-themes-default-error-offline.component-E7SzBcAt.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-column.component-C0EpfU2k.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-icon-chooser-view.component-9W52W6Nu.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-column.component-DTnfRy5f.mjs.map +0 -1
- package/fesm2022/acorex-platform-themes-shared-theme-color-chooser-view.component-DY0JtT1v.mjs.map +0 -1
- package/layout/components/index.d.ts +0 -1669
- package/workflow/index.d.ts +0 -2443
- /package/{index.d.ts → types/acorex-platform.d.ts} +0 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable,
|
|
2
|
+
import { InjectionToken, inject, Injectable, Directive, computed, Injector, ChangeDetectionStrategy, Component, input, ElementRef, ViewContainerRef, signal, effect, runInInjectionContext, Optional, Inject, NgModule, EventEmitter, HostListener, Output, provideAppInitializer, ChangeDetectorRef, Pipe } from '@angular/core';
|
|
3
|
+
import { get, isPlainObject, set, isNil, isEmpty, isArray, merge, isObjectLike, transform, isEqual, differenceWith, union, cloneDeep, has, sortBy, isUndefined, endsWith, startsWith, includes, lte, gte, lt, gt, orderBy } from 'lodash-es';
|
|
3
4
|
import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
5
|
+
import * as i1 from '@acorex/components/skeleton';
|
|
6
|
+
import { AXSkeletonModule } from '@acorex/components/skeleton';
|
|
7
|
+
import { Subject, merge as merge$1, of, interval, fromEvent } from 'rxjs';
|
|
8
|
+
import { AXDataSource } from '@acorex/cdk/common';
|
|
9
|
+
import { AXTranslationService } from '@acorex/core/translation';
|
|
10
|
+
import { map, distinctUntilChanged, startWith, debounceTime } from 'rxjs/operators';
|
|
6
11
|
import { AXCalendarService } from '@acorex/core/date-time';
|
|
7
|
-
import { startWith, map, debounceTime } from 'rxjs/operators';
|
|
8
12
|
|
|
9
13
|
const AXP_ACTIVITY_LOG_PROVIDER = new InjectionToken('AXP_ACTIVITY_LOGS_PROVIDER');
|
|
10
14
|
class AXPActivityLogService {
|
|
@@ -17,10 +21,10 @@ class AXPActivityLogService {
|
|
|
17
21
|
async getHistoryByIds(refId, refType, ids) {
|
|
18
22
|
return (await Promise.all(this.providers?.map((p) => p.getHistoryByIds(refId, refType, ids)) ?? [])).flat();
|
|
19
23
|
}
|
|
20
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
21
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
24
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityLogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
25
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityLogService, providedIn: 'root' }); }
|
|
22
26
|
}
|
|
23
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
27
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPActivityLogService, decorators: [{
|
|
24
28
|
type: Injectable,
|
|
25
29
|
args: [{ providedIn: 'root' }]
|
|
26
30
|
}] });
|
|
@@ -170,10 +174,10 @@ class AXPColorPaletteService {
|
|
|
170
174
|
const uniquePalettes = allPalettes.filter((palette, index, self) => index === self.findIndex((p) => p.name === palette.name));
|
|
171
175
|
this.cache = uniquePalettes;
|
|
172
176
|
}
|
|
173
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
174
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
177
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPColorPaletteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
178
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPColorPaletteService, providedIn: 'root' }); }
|
|
175
179
|
}
|
|
176
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPColorPaletteService, decorators: [{
|
|
177
181
|
type: Injectable,
|
|
178
182
|
args: [{
|
|
179
183
|
providedIn: 'root',
|
|
@@ -288,13 +292,241 @@ class AXPDefaultColorPalettesProvider extends AXPColorPaletteProvider {
|
|
|
288
292
|
},
|
|
289
293
|
];
|
|
290
294
|
}
|
|
291
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
292
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
295
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDefaultColorPalettesProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
296
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDefaultColorPalettesProvider }); }
|
|
293
297
|
}
|
|
294
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
298
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDefaultColorPalettesProvider, decorators: [{
|
|
295
299
|
type: Injectable
|
|
296
300
|
}] });
|
|
297
301
|
|
|
302
|
+
//#region ---- Column Width Provider ----
|
|
303
|
+
/**
|
|
304
|
+
* Injection token for column width providers
|
|
305
|
+
* Use this to register multiple column width providers with multi: true
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```typescript
|
|
309
|
+
* providers: [
|
|
310
|
+
* {
|
|
311
|
+
* provide: AXP_COLUMN_WIDTH_PROVIDER,
|
|
312
|
+
* useValue: {
|
|
313
|
+
* matchers: [
|
|
314
|
+
* { name: 'title', width: '300px', priority: 10 },
|
|
315
|
+
* { widgetType: /text-box/i, width: '200px' }
|
|
316
|
+
* ],
|
|
317
|
+
* priority: 150
|
|
318
|
+
* },
|
|
319
|
+
* multi: true
|
|
320
|
+
* }
|
|
321
|
+
* ]
|
|
322
|
+
* ```
|
|
323
|
+
*/
|
|
324
|
+
const AXP_COLUMN_WIDTH_PROVIDER = new InjectionToken('AXP_COLUMN_WIDTH_PROVIDER');
|
|
325
|
+
//#endregion
|
|
326
|
+
|
|
327
|
+
//#region ---- Column Width Service ----
|
|
328
|
+
/**
|
|
329
|
+
* Service for resolving column widths based on registered providers
|
|
330
|
+
* Supports matching by column name (priority) and widget type (fallback)
|
|
331
|
+
* Uses multi-provider pattern for extensibility
|
|
332
|
+
*/
|
|
333
|
+
class AXPColumnWidthService {
|
|
334
|
+
constructor() {
|
|
335
|
+
//#region ---- Services & Dependencies ----
|
|
336
|
+
this.providers = inject(AXP_COLUMN_WIDTH_PROVIDER, {
|
|
337
|
+
optional: true,
|
|
338
|
+
}) ?? [];
|
|
339
|
+
}
|
|
340
|
+
//#region ---- Public Methods ----
|
|
341
|
+
/**
|
|
342
|
+
* Resolve width for a column based on registered providers
|
|
343
|
+
* Only returns a width if column doesn't already have one set
|
|
344
|
+
*
|
|
345
|
+
* @param column Column to resolve width for
|
|
346
|
+
* @returns Resolved width string (normalized) or undefined if no match or column already has width
|
|
347
|
+
*/
|
|
348
|
+
resolveWidth(column) {
|
|
349
|
+
// If column already has a width set, don't override
|
|
350
|
+
const existingWidth = column.width || column.options?.width;
|
|
351
|
+
if (existingWidth) {
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
// Get widget type from column (support both widget.type and showAs.type)
|
|
355
|
+
const widgetType = column.widget?.type || column.showAs?.type;
|
|
356
|
+
// Collect all matchers from all providers
|
|
357
|
+
const allMatchers = this.collectMatchers();
|
|
358
|
+
// Try name-based matches first (higher priority)
|
|
359
|
+
const nameMatch = this.findNameMatch(column.name, allMatchers);
|
|
360
|
+
if (nameMatch) {
|
|
361
|
+
return this.normalizeWidth(nameMatch.width);
|
|
362
|
+
}
|
|
363
|
+
// Fallback to widget-type matches (case-insensitive)
|
|
364
|
+
if (widgetType) {
|
|
365
|
+
const widgetMatch = this.findWidgetTypeMatch(widgetType, allMatchers);
|
|
366
|
+
if (widgetMatch) {
|
|
367
|
+
return this.normalizeWidth(widgetMatch.width);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return undefined;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Apply resolved width to a column (mutates the column)
|
|
374
|
+
* Only applies if column doesn't already have a width
|
|
375
|
+
*
|
|
376
|
+
* @param column Column to apply width to
|
|
377
|
+
* @returns true if width was applied, false if column already had width or no match found
|
|
378
|
+
*/
|
|
379
|
+
applyWidth(column) {
|
|
380
|
+
const width = this.resolveWidth(column);
|
|
381
|
+
if (!width) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
// Apply to the appropriate property
|
|
385
|
+
if (column.options) {
|
|
386
|
+
column.options.width = width;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
column.width = width;
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region ---- Private Methods ----
|
|
395
|
+
/**
|
|
396
|
+
* Collect all matchers from all providers, sorted by provider priority and matcher priority
|
|
397
|
+
*/
|
|
398
|
+
collectMatchers() {
|
|
399
|
+
const allMatchers = [];
|
|
400
|
+
for (const provider of this.providers) {
|
|
401
|
+
const providerPriority = provider.priority ?? 100;
|
|
402
|
+
for (const matcher of provider.matchers) {
|
|
403
|
+
allMatchers.push({
|
|
404
|
+
matcher,
|
|
405
|
+
providerPriority,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
// Sort by provider priority (descending), then by matcher priority (descending)
|
|
410
|
+
allMatchers.sort((a, b) => {
|
|
411
|
+
if (a.providerPriority !== b.providerPriority) {
|
|
412
|
+
return b.providerPriority - a.providerPriority; // Higher priority first
|
|
413
|
+
}
|
|
414
|
+
const priorityA = a.matcher.priority ?? 0;
|
|
415
|
+
const priorityB = b.matcher.priority ?? 0;
|
|
416
|
+
return priorityB - priorityA; // Higher priority first
|
|
417
|
+
});
|
|
418
|
+
return allMatchers;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Find first matching matcher by column name
|
|
422
|
+
* Name matches take precedence over widget type matches
|
|
423
|
+
*/
|
|
424
|
+
findNameMatch(columnName, allMatchers) {
|
|
425
|
+
for (const { matcher } of allMatchers) {
|
|
426
|
+
if (!matcher.name) {
|
|
427
|
+
continue; // Skip if no name matcher
|
|
428
|
+
}
|
|
429
|
+
if (typeof matcher.name === 'string') {
|
|
430
|
+
// Exact string match (case-sensitive for names)
|
|
431
|
+
if (matcher.name === columnName) {
|
|
432
|
+
return matcher;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else if (matcher.name instanceof RegExp) {
|
|
436
|
+
// RegExp match
|
|
437
|
+
if (matcher.name.test(columnName)) {
|
|
438
|
+
return matcher;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return undefined;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Find first matching matcher by widget type (case-insensitive)
|
|
446
|
+
*/
|
|
447
|
+
findWidgetTypeMatch(widgetType, allMatchers) {
|
|
448
|
+
const widgetTypeLower = widgetType.toLowerCase();
|
|
449
|
+
for (const { matcher } of allMatchers) {
|
|
450
|
+
if (!matcher.widgetType) {
|
|
451
|
+
continue; // Skip if no widget type matcher
|
|
452
|
+
}
|
|
453
|
+
if (typeof matcher.widgetType === 'string') {
|
|
454
|
+
// Case-insensitive string match
|
|
455
|
+
if (matcher.widgetType.toLowerCase() === widgetTypeLower) {
|
|
456
|
+
return matcher;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
else if (matcher.widgetType instanceof RegExp) {
|
|
460
|
+
// RegExp match (should already be case-insensitive if needed, but we'll test case-insensitively)
|
|
461
|
+
// Create a new regex with case-insensitive flag if not already present
|
|
462
|
+
let regex = matcher.widgetType;
|
|
463
|
+
if (!regex.flags.includes('i')) {
|
|
464
|
+
regex = new RegExp(regex.source, regex.flags + 'i');
|
|
465
|
+
}
|
|
466
|
+
if (regex.test(widgetType)) {
|
|
467
|
+
return matcher;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return undefined;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Normalize width value to string format
|
|
475
|
+
* Numbers are converted to pixels (e.g., 150 -> '150px')
|
|
476
|
+
* Strings are preserved as-is (supports any CSS unit)
|
|
477
|
+
*/
|
|
478
|
+
normalizeWidth(width) {
|
|
479
|
+
if (typeof width === 'number') {
|
|
480
|
+
return `${width}px`;
|
|
481
|
+
}
|
|
482
|
+
return width;
|
|
483
|
+
}
|
|
484
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPColumnWidthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
485
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPColumnWidthService, providedIn: 'root' }); }
|
|
486
|
+
}
|
|
487
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPColumnWidthService, decorators: [{
|
|
488
|
+
type: Injectable,
|
|
489
|
+
args: [{
|
|
490
|
+
providedIn: 'root',
|
|
491
|
+
}]
|
|
492
|
+
}] });
|
|
493
|
+
|
|
494
|
+
//#region ---- Column Width Types ----
|
|
495
|
+
//#endregion
|
|
496
|
+
|
|
497
|
+
//#region ---- Default Column Width Provider ----
|
|
498
|
+
/**
|
|
499
|
+
* Default column width configuration
|
|
500
|
+
* Migrated from DEFAULT_COLUMN_WIDTHS in column-width.middleware.ts
|
|
501
|
+
* Provides sensible defaults for common column names
|
|
502
|
+
*/
|
|
503
|
+
const defaultColumnWidthProvider = {
|
|
504
|
+
priority: 100,
|
|
505
|
+
matchers: [
|
|
506
|
+
// Priority: name-based matches (higher priority = more specific)
|
|
507
|
+
{ name: 'code', width: '150px', priority: 10 },
|
|
508
|
+
{ name: 'name', width: '250px', priority: 10 },
|
|
509
|
+
{ name: 'title', width: '250px', priority: 10 },
|
|
510
|
+
{ name: 'description', width: '350px', priority: 10 },
|
|
511
|
+
{ name: 'note', width: '350px', priority: 10 },
|
|
512
|
+
{ name: 'notes', width: '350px', priority: 10 },
|
|
513
|
+
{ name: 'content', width: '500px', priority: 10 },
|
|
514
|
+
{ name: 'level', width: '100px', priority: 10 },
|
|
515
|
+
{ name: 'order', width: '100px', priority: 10 },
|
|
516
|
+
{ name: 'phones', width: '300px', priority: 10 },
|
|
517
|
+
{ name: 'emails', width: '300px', priority: 10 },
|
|
518
|
+
],
|
|
519
|
+
};
|
|
520
|
+
//#endregion
|
|
521
|
+
|
|
522
|
+
class AXPComponentSlot {
|
|
523
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
524
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: AXPComponentSlot, isStandalone: true, ngImport: i0 }); }
|
|
525
|
+
}
|
|
526
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlot, decorators: [{
|
|
527
|
+
type: Directive
|
|
528
|
+
}] });
|
|
529
|
+
|
|
298
530
|
function extractNestedFieldsWildcard(obj, basePath, fields) {
|
|
299
531
|
const result = {};
|
|
300
532
|
if (fields.length === 1 && fields[0] === '*') {
|
|
@@ -313,7 +545,41 @@ function setSmart(obj, smartPath, value) {
|
|
|
313
545
|
const lastPart = pathParts[pathParts.length - 1];
|
|
314
546
|
const fieldMatch = lastPart.match(/^\{(.+)\}$/);
|
|
315
547
|
if (!fieldMatch) {
|
|
548
|
+
// Fix: If value is undefined and we're setting a nested property,
|
|
549
|
+
// check if the parent object exists and if setting this would result in
|
|
550
|
+
// all properties being undefined. If so, set the parent to null instead.
|
|
551
|
+
if (isNil(value) && pathParts.length > 1) {
|
|
552
|
+
const parentPath = pathParts.slice(0, -1).join('.');
|
|
553
|
+
const parentObj = get(obj, parentPath);
|
|
554
|
+
// If parent is already null/undefined, don't recreate the object structure
|
|
555
|
+
if (isNil(parentObj)) {
|
|
556
|
+
return obj;
|
|
557
|
+
}
|
|
558
|
+
// Check if parent is a plain object (not array, not null)
|
|
559
|
+
if (isPlainObject(parentObj)) {
|
|
560
|
+
const existingKeys = Object.keys(parentObj);
|
|
561
|
+
// Check if all existing properties are null/undefined using lodash
|
|
562
|
+
const allNil = isEmpty(existingKeys) || existingKeys.every((key) => isNil(parentObj[key]));
|
|
563
|
+
if (allNil) {
|
|
564
|
+
// Set parent to null instead of creating/keeping an object with all undefined properties
|
|
565
|
+
set(obj, parentPath, null);
|
|
566
|
+
return obj;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
316
570
|
set(obj, smartPath, value);
|
|
571
|
+
// After setting, check again if parent should be null using lodash
|
|
572
|
+
if (isNil(value) && pathParts.length > 1) {
|
|
573
|
+
const parentPath = pathParts.slice(0, -1).join('.');
|
|
574
|
+
const parentObj = get(obj, parentPath);
|
|
575
|
+
if (isPlainObject(parentObj)) {
|
|
576
|
+
// Use lodash to check if all properties are null/undefined
|
|
577
|
+
const allNil = Object.keys(parentObj).every((key) => isNil(parentObj[key]));
|
|
578
|
+
if (allNil) {
|
|
579
|
+
set(obj, parentPath, null);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
317
583
|
return obj;
|
|
318
584
|
}
|
|
319
585
|
const fields = fieldMatch[1].split(',').map((f) => f.trim());
|
|
@@ -525,9 +791,10 @@ function getEnumValues(enumType) {
|
|
|
525
791
|
|
|
526
792
|
class AXPContextChangeEvent {
|
|
527
793
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
794
|
+
//#endregion
|
|
795
|
+
//#region ---- Context signal store ----
|
|
796
|
+
// Shared reactive context: root injector has a default instance; widget/layout trees
|
|
797
|
+
const AXPContextStore = signalStore(
|
|
531
798
|
// Initial State
|
|
532
799
|
withState(() => ({
|
|
533
800
|
data: {}, // Shared context data
|
|
@@ -577,7 +844,7 @@ withMethods((store) => ({
|
|
|
577
844
|
lastChange: changeEvent,
|
|
578
845
|
});
|
|
579
846
|
},
|
|
580
|
-
patch(context) {
|
|
847
|
+
patch(context, skipDirtyTracking = false) {
|
|
581
848
|
const currentData = cloneDeep(store.data());
|
|
582
849
|
// Update the value and prepare the change event
|
|
583
850
|
const updatedData = { ...currentData, ...context };
|
|
@@ -587,7 +854,7 @@ withMethods((store) => ({
|
|
|
587
854
|
};
|
|
588
855
|
// Patch the state
|
|
589
856
|
patchState(store, {
|
|
590
|
-
previousSnapshot: store.snapshot(),
|
|
857
|
+
...(skipDirtyTracking ? {} : { previousSnapshot: store.snapshot() }),
|
|
591
858
|
data: updatedData,
|
|
592
859
|
state: 'changed',
|
|
593
860
|
lastChange: changeEvent,
|
|
@@ -635,107 +902,527 @@ withMethods((store) => ({
|
|
|
635
902
|
getValue(path) {
|
|
636
903
|
return getSmart(store.data(), path);
|
|
637
904
|
},
|
|
905
|
+
// Check if a path exists in the context
|
|
906
|
+
hasValue(path) {
|
|
907
|
+
return has(store.data(), path);
|
|
908
|
+
},
|
|
638
909
|
})));
|
|
910
|
+
//#endregion
|
|
639
911
|
|
|
640
|
-
class
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const random = (Math.random() * 16) | 0;
|
|
644
|
-
const value = char === 'x' ? random : (random & 0x3) | 0x8;
|
|
645
|
-
return value.toString(16);
|
|
646
|
-
});
|
|
912
|
+
class AXPExpressionEvaluatorScopeProviderContext {
|
|
913
|
+
constructor() {
|
|
914
|
+
this.scopes = {};
|
|
647
915
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
let max = 100;
|
|
651
|
-
if (args.length == 1)
|
|
652
|
-
max = args[0];
|
|
653
|
-
if (args.length == 2) {
|
|
654
|
-
min = args[0];
|
|
655
|
-
max = args[1];
|
|
656
|
-
}
|
|
657
|
-
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
916
|
+
addScope(namespace, functions) {
|
|
917
|
+
this.scopes[namespace] = { ...this.scopes[namespace], ...functions };
|
|
658
918
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
let end = new Date();
|
|
662
|
-
if (args.length === 1) {
|
|
663
|
-
start = args[0];
|
|
664
|
-
}
|
|
665
|
-
else if (args.length === 2) {
|
|
666
|
-
start = args[0];
|
|
667
|
-
end = args[1];
|
|
668
|
-
}
|
|
669
|
-
const startTime = start.getTime();
|
|
670
|
-
const endTime = end.getTime();
|
|
671
|
-
return new Date(startTime + Math.random() * (endTime - startTime));
|
|
919
|
+
getScopes() {
|
|
920
|
+
return this.scopes;
|
|
672
921
|
}
|
|
673
|
-
|
|
674
|
-
|
|
922
|
+
}
|
|
923
|
+
const AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER = new InjectionToken('AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER');
|
|
924
|
+
class AXPExpressionEvaluatorScopeProviderService {
|
|
925
|
+
constructor() {
|
|
926
|
+
this.injector = inject(Injector);
|
|
927
|
+
this.cache = null;
|
|
675
928
|
}
|
|
676
|
-
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
}
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
}
|
|
689
|
-
// Shuffle the array and slice the first 'count' elements
|
|
690
|
-
const shuffled = items.slice();
|
|
691
|
-
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
692
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
693
|
-
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; // Swap elements
|
|
929
|
+
async load() {
|
|
930
|
+
if (this.cache)
|
|
931
|
+
return;
|
|
932
|
+
const raw = this.injector.get(AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, [], { optional: true });
|
|
933
|
+
const providers = Array.isArray(raw)
|
|
934
|
+
? raw
|
|
935
|
+
: typeof raw === 'function'
|
|
936
|
+
? raw()
|
|
937
|
+
: [];
|
|
938
|
+
const context = new AXPExpressionEvaluatorScopeProviderContext();
|
|
939
|
+
for (const provider of providers) {
|
|
940
|
+
await provider.provide(context);
|
|
694
941
|
}
|
|
695
|
-
|
|
942
|
+
this.cache = context.getScopes();
|
|
696
943
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
return
|
|
944
|
+
async getScopesAsync() {
|
|
945
|
+
await this.load();
|
|
946
|
+
return this.cache || {};
|
|
700
947
|
}
|
|
701
|
-
static
|
|
702
|
-
|
|
948
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPExpressionEvaluatorScopeProviderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
949
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPExpressionEvaluatorScopeProviderService, providedIn: 'root' }); }
|
|
950
|
+
}
|
|
951
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPExpressionEvaluatorScopeProviderService, decorators: [{
|
|
952
|
+
type: Injectable,
|
|
953
|
+
args: [{ providedIn: 'root' }]
|
|
954
|
+
}] });
|
|
955
|
+
|
|
956
|
+
class AXPExpressionEvaluatorService {
|
|
957
|
+
constructor() {
|
|
958
|
+
// Memoization cache for compiled expressions
|
|
959
|
+
this.expressionCache = new Map();
|
|
960
|
+
this.providerService = inject(AXPExpressionEvaluatorScopeProviderService);
|
|
703
961
|
}
|
|
704
|
-
|
|
705
|
-
|
|
962
|
+
getOrCompileFunction(expression) {
|
|
963
|
+
if (!this.expressionCache.has(expression)) {
|
|
964
|
+
// Check if expression contains multiple statements (has semicolons or newlines)
|
|
965
|
+
const hasMultipleStatements = expression.includes(';') || expression.includes('\n');
|
|
966
|
+
let fn;
|
|
967
|
+
if (hasMultipleStatements) {
|
|
968
|
+
// For multiple statements, execute them in sequence and return the last expression
|
|
969
|
+
fn = new Function('scope', `with (scope) { return (async function() { ${expression} })(); }`);
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
// For single expressions, use return
|
|
973
|
+
fn = new Function('scope', `with (scope) { return (async function() { return ${expression}; })(); }`);
|
|
974
|
+
}
|
|
975
|
+
this.expressionCache.set(expression, fn);
|
|
976
|
+
}
|
|
977
|
+
return this.expressionCache.get(expression);
|
|
706
978
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
979
|
+
async getMergedScope(userScope) {
|
|
980
|
+
const pluginScopes = await this.providerService.getScopesAsync();
|
|
981
|
+
// Merge pluginScopes and userScope (userScope takes precedence)
|
|
982
|
+
return { ...pluginScopes, ...userScope };
|
|
983
|
+
}
|
|
984
|
+
async evaluate(source, scope = {}) {
|
|
985
|
+
try {
|
|
986
|
+
const mergedScope = await this.getMergedScope(scope);
|
|
987
|
+
if (typeof source === 'string' && source.includes('{{')) {
|
|
988
|
+
return await this.evaluateStringExpression(source, mergedScope);
|
|
989
|
+
}
|
|
990
|
+
else if (Array.isArray(source)) {
|
|
991
|
+
const evaluatedArray = [];
|
|
992
|
+
for (const item of source) {
|
|
993
|
+
evaluatedArray.push(await this.evaluate(item, mergedScope));
|
|
994
|
+
}
|
|
995
|
+
return evaluatedArray;
|
|
996
|
+
}
|
|
997
|
+
else if (typeof source === 'object' && source !== null) {
|
|
998
|
+
const evaluatedObject = {};
|
|
999
|
+
for (const key in source) {
|
|
1000
|
+
if (source.hasOwnProperty(key)) {
|
|
1001
|
+
evaluatedObject[key] = await this.evaluate(source[key], mergedScope);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return evaluatedObject;
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
return source;
|
|
1008
|
+
}
|
|
714
1009
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
return `rgb(${r}, ${g}, ${b})`;
|
|
1010
|
+
catch (error) {
|
|
1011
|
+
console.error('Expression evaluator - Error evaluating expression:', source, error);
|
|
1012
|
+
return false;
|
|
719
1013
|
}
|
|
720
|
-
// Convert RGB to HEX
|
|
721
|
-
const toHex = (val) => val.toString(16).padStart(2, '0');
|
|
722
|
-
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
723
1014
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
1015
|
+
async evaluateStringExpression(templateExpression, scope) {
|
|
1016
|
+
// Check if the input is exactly a single {{ ... }} expression (handle multiline)
|
|
1017
|
+
const exactMatch = templateExpression.match(/^\s*\{\{\s*([\s\S]*?)\s*\}\}\s*$/);
|
|
1018
|
+
if (exactMatch) {
|
|
1019
|
+
const expression = exactMatch[1];
|
|
1020
|
+
const sandbox = this.getOrCompileFunction(expression);
|
|
1021
|
+
const result = await sandbox(scope);
|
|
1022
|
+
return result;
|
|
1023
|
+
}
|
|
1024
|
+
// Otherwise, interpolate all {{ ... }} expressions in the string
|
|
1025
|
+
const regex = /\{\{\s*([\s\S]*?)\s*\}\}/g;
|
|
1026
|
+
// Collect all matches and their positions
|
|
1027
|
+
const matches = [];
|
|
1028
|
+
let match;
|
|
1029
|
+
while ((match = regex.exec(templateExpression)) !== null) {
|
|
1030
|
+
matches.push({
|
|
1031
|
+
expression: match[1],
|
|
1032
|
+
start: match.index,
|
|
1033
|
+
end: regex.lastIndex,
|
|
1034
|
+
raw: match[0],
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
// Evaluate all expressions in parallel
|
|
1038
|
+
const values = await Promise.all(matches.map((m) => {
|
|
1039
|
+
const sandbox = this.getOrCompileFunction(m.expression);
|
|
1040
|
+
return sandbox(scope);
|
|
1041
|
+
}));
|
|
1042
|
+
// Reconstruct the string with evaluated values
|
|
1043
|
+
let result = '';
|
|
1044
|
+
let lastIndex = 0;
|
|
1045
|
+
matches.forEach((m, i) => {
|
|
1046
|
+
result += templateExpression.slice(lastIndex, m.start);
|
|
1047
|
+
const value = values[i];
|
|
1048
|
+
result += value !== undefined && value !== null ? value : '';
|
|
1049
|
+
lastIndex = m.end;
|
|
1050
|
+
});
|
|
1051
|
+
result += templateExpression.slice(lastIndex);
|
|
1052
|
+
return result;
|
|
1053
|
+
}
|
|
1054
|
+
isExpression(expression) {
|
|
1055
|
+
if (typeof expression === 'string') {
|
|
1056
|
+
return expression.trim().startsWith('{{') && expression.trim().endsWith('}}');
|
|
1057
|
+
}
|
|
1058
|
+
return false;
|
|
1059
|
+
}
|
|
1060
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPExpressionEvaluatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1061
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPExpressionEvaluatorService, providedIn: 'root' }); }
|
|
1062
|
+
}
|
|
1063
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPExpressionEvaluatorService, decorators: [{
|
|
1064
|
+
type: Injectable,
|
|
1065
|
+
args: [{ providedIn: 'root' }]
|
|
1066
|
+
}] });
|
|
1067
|
+
|
|
1068
|
+
class AXPComponentSlotPlaceholderComponent {
|
|
1069
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotPlaceholderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1070
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.9", type: AXPComponentSlotPlaceholderComponent, isStandalone: true, selector: "axp-component-slot-placeholder", ngImport: i0, template: `<div>
|
|
1071
|
+
<ax-skeleton class="ax-w-full ax-h-10 ax-rounded-md"></ax-skeleton>
|
|
1072
|
+
</div>`, isInline: true, dependencies: [{ kind: "ngmodule", type: AXSkeletonModule }, { kind: "component", type: i1.AXSkeletonComponent, selector: "ax-skeleton", inputs: ["animated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1073
|
+
}
|
|
1074
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotPlaceholderComponent, decorators: [{
|
|
1075
|
+
type: Component,
|
|
1076
|
+
args: [{
|
|
1077
|
+
selector: 'axp-component-slot-placeholder',
|
|
1078
|
+
template: `<div>
|
|
1079
|
+
<ax-skeleton class="ax-w-full ax-h-10 ax-rounded-md"></ax-skeleton>
|
|
1080
|
+
</div>`,
|
|
1081
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1082
|
+
imports: [AXSkeletonModule],
|
|
1083
|
+
standalone: true,
|
|
1084
|
+
}]
|
|
1085
|
+
}] });
|
|
1086
|
+
|
|
1087
|
+
class AXPComponentSlotRegistryService {
|
|
1088
|
+
constructor() {
|
|
1089
|
+
this.registry = new Map();
|
|
1090
|
+
}
|
|
1091
|
+
register(slotName, config) {
|
|
1092
|
+
let configs = this.registry.get(slotName) || [];
|
|
1093
|
+
// Check if the component is already registered in this slot
|
|
1094
|
+
const isDuplicate = configs.some(existingConfig => existingConfig.name === config.name);
|
|
1095
|
+
if (!isDuplicate) {
|
|
1096
|
+
configs = [...configs, config]; // Add the new configuration
|
|
1097
|
+
this.registry.set(slotName, configs);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
get(slotName) {
|
|
1101
|
+
return this.registry.get(slotName) || [];
|
|
1102
|
+
}
|
|
1103
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1104
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotRegistryService, providedIn: 'root' }); }
|
|
1105
|
+
}
|
|
1106
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotRegistryService, decorators: [{
|
|
1107
|
+
type: Injectable,
|
|
1108
|
+
args: [{
|
|
1109
|
+
providedIn: 'root'
|
|
1110
|
+
}]
|
|
1111
|
+
}] });
|
|
1112
|
+
|
|
1113
|
+
class AXPComponentSlotDirective {
|
|
1114
|
+
constructor() {
|
|
1115
|
+
this.name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
1116
|
+
this.host = input(...(ngDevMode ? [undefined, { debugName: "host" }] : /* istanbul ignore next */ []));
|
|
1117
|
+
this.context = input(...(ngDevMode ? [undefined, { debugName: "context" }] : /* istanbul ignore next */ []));
|
|
1118
|
+
this.elementRef = inject(ElementRef);
|
|
1119
|
+
this.registryService = inject(AXPComponentSlotRegistryService);
|
|
1120
|
+
this.injector = inject(Injector);
|
|
1121
|
+
this.evaluator = inject(AXPExpressionEvaluatorService);
|
|
1122
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
1123
|
+
this.contextStore = inject(AXPContextStore);
|
|
1124
|
+
this.isEmpty = computed(() => this._viewCount() === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
1125
|
+
// Create a signal to store the count of children
|
|
1126
|
+
this._viewCount = signal(0, ...(ngDevMode ? [{ debugName: "_viewCount" }] : /* istanbul ignore next */ []));
|
|
1127
|
+
// Track component references for updates
|
|
1128
|
+
this.componentRefs = [];
|
|
1129
|
+
// Track placeholder references for replacement
|
|
1130
|
+
this.placeholderRefs = new Map();
|
|
1131
|
+
// Watch for context changes and update component instances
|
|
1132
|
+
effect(() => {
|
|
1133
|
+
const currentContext = this.context();
|
|
1134
|
+
const currentHost = this.host();
|
|
1135
|
+
// Update all component references with new context and host
|
|
1136
|
+
this.componentRefs.forEach((componentRef) => {
|
|
1137
|
+
if (componentRef.instance) {
|
|
1138
|
+
Object.assign(componentRef.instance, {
|
|
1139
|
+
host: currentHost,
|
|
1140
|
+
context: currentContext,
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
async ngOnInit() {
|
|
1147
|
+
await this.loadComponents();
|
|
1148
|
+
// Update the signal after loading
|
|
1149
|
+
this._viewCount.set(this.viewContainerRef.length);
|
|
1150
|
+
}
|
|
1151
|
+
async loadComponents() {
|
|
1152
|
+
this.viewContainerRef.clear();
|
|
1153
|
+
// Clear previous component references
|
|
1154
|
+
this.componentRefs = [];
|
|
1155
|
+
this.placeholderRefs.clear();
|
|
1156
|
+
const configs = sortBy(this.registryService.get(this.name()), (c) => c.priority ?? 0);
|
|
1157
|
+
if (!configs) {
|
|
1158
|
+
console.error(`No component found for slot ${this.name()}`);
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
// Evaluate conditions and check features in parallel for performance
|
|
1162
|
+
const results = await Promise.all(configs.map(async (c) => {
|
|
1163
|
+
// Check condition if provided
|
|
1164
|
+
const conditionPassed = c.condition ? await this.evaluateCondition(c.condition) : true;
|
|
1165
|
+
// Check features if provided
|
|
1166
|
+
// const featuresPassed =
|
|
1167
|
+
// c.features && c.features.length > 0 ? this.sessionService.isFeatureEnabled(...c.features) : true;
|
|
1168
|
+
return {
|
|
1169
|
+
config: c,
|
|
1170
|
+
// visible: conditionPassed && featuresPassed,
|
|
1171
|
+
visible: conditionPassed,
|
|
1172
|
+
};
|
|
1173
|
+
}));
|
|
1174
|
+
// Filter visible components while preserving priority order
|
|
1175
|
+
const slots = results.filter((r) => r.visible).map((r) => r.config);
|
|
1176
|
+
// Create skeleton placeholders immediately in priority order
|
|
1177
|
+
slots.forEach((config, index) => {
|
|
1178
|
+
const placeholderRef = this.viewContainerRef.createComponent(AXPComponentSlotPlaceholderComponent);
|
|
1179
|
+
this.placeholderRefs.set(index, placeholderRef);
|
|
1180
|
+
});
|
|
1181
|
+
// Load all components in parallel and replace placeholders as they become ready
|
|
1182
|
+
const loadPromises = slots.map(async (config, index) => {
|
|
1183
|
+
let component;
|
|
1184
|
+
let options = {};
|
|
1185
|
+
// load component
|
|
1186
|
+
if (typeof config.loadComponent === 'function') {
|
|
1187
|
+
await runInInjectionContext(this.injector, async () => {
|
|
1188
|
+
component = await config.loadComponent?.();
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
else if (config.component) {
|
|
1192
|
+
component = config.component;
|
|
1193
|
+
}
|
|
1194
|
+
// load options
|
|
1195
|
+
if (typeof config.options === 'function') {
|
|
1196
|
+
await runInInjectionContext(this.injector, async () => {
|
|
1197
|
+
const fun = config.options;
|
|
1198
|
+
options = await fun();
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
else if (config.options) {
|
|
1202
|
+
options = await this.evaluator.evaluate(config.options, {});
|
|
1203
|
+
}
|
|
1204
|
+
// Replace placeholder with actual component as soon as it's ready
|
|
1205
|
+
if (!component) {
|
|
1206
|
+
console.warn(`Component failed to load for slot ${this.name()} at index ${index}`);
|
|
1207
|
+
// Remove placeholder if component failed to load
|
|
1208
|
+
const placeholderRef = this.placeholderRefs.get(index);
|
|
1209
|
+
if (placeholderRef) {
|
|
1210
|
+
placeholderRef.destroy();
|
|
1211
|
+
this.placeholderRefs.delete(index);
|
|
1212
|
+
}
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
// Get the placeholder reference at this index
|
|
1216
|
+
const placeholderRef = this.placeholderRefs.get(index);
|
|
1217
|
+
if (!placeholderRef) {
|
|
1218
|
+
console.warn(`Placeholder not found for index ${index}`);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
// Get the index of the placeholder in the view container
|
|
1222
|
+
const placeholderIndex = this.viewContainerRef.indexOf(placeholderRef.hostView);
|
|
1223
|
+
// Remove the placeholder
|
|
1224
|
+
placeholderRef.destroy();
|
|
1225
|
+
this.placeholderRefs.delete(index);
|
|
1226
|
+
// Create the actual component at the same position
|
|
1227
|
+
const componentRef = this.viewContainerRef.createComponent(component, { index: placeholderIndex });
|
|
1228
|
+
// Store the component reference for future updates
|
|
1229
|
+
this.componentRefs.push(componentRef);
|
|
1230
|
+
Object.assign(componentRef.instance, {
|
|
1231
|
+
host: this.host(),
|
|
1232
|
+
context: this.context(),
|
|
1233
|
+
...options,
|
|
1234
|
+
});
|
|
1235
|
+
});
|
|
1236
|
+
// Wait for all components to finish loading (they render as they become ready)
|
|
1237
|
+
await Promise.all(loadPromises);
|
|
1238
|
+
}
|
|
1239
|
+
async evaluateCondition(condition) {
|
|
1240
|
+
if (typeof condition === 'string') {
|
|
1241
|
+
const result = await this.evaluator.evaluate(condition, {});
|
|
1242
|
+
return result;
|
|
1243
|
+
}
|
|
1244
|
+
return condition(this.contextStore.data());
|
|
1245
|
+
//return condition(this.context());
|
|
1246
|
+
}
|
|
1247
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1248
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: AXPComponentSlotDirective, isStandalone: false, selector: "axp-component-slot", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, host: { classPropertyName: "host", publicName: "host", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["slot"], ngImport: i0 }); }
|
|
1249
|
+
}
|
|
1250
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotDirective, decorators: [{
|
|
1251
|
+
type: Directive,
|
|
1252
|
+
args: [{
|
|
1253
|
+
selector: 'axp-component-slot',
|
|
1254
|
+
standalone: false,
|
|
1255
|
+
exportAs: 'slot',
|
|
1256
|
+
}]
|
|
1257
|
+
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], host: [{ type: i0.Input, args: [{ isSignal: true, alias: "host", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }] } });
|
|
1258
|
+
|
|
1259
|
+
class AXPComponentSlotModule {
|
|
1260
|
+
static forRoot(configs) {
|
|
1261
|
+
return {
|
|
1262
|
+
ngModule: AXPComponentSlotModule,
|
|
1263
|
+
providers: [
|
|
1264
|
+
{
|
|
1265
|
+
provide: 'AXPComponentSlotModuleFactory',
|
|
1266
|
+
useFactory: (registry) => () => {
|
|
1267
|
+
if (configs) {
|
|
1268
|
+
for (const [key, value] of Object.entries(configs)) {
|
|
1269
|
+
value.forEach(v => {
|
|
1270
|
+
registry.register(key, v);
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
},
|
|
1275
|
+
deps: [AXPComponentSlotRegistryService],
|
|
1276
|
+
multi: true
|
|
1277
|
+
}
|
|
1278
|
+
]
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
static forChild(configs) {
|
|
1282
|
+
return {
|
|
1283
|
+
ngModule: AXPComponentSlotModule,
|
|
1284
|
+
providers: [
|
|
1285
|
+
{
|
|
1286
|
+
provide: 'AXPComponentSlotModuleFactory',
|
|
1287
|
+
useFactory: (registry) => () => {
|
|
1288
|
+
if (configs) {
|
|
1289
|
+
for (const [key, value] of Object.entries(configs)) {
|
|
1290
|
+
value.forEach(v => {
|
|
1291
|
+
registry.register(key, v);
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
deps: [AXPComponentSlotRegistryService],
|
|
1297
|
+
multi: true
|
|
1298
|
+
}
|
|
1299
|
+
]
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* @ignore
|
|
1304
|
+
*/
|
|
1305
|
+
constructor(instances) {
|
|
1306
|
+
instances?.forEach(f => {
|
|
1307
|
+
f();
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotModule, deps: [{ token: 'AXPComponentSlotModuleFactory', optional: true }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1311
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotModule, declarations: [AXPComponentSlotDirective], exports: [AXPComponentSlotDirective] }); }
|
|
1312
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotModule }); }
|
|
1313
|
+
}
|
|
1314
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPComponentSlotModule, decorators: [{
|
|
1315
|
+
type: NgModule,
|
|
1316
|
+
args: [{
|
|
1317
|
+
declarations: [AXPComponentSlotDirective],
|
|
1318
|
+
exports: [AXPComponentSlotDirective]
|
|
1319
|
+
}]
|
|
1320
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1321
|
+
type: Optional
|
|
1322
|
+
}, {
|
|
1323
|
+
type: Inject,
|
|
1324
|
+
args: ['AXPComponentSlotModuleFactory']
|
|
1325
|
+
}] }] });
|
|
1326
|
+
|
|
1327
|
+
class AXPDataGenerator {
|
|
1328
|
+
static uuid() {
|
|
1329
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
|
|
1330
|
+
const random = (Math.random() * 16) | 0;
|
|
1331
|
+
const value = char === 'x' ? random : (random & 0x3) | 0x8;
|
|
1332
|
+
return value.toString(16);
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
static number(...args) {
|
|
1336
|
+
let min = 0;
|
|
1337
|
+
let max = 100;
|
|
1338
|
+
if (args.length == 1)
|
|
1339
|
+
max = args[0];
|
|
1340
|
+
if (args.length == 2) {
|
|
1341
|
+
min = args[0];
|
|
1342
|
+
max = args[1];
|
|
1343
|
+
}
|
|
1344
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
1345
|
+
}
|
|
1346
|
+
static date(...args) {
|
|
1347
|
+
let start = new Date(2000, 0, 1);
|
|
1348
|
+
let end = new Date();
|
|
1349
|
+
if (args.length === 1) {
|
|
1350
|
+
start = args[0];
|
|
1351
|
+
}
|
|
1352
|
+
else if (args.length === 2) {
|
|
1353
|
+
start = args[0];
|
|
1354
|
+
end = args[1];
|
|
1355
|
+
}
|
|
1356
|
+
const startTime = start.getTime();
|
|
1357
|
+
const endTime = end.getTime();
|
|
1358
|
+
return new Date(startTime + Math.random() * (endTime - startTime));
|
|
1359
|
+
}
|
|
1360
|
+
static array(length = 5, generator) {
|
|
1361
|
+
return Array.from({ length }, generator);
|
|
1362
|
+
}
|
|
1363
|
+
static pick(...args) {
|
|
1364
|
+
if (args.length < 1) {
|
|
1365
|
+
throw new Error('Invalid parameters');
|
|
1366
|
+
}
|
|
1367
|
+
const items = args[0];
|
|
1368
|
+
const count = args[1] ?? 1;
|
|
1369
|
+
if (count < 1) {
|
|
1370
|
+
throw new Error('Count must be at least 1');
|
|
1371
|
+
}
|
|
1372
|
+
// If the count is greater than the number of items, just return a shuffled copy of the array
|
|
1373
|
+
if (count >= items.length) {
|
|
1374
|
+
return [...items].sort(() => Math.random() - 0.5);
|
|
1375
|
+
}
|
|
1376
|
+
// Shuffle the array and slice the first 'count' elements
|
|
1377
|
+
const shuffled = items.slice();
|
|
1378
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
1379
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
1380
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; // Swap elements
|
|
1381
|
+
}
|
|
1382
|
+
return count == 1 ? shuffled.slice(0, count)[0] : shuffled.slice(0, count);
|
|
1383
|
+
}
|
|
1384
|
+
static string(length = 10) {
|
|
1385
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
1386
|
+
return Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
|
|
1387
|
+
}
|
|
1388
|
+
static boolean() {
|
|
1389
|
+
return Math.random() >= 0.5;
|
|
1390
|
+
}
|
|
1391
|
+
static item(array = []) {
|
|
1392
|
+
return array.length > 0 ? array[Math.floor(Math.random() * array.length)] : undefined;
|
|
1393
|
+
}
|
|
1394
|
+
static color(format = 'hex') {
|
|
1395
|
+
// Generate HSL values with safe ranges for good contrast
|
|
1396
|
+
const h = Math.floor(Math.random() * 360);
|
|
1397
|
+
const s = Math.floor(Math.random() * 20) + 60; // 60% - 80%
|
|
1398
|
+
const l = Math.floor(Math.random() * 20) + 40; // 40% - 60%
|
|
1399
|
+
if (format === 'hsl') {
|
|
1400
|
+
return `hsl(${h}, ${s}%, ${l}%)`;
|
|
1401
|
+
}
|
|
1402
|
+
// Convert HSL to RGB
|
|
1403
|
+
const { r, g, b } = this.hslToRgb(h, s / 100, l / 100);
|
|
1404
|
+
if (format === 'rgb') {
|
|
1405
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
1406
|
+
}
|
|
1407
|
+
// Convert RGB to HEX
|
|
1408
|
+
const toHex = (val) => val.toString(16).padStart(2, '0');
|
|
1409
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
1410
|
+
}
|
|
1411
|
+
//TODO: move or read from utils
|
|
1412
|
+
static hslToRgb(h, s, l) {
|
|
1413
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
1414
|
+
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
|
|
1415
|
+
const m = l - c / 2;
|
|
1416
|
+
let r = 0, g = 0, b = 0;
|
|
1417
|
+
if (h < 60)
|
|
1418
|
+
[r, g, b] = [c, x, 0];
|
|
1419
|
+
else if (h < 120)
|
|
1420
|
+
[r, g, b] = [x, c, 0];
|
|
1421
|
+
else if (h < 180)
|
|
1422
|
+
[r, g, b] = [0, c, x];
|
|
1423
|
+
else if (h < 240)
|
|
1424
|
+
[r, g, b] = [0, x, c];
|
|
1425
|
+
else if (h < 300)
|
|
739
1426
|
[r, g, b] = [x, 0, c];
|
|
740
1427
|
else
|
|
741
1428
|
[r, g, b] = [c, 0, x];
|
|
@@ -822,203 +1509,54 @@ function objectKeyValueTransforms(keyName) {
|
|
|
822
1509
|
};
|
|
823
1510
|
}
|
|
824
1511
|
|
|
825
|
-
//#region ---- Imports ----
|
|
826
|
-
//#endregion
|
|
827
|
-
//#region ---- Provider Registry Service ----
|
|
828
|
-
/**
|
|
829
|
-
* Registry service for dynamically loaded module providers.
|
|
830
|
-
* Stores provider instances that are loaded conditionally based on access control.
|
|
831
|
-
*/
|
|
832
|
-
class AXPModuleProviderRegistry {
|
|
833
|
-
constructor() {
|
|
834
|
-
//#region ---- Fields ----
|
|
835
|
-
this.permissionProviders = [];
|
|
836
|
-
this.menuProviders = [];
|
|
837
|
-
this.entityProviders = [];
|
|
838
|
-
this.settingProviders = [];
|
|
839
|
-
this.searchProviders = [];
|
|
840
|
-
this.featureProviders = [];
|
|
841
|
-
this.datasourceProviders = [];
|
|
842
|
-
}
|
|
843
|
-
//#endregion
|
|
844
|
-
//#region ---- Public Methods ----
|
|
845
|
-
/**
|
|
846
|
-
* Register a permission provider.
|
|
847
|
-
*/
|
|
848
|
-
registerPermissionProvider(provider) {
|
|
849
|
-
this.permissionProviders.push(provider);
|
|
850
|
-
}
|
|
851
|
-
/**
|
|
852
|
-
* Get all registered permission providers.
|
|
853
|
-
*/
|
|
854
|
-
getPermissionProviders() {
|
|
855
|
-
return [...this.permissionProviders];
|
|
856
|
-
}
|
|
857
|
-
/**
|
|
858
|
-
* Register a menu provider.
|
|
859
|
-
*/
|
|
860
|
-
registerMenuProvider(provider) {
|
|
861
|
-
this.menuProviders.push(provider);
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Get all registered menu providers.
|
|
865
|
-
*/
|
|
866
|
-
getMenuProviders() {
|
|
867
|
-
return [...this.menuProviders];
|
|
868
|
-
}
|
|
869
|
-
/**
|
|
870
|
-
* Register an entity provider.
|
|
871
|
-
*/
|
|
872
|
-
registerEntityProvider(provider) {
|
|
873
|
-
this.entityProviders.push(provider);
|
|
874
|
-
}
|
|
875
|
-
/**
|
|
876
|
-
* Get all registered entity providers.
|
|
877
|
-
*/
|
|
878
|
-
getEntityProviders() {
|
|
879
|
-
return [...this.entityProviders];
|
|
880
|
-
}
|
|
881
|
-
/**
|
|
882
|
-
* Register a settings provider.
|
|
883
|
-
*/
|
|
884
|
-
registerSettingProvider(provider) {
|
|
885
|
-
this.settingProviders.push(provider);
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Get all registered settings providers.
|
|
889
|
-
*/
|
|
890
|
-
getSettingProviders() {
|
|
891
|
-
return [...this.settingProviders];
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* Register a search provider.
|
|
895
|
-
*/
|
|
896
|
-
registerSearchProvider(provider) {
|
|
897
|
-
this.searchProviders.push(provider);
|
|
898
|
-
}
|
|
899
|
-
/**
|
|
900
|
-
* Get all registered search providers.
|
|
901
|
-
*/
|
|
902
|
-
getSearchProviders() {
|
|
903
|
-
return [...this.searchProviders];
|
|
904
|
-
}
|
|
905
|
-
/**
|
|
906
|
-
* Register a feature provider.
|
|
907
|
-
*/
|
|
908
|
-
registerFeatureProvider(provider) {
|
|
909
|
-
this.featureProviders.push(provider);
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Get all registered feature providers.
|
|
913
|
-
*/
|
|
914
|
-
getFeatureProviders() {
|
|
915
|
-
return [...this.featureProviders];
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Register a datasource provider.
|
|
919
|
-
*/
|
|
920
|
-
registerDatasourceProvider(provider) {
|
|
921
|
-
this.datasourceProviders.push(provider);
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Get all registered datasource providers.
|
|
925
|
-
*/
|
|
926
|
-
getDatasourceProviders() {
|
|
927
|
-
return [...this.datasourceProviders];
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Clear all registered providers.
|
|
931
|
-
* Useful for testing or re-initialization.
|
|
932
|
-
*/
|
|
933
|
-
clear() {
|
|
934
|
-
this.permissionProviders.length = 0;
|
|
935
|
-
this.menuProviders.length = 0;
|
|
936
|
-
this.entityProviders.length = 0;
|
|
937
|
-
this.settingProviders.length = 0;
|
|
938
|
-
this.searchProviders.length = 0;
|
|
939
|
-
this.featureProviders.length = 0;
|
|
940
|
-
this.datasourceProviders.length = 0;
|
|
941
|
-
}
|
|
942
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPModuleProviderRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
943
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPModuleProviderRegistry, providedIn: 'root' }); }
|
|
944
|
-
}
|
|
945
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPModuleProviderRegistry, decorators: [{
|
|
946
|
-
type: Injectable,
|
|
947
|
-
args: [{ providedIn: 'root' }]
|
|
948
|
-
}] });
|
|
949
|
-
|
|
950
1512
|
const AXP_DATASOURCE_DEFINITION_PROVIDER = new InjectionToken('AXP_DATASOURCE_TYPE_PROVIDER');
|
|
951
1513
|
class AXPDataSourceDefinitionProviderService {
|
|
952
1514
|
constructor() {
|
|
953
1515
|
this.providers = inject(AXP_DATASOURCE_DEFINITION_PROVIDER, { optional: true });
|
|
954
|
-
this.providerRegistry = inject(AXPModuleProviderRegistry);
|
|
955
1516
|
}
|
|
956
1517
|
async items() {
|
|
957
1518
|
const items = [];
|
|
958
|
-
// Load from DI tokens (
|
|
1519
|
+
// Load from DI tokens; resolve lazy providers (provideLazyProvider uses useFactory that returns Promise<T>)
|
|
959
1520
|
if (Array.isArray(this.providers)) {
|
|
960
|
-
for (const
|
|
961
|
-
|
|
962
|
-
|
|
1521
|
+
for (const raw of this.providers) {
|
|
1522
|
+
const provider = await Promise.resolve(raw);
|
|
1523
|
+
if (provider && typeof provider.items === 'function') {
|
|
1524
|
+
set(provider, '__parent__', this);
|
|
1525
|
+
items.push(...(await provider.items()));
|
|
1526
|
+
}
|
|
963
1527
|
}
|
|
964
1528
|
}
|
|
965
|
-
// Load from registry (manifest-based, conditionally loaded)
|
|
966
|
-
const registryProviders = this.providerRegistry.getDatasourceProviders();
|
|
967
|
-
for (const provider of registryProviders) {
|
|
968
|
-
set(provider, '__parent__', this);
|
|
969
|
-
items.push(...(await provider.items()));
|
|
970
|
-
}
|
|
971
1529
|
return items;
|
|
972
1530
|
}
|
|
973
1531
|
async get(name) {
|
|
974
1532
|
return (await this.items()).find((c) => c.name == name);
|
|
975
1533
|
}
|
|
976
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
977
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1534
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSourceDefinitionProviderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1535
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSourceDefinitionProviderService, providedIn: 'root' }); }
|
|
978
1536
|
}
|
|
979
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1537
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDataSourceDefinitionProviderService, decorators: [{
|
|
980
1538
|
type: Injectable,
|
|
981
1539
|
args: [{ providedIn: 'root' }]
|
|
982
1540
|
}] });
|
|
983
1541
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
this.
|
|
988
|
-
this.
|
|
989
|
-
|
|
990
|
-
this.updateEffect = effect(() => {
|
|
991
|
-
const currentData = this.data();
|
|
992
|
-
const currentPath = this.path();
|
|
993
|
-
set(this.elementRef.nativeElement, currentPath, currentData);
|
|
994
|
-
}, ...(ngDevMode ? [{ debugName: "updateEffect" }] : []));
|
|
995
|
-
}
|
|
996
|
-
ngOnInit() {
|
|
997
|
-
// Initial data setup
|
|
998
|
-
set(this.elementRef.nativeElement, this.path(), this.data());
|
|
999
|
-
}
|
|
1000
|
-
/**
|
|
1001
|
-
* Get data from the element
|
|
1002
|
-
*/
|
|
1003
|
-
getData() {
|
|
1004
|
-
return get(this.elementRef.nativeElement, this.path());
|
|
1005
|
-
}
|
|
1006
|
-
/**
|
|
1007
|
-
* Update data at runtime
|
|
1008
|
-
*/
|
|
1009
|
-
setData(data) {
|
|
1010
|
-
set(this.elementRef.nativeElement, this.path(), data);
|
|
1542
|
+
// src/app/directives/grid-layout.directive.ts
|
|
1543
|
+
class AXPContentCheckerDirective {
|
|
1544
|
+
constructor() {
|
|
1545
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
1546
|
+
this.elementRef = inject((ElementRef));
|
|
1547
|
+
this.isEmpty = computed(() => this.viewContainerRef.length === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : /* istanbul ignore next */ []));
|
|
1011
1548
|
}
|
|
1012
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1013
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "
|
|
1549
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPContentCheckerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1550
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: AXPContentCheckerDirective, isStandalone: true, selector: "[axp-content-checker]", exportAs: ["checker"], ngImport: i0 }); }
|
|
1014
1551
|
}
|
|
1015
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1552
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPContentCheckerDirective, decorators: [{
|
|
1016
1553
|
type: Directive,
|
|
1017
1554
|
args: [{
|
|
1018
|
-
selector: '[axp-
|
|
1019
|
-
standalone: true
|
|
1555
|
+
selector: '[axp-content-checker]',
|
|
1556
|
+
standalone: true,
|
|
1557
|
+
exportAs: 'checker'
|
|
1020
1558
|
}]
|
|
1021
|
-
}]
|
|
1559
|
+
}] });
|
|
1022
1560
|
|
|
1023
1561
|
class AXPDblClickDirective {
|
|
1024
1562
|
constructor() {
|
|
@@ -1041,30 +1579,69 @@ class AXPDblClickDirective {
|
|
|
1041
1579
|
}
|
|
1042
1580
|
this.lastTap = currentTime;
|
|
1043
1581
|
}
|
|
1044
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1045
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
1582
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDblClickDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1583
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: AXPDblClickDirective, isStandalone: true, selector: "[onDblClick]", outputs: { onDblClick: "onDblClick" }, host: { listeners: { "dblclick": "handleOnDblClick($event)", "touchend": "onTouchEnd($event)" } }, ngImport: i0 }); }
|
|
1046
1584
|
}
|
|
1047
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1585
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDblClickDirective, decorators: [{
|
|
1048
1586
|
type: Directive,
|
|
1049
1587
|
args: [{
|
|
1050
1588
|
selector: '[onDblClick]'
|
|
1051
1589
|
}]
|
|
1052
|
-
}], propDecorators: { onDblClick: [{
|
|
1053
|
-
type: Output
|
|
1054
|
-
}], handleOnDblClick: [{
|
|
1055
|
-
type: HostListener,
|
|
1056
|
-
args: ['dblclick', ['$event']]
|
|
1057
|
-
}], onTouchEnd: [{
|
|
1058
|
-
type: HostListener,
|
|
1059
|
-
args: ['touchend', ['$event']]
|
|
1060
|
-
}] } });
|
|
1590
|
+
}], propDecorators: { onDblClick: [{
|
|
1591
|
+
type: Output
|
|
1592
|
+
}], handleOnDblClick: [{
|
|
1593
|
+
type: HostListener,
|
|
1594
|
+
args: ['dblclick', ['$event']]
|
|
1595
|
+
}], onTouchEnd: [{
|
|
1596
|
+
type: HostListener,
|
|
1597
|
+
args: ['touchend', ['$event']]
|
|
1598
|
+
}] } });
|
|
1599
|
+
|
|
1600
|
+
class AXPElementDataDirective {
|
|
1601
|
+
constructor(elementRef) {
|
|
1602
|
+
this.elementRef = elementRef;
|
|
1603
|
+
this.data = input(null, { ...(ngDevMode ? { debugName: "data" } : /* istanbul ignore next */ {}), alias: 'axp-data' });
|
|
1604
|
+
this.path = input('__data__', { ...(ngDevMode ? { debugName: "path" } : /* istanbul ignore next */ {}), alias: 'axp-data-path' });
|
|
1605
|
+
// Effect to update element data when inputs change
|
|
1606
|
+
this.updateEffect = effect(() => {
|
|
1607
|
+
const currentData = this.data();
|
|
1608
|
+
const currentPath = this.path();
|
|
1609
|
+
set(this.elementRef.nativeElement, currentPath, currentData);
|
|
1610
|
+
}, ...(ngDevMode ? [{ debugName: "updateEffect" }] : /* istanbul ignore next */ []));
|
|
1611
|
+
}
|
|
1612
|
+
ngOnInit() {
|
|
1613
|
+
// Initial data setup
|
|
1614
|
+
set(this.elementRef.nativeElement, this.path(), this.data());
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* Get data from the element
|
|
1618
|
+
*/
|
|
1619
|
+
getData() {
|
|
1620
|
+
return get(this.elementRef.nativeElement, this.path());
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Update data at runtime
|
|
1624
|
+
*/
|
|
1625
|
+
setData(data) {
|
|
1626
|
+
set(this.elementRef.nativeElement, this.path(), data);
|
|
1627
|
+
}
|
|
1628
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPElementDataDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1629
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: AXPElementDataDirective, isStandalone: true, selector: "[axp-data]", inputs: { data: { classPropertyName: "data", publicName: "axp-data", isSignal: true, isRequired: false, transformFunction: null }, path: { classPropertyName: "path", publicName: "axp-data-path", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
|
|
1630
|
+
}
|
|
1631
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPElementDataDirective, decorators: [{
|
|
1632
|
+
type: Directive,
|
|
1633
|
+
args: [{
|
|
1634
|
+
selector: '[axp-data]',
|
|
1635
|
+
standalone: true
|
|
1636
|
+
}]
|
|
1637
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "axp-data", required: false }] }], path: [{ type: i0.Input, args: [{ isSignal: true, alias: "axp-data-path", required: false }] }] } });
|
|
1061
1638
|
|
|
1062
1639
|
// src/app/directives/grid-layout.directive.ts
|
|
1063
1640
|
class AXPGridLayoutDirective {
|
|
1064
1641
|
constructor(el, renderer) {
|
|
1065
1642
|
this.el = el;
|
|
1066
1643
|
this.renderer = renderer;
|
|
1067
|
-
this.options = input.required(...(ngDevMode ?
|
|
1644
|
+
this.options = input.required({ ...(ngDevMode ? { debugName: "options" } : /* istanbul ignore next */ {}), alias: 'axp-grid-layout' });
|
|
1068
1645
|
}
|
|
1069
1646
|
ngOnChanges(changes) {
|
|
1070
1647
|
if (changes['options']) {
|
|
@@ -1108,10 +1685,10 @@ class AXPGridLayoutDirective {
|
|
|
1108
1685
|
}
|
|
1109
1686
|
});
|
|
1110
1687
|
}
|
|
1111
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1112
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
1688
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGridLayoutDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1689
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: AXPGridLayoutDirective, isStandalone: true, selector: "[axp-grid-layout]", inputs: { options: { classPropertyName: "options", publicName: "axp-grid-layout", isSignal: true, isRequired: true, transformFunction: null } }, usesOnChanges: true, ngImport: i0 }); }
|
|
1113
1690
|
}
|
|
1114
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1691
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPGridLayoutDirective, decorators: [{
|
|
1115
1692
|
type: Directive,
|
|
1116
1693
|
args: [{
|
|
1117
1694
|
selector: '[axp-grid-layout]',
|
|
@@ -1119,222 +1696,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
1119
1696
|
}]
|
|
1120
1697
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "axp-grid-layout", required: true }] }] } });
|
|
1121
1698
|
|
|
1122
|
-
// src/app/directives/grid-layout.directive.ts
|
|
1123
|
-
class AXPContentCheckerDirective {
|
|
1124
|
-
constructor() {
|
|
1125
|
-
this.viewContainerRef = inject(ViewContainerRef);
|
|
1126
|
-
this.elementRef = inject((ElementRef));
|
|
1127
|
-
this.isEmpty = computed(() => this.viewContainerRef.length === 0, ...(ngDevMode ? [{ debugName: "isEmpty" }] : []));
|
|
1128
|
-
}
|
|
1129
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPContentCheckerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1130
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.12", type: AXPContentCheckerDirective, isStandalone: true, selector: "[axp-content-checker]", exportAs: ["checker"], ngImport: i0 }); }
|
|
1131
|
-
}
|
|
1132
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPContentCheckerDirective, decorators: [{
|
|
1133
|
-
type: Directive,
|
|
1134
|
-
args: [{
|
|
1135
|
-
selector: '[axp-content-checker]',
|
|
1136
|
-
standalone: true,
|
|
1137
|
-
exportAs: 'checker'
|
|
1138
|
-
}]
|
|
1139
|
-
}] });
|
|
1140
|
-
|
|
1141
|
-
//#region ---- Imports ----
|
|
1142
|
-
//#endregion
|
|
1143
|
-
//#region ---- Directive ----
|
|
1144
|
-
/**
|
|
1145
|
-
* Fullscreen directive that provides CSS-based fullscreen functionality
|
|
1146
|
-
* Usage: <element axFullscreen #fullscreen="axFullscreen"></element>
|
|
1147
|
-
* Then: fullscreen.toggle() or fullscreen.enter() or fullscreen.exit()
|
|
1148
|
-
*/
|
|
1149
|
-
class AXFullscreenDirective {
|
|
1150
|
-
constructor(elementRef) {
|
|
1151
|
-
this.elementRef = elementRef;
|
|
1152
|
-
//#region ---- Properties ----
|
|
1153
|
-
/**
|
|
1154
|
-
* Current fullscreen state
|
|
1155
|
-
*/
|
|
1156
|
-
this.isFullscreenState = signal(false, ...(ngDevMode ? [{ debugName: "isFullscreenState" }] : []));
|
|
1157
|
-
/**
|
|
1158
|
-
* Original element styles to restore
|
|
1159
|
-
*/
|
|
1160
|
-
this.originalStyles = {};
|
|
1161
|
-
/**
|
|
1162
|
-
* Original parent element reference
|
|
1163
|
-
*/
|
|
1164
|
-
this.originalParent = null;
|
|
1165
|
-
/**
|
|
1166
|
-
* Fullscreen container element
|
|
1167
|
-
*/
|
|
1168
|
-
this.fullscreenContainer = null;
|
|
1169
|
-
/**
|
|
1170
|
-
* Fullscreen change event
|
|
1171
|
-
*/
|
|
1172
|
-
this.fullscreenChange = output();
|
|
1173
|
-
//#endregion
|
|
1174
|
-
//#region ---- Constructor ----
|
|
1175
|
-
this.destroyRef = inject(DestroyRef);
|
|
1176
|
-
this.renderer = inject(Renderer2);
|
|
1177
|
-
// Sync state changes to output
|
|
1178
|
-
effect(() => {
|
|
1179
|
-
const isFullscreen = this.isFullscreenState();
|
|
1180
|
-
untracked(() => {
|
|
1181
|
-
this.fullscreenChange.emit(isFullscreen);
|
|
1182
|
-
});
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
//#endregion
|
|
1186
|
-
//#region ---- Public API ----
|
|
1187
|
-
/**
|
|
1188
|
-
* Toggle fullscreen state
|
|
1189
|
-
*/
|
|
1190
|
-
async toggle() {
|
|
1191
|
-
if (this.isFullscreenState()) {
|
|
1192
|
-
await this.exit();
|
|
1193
|
-
}
|
|
1194
|
-
else {
|
|
1195
|
-
await this.enter();
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Enter fullscreen mode using CSS
|
|
1200
|
-
*/
|
|
1201
|
-
async enter() {
|
|
1202
|
-
if (this.isFullscreenState()) {
|
|
1203
|
-
return;
|
|
1204
|
-
}
|
|
1205
|
-
const element = this.elementRef.nativeElement;
|
|
1206
|
-
try {
|
|
1207
|
-
// Store original styles and parent
|
|
1208
|
-
this.storeOriginalStyles(element);
|
|
1209
|
-
this.originalParent = element.parentElement;
|
|
1210
|
-
// Create fullscreen container
|
|
1211
|
-
this.fullscreenContainer = this.renderer.createElement('div');
|
|
1212
|
-
this.renderer.setStyle(this.fullscreenContainer, 'position', 'fixed');
|
|
1213
|
-
this.renderer.setStyle(this.fullscreenContainer, 'top', '0');
|
|
1214
|
-
this.renderer.setStyle(this.fullscreenContainer, 'left', '0');
|
|
1215
|
-
this.renderer.setStyle(this.fullscreenContainer, 'width', '100vw');
|
|
1216
|
-
this.renderer.setStyle(this.fullscreenContainer, 'height', '100vh');
|
|
1217
|
-
this.renderer.setStyle(this.fullscreenContainer, 'z-index', '9999');
|
|
1218
|
-
this.renderer.setStyle(this.fullscreenContainer, 'background-color', '#ffffff');
|
|
1219
|
-
this.renderer.setStyle(this.fullscreenContainer, 'overflow', 'auto');
|
|
1220
|
-
// Move element to container
|
|
1221
|
-
this.renderer.appendChild(this.fullscreenContainer, element);
|
|
1222
|
-
// Apply fullscreen styles to element
|
|
1223
|
-
this.renderer.setStyle(element, 'position', 'relative');
|
|
1224
|
-
this.renderer.setStyle(element, 'width', '100%');
|
|
1225
|
-
this.renderer.setStyle(element, 'height', '100%');
|
|
1226
|
-
this.renderer.setStyle(element, 'margin', '0');
|
|
1227
|
-
this.renderer.setStyle(element, 'padding', '0');
|
|
1228
|
-
// Append container to body
|
|
1229
|
-
this.renderer.appendChild(document.body, this.fullscreenContainer);
|
|
1230
|
-
// Prevent body scroll
|
|
1231
|
-
this.renderer.setStyle(document.body, 'overflow', 'hidden');
|
|
1232
|
-
this.isFullscreenState.set(true);
|
|
1233
|
-
}
|
|
1234
|
-
catch (error) {
|
|
1235
|
-
console.error('Error entering fullscreen:', error);
|
|
1236
|
-
this.restoreOriginalStyles(element);
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
/**
|
|
1240
|
-
* Exit fullscreen mode
|
|
1241
|
-
*/
|
|
1242
|
-
async exit() {
|
|
1243
|
-
if (!this.isFullscreenState()) {
|
|
1244
|
-
return;
|
|
1245
|
-
}
|
|
1246
|
-
const element = this.elementRef.nativeElement;
|
|
1247
|
-
try {
|
|
1248
|
-
// Restore body scroll
|
|
1249
|
-
this.renderer.removeStyle(document.body, 'overflow');
|
|
1250
|
-
// Move element back to original parent
|
|
1251
|
-
if (this.fullscreenContainer && this.originalParent) {
|
|
1252
|
-
this.renderer.removeChild(this.fullscreenContainer, element);
|
|
1253
|
-
this.renderer.appendChild(this.originalParent, element);
|
|
1254
|
-
// Remove container
|
|
1255
|
-
this.renderer.removeChild(document.body, this.fullscreenContainer);
|
|
1256
|
-
this.fullscreenContainer = null;
|
|
1257
|
-
}
|
|
1258
|
-
// Restore original styles
|
|
1259
|
-
this.restoreOriginalStyles(element);
|
|
1260
|
-
this.isFullscreenState.set(false);
|
|
1261
|
-
}
|
|
1262
|
-
catch (error) {
|
|
1263
|
-
console.error('Error exiting fullscreen:', error);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
/**
|
|
1267
|
-
* Check if currently in fullscreen mode
|
|
1268
|
-
*/
|
|
1269
|
-
isFullscreen() {
|
|
1270
|
-
return this.isFullscreenState();
|
|
1271
|
-
}
|
|
1272
|
-
//#endregion
|
|
1273
|
-
//#region ---- Private Methods ----
|
|
1274
|
-
/**
|
|
1275
|
-
* Store original element styles
|
|
1276
|
-
*/
|
|
1277
|
-
storeOriginalStyles(element) {
|
|
1278
|
-
const computedStyle = window.getComputedStyle(element);
|
|
1279
|
-
this.originalStyles = {
|
|
1280
|
-
position: computedStyle.position,
|
|
1281
|
-
top: computedStyle.top,
|
|
1282
|
-
left: computedStyle.left,
|
|
1283
|
-
width: computedStyle.width,
|
|
1284
|
-
height: computedStyle.height,
|
|
1285
|
-
zIndex: computedStyle.zIndex,
|
|
1286
|
-
backgroundColor: computedStyle.backgroundColor,
|
|
1287
|
-
margin: computedStyle.margin,
|
|
1288
|
-
padding: computedStyle.padding,
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
/**
|
|
1292
|
-
* Restore original element styles
|
|
1293
|
-
*/
|
|
1294
|
-
restoreOriginalStyles(element) {
|
|
1295
|
-
if (!this.originalStyles) {
|
|
1296
|
-
return;
|
|
1297
|
-
}
|
|
1298
|
-
// Restore each style property
|
|
1299
|
-
Object.entries(this.originalStyles).forEach(([key, value]) => {
|
|
1300
|
-
const styleKey = this.camelToKebabCase(key);
|
|
1301
|
-
if (value) {
|
|
1302
|
-
this.renderer.setStyle(element, styleKey, value);
|
|
1303
|
-
}
|
|
1304
|
-
else {
|
|
1305
|
-
this.renderer.removeStyle(element, styleKey);
|
|
1306
|
-
}
|
|
1307
|
-
});
|
|
1308
|
-
this.originalStyles = {};
|
|
1309
|
-
}
|
|
1310
|
-
/**
|
|
1311
|
-
* Convert camelCase to kebab-case for CSS properties
|
|
1312
|
-
*/
|
|
1313
|
-
camelToKebabCase(str) {
|
|
1314
|
-
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
|
|
1315
|
-
}
|
|
1316
|
-
//#endregion
|
|
1317
|
-
//#region ---- Lifecycle ----
|
|
1318
|
-
ngOnDestroy() {
|
|
1319
|
-
// Exit fullscreen if still active
|
|
1320
|
-
if (this.isFullscreenState()) {
|
|
1321
|
-
this.exit().catch(() => {
|
|
1322
|
-
// Ignore errors during cleanup
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXFullscreenDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1327
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.12", type: AXFullscreenDirective, isStandalone: true, selector: "[axFullscreen]", outputs: { fullscreenChange: "fullscreenChange" }, exportAs: ["axFullscreen"], ngImport: i0 }); }
|
|
1328
|
-
}
|
|
1329
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXFullscreenDirective, decorators: [{
|
|
1330
|
-
type: Directive,
|
|
1331
|
-
args: [{
|
|
1332
|
-
selector: '[axFullscreen]',
|
|
1333
|
-
standalone: true,
|
|
1334
|
-
exportAs: 'axFullscreen',
|
|
1335
|
-
}]
|
|
1336
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { fullscreenChange: [{ type: i0.Output, args: ["fullscreenChange"] }] } });
|
|
1337
|
-
|
|
1338
1699
|
const AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER = new InjectionToken('AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER');
|
|
1339
1700
|
|
|
1340
1701
|
//#region ---- Imports ----
|
|
@@ -1471,10 +1832,10 @@ class AXPDistributedEventListenerService {
|
|
|
1471
1832
|
this.listenersByKey.clear();
|
|
1472
1833
|
this.providersLoaded = false;
|
|
1473
1834
|
}
|
|
1474
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1475
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1835
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDistributedEventListenerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1836
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDistributedEventListenerService, providedIn: 'root' }); }
|
|
1476
1837
|
}
|
|
1477
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1838
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDistributedEventListenerService, decorators: [{
|
|
1478
1839
|
type: Injectable,
|
|
1479
1840
|
args: [{
|
|
1480
1841
|
providedIn: 'root',
|
|
@@ -1565,200 +1926,48 @@ class AXPBroadcastEventService {
|
|
|
1565
1926
|
}
|
|
1566
1927
|
else {
|
|
1567
1928
|
reject(new Error(`Timeout: No response received for event '${type}' after ${options.retries} attempts.`));
|
|
1568
|
-
}
|
|
1569
|
-
}
|
|
1570
|
-
}, options.timeout);
|
|
1571
|
-
});
|
|
1572
|
-
};
|
|
1573
|
-
return attemptRequest(0);
|
|
1574
|
-
}
|
|
1575
|
-
/**
|
|
1576
|
-
* Respond to a request
|
|
1577
|
-
*/
|
|
1578
|
-
respondToRequest(requestId, response) {
|
|
1579
|
-
if (!requestId) {
|
|
1580
|
-
console.warn('Invalid requestId. Cannot send response.');
|
|
1581
|
-
return;
|
|
1582
|
-
}
|
|
1583
|
-
this.channel.postMessage({ requestId, response });
|
|
1584
|
-
}
|
|
1585
|
-
/**
|
|
1586
|
-
* Cleanup when the service is destroyed
|
|
1587
|
-
*/
|
|
1588
|
-
ngOnDestroy() {
|
|
1589
|
-
this.channel.close();
|
|
1590
|
-
// Complete all subjects
|
|
1591
|
-
this.eventSubjects.forEach((subject) => subject.complete());
|
|
1592
|
-
this.eventSubjects.clear();
|
|
1593
|
-
// Reject all pending requests to avoid dangling promises
|
|
1594
|
-
this.pendingRequests.forEach((resolve, requestId) => {
|
|
1595
|
-
resolve(Promise.reject(new Error(`Service destroyed. Request ${requestId} was not completed.`)));
|
|
1596
|
-
});
|
|
1597
|
-
this.pendingRequests.clear();
|
|
1598
|
-
// Cleanup multi-tab event history
|
|
1599
|
-
this.multiTabEventHistory.clear();
|
|
1600
|
-
}
|
|
1601
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPBroadcastEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1602
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPBroadcastEventService, providedIn: 'root' }); }
|
|
1603
|
-
}
|
|
1604
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPBroadcastEventService, decorators: [{
|
|
1605
|
-
type: Injectable,
|
|
1606
|
-
args: [{
|
|
1607
|
-
providedIn: 'root',
|
|
1608
|
-
}]
|
|
1609
|
-
}], ctorParameters: () => [] });
|
|
1610
|
-
|
|
1611
|
-
class AXPExpressionEvaluatorScopeProviderContext {
|
|
1612
|
-
constructor() {
|
|
1613
|
-
this.scopes = {};
|
|
1614
|
-
}
|
|
1615
|
-
addScope(namespace, functions) {
|
|
1616
|
-
this.scopes[namespace] = { ...this.scopes[namespace], ...functions };
|
|
1617
|
-
}
|
|
1618
|
-
getScopes() {
|
|
1619
|
-
return this.scopes;
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
const AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER = new InjectionToken('AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER');
|
|
1623
|
-
class AXPExpressionEvaluatorScopeProviderService {
|
|
1624
|
-
constructor() {
|
|
1625
|
-
this.providers = inject(AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, { optional: true });
|
|
1626
|
-
this.cache = null;
|
|
1627
|
-
}
|
|
1628
|
-
async load() {
|
|
1629
|
-
if (this.cache)
|
|
1630
|
-
return;
|
|
1631
|
-
const context = new AXPExpressionEvaluatorScopeProviderContext();
|
|
1632
|
-
if (Array.isArray(this.providers)) {
|
|
1633
|
-
for (const provider of this.providers) {
|
|
1634
|
-
await provider.provide(context);
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
this.cache = context.getScopes();
|
|
1638
|
-
}
|
|
1639
|
-
async getScopesAsync() {
|
|
1640
|
-
await this.load();
|
|
1641
|
-
return this.cache || {};
|
|
1642
|
-
}
|
|
1643
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPExpressionEvaluatorScopeProviderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1644
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPExpressionEvaluatorScopeProviderService, providedIn: 'root' }); }
|
|
1645
|
-
}
|
|
1646
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: AXPExpressionEvaluatorScopeProviderService, decorators: [{
|
|
1647
|
-
type: Injectable,
|
|
1648
|
-
args: [{ providedIn: 'root' }]
|
|
1649
|
-
}] });
|
|
1650
|
-
|
|
1651
|
-
class AXPExpressionEvaluatorService {
|
|
1652
|
-
constructor() {
|
|
1653
|
-
// Memoization cache for compiled expressions
|
|
1654
|
-
this.expressionCache = new Map();
|
|
1655
|
-
this.providerService = inject(AXPExpressionEvaluatorScopeProviderService);
|
|
1656
|
-
}
|
|
1657
|
-
getOrCompileFunction(expression) {
|
|
1658
|
-
if (!this.expressionCache.has(expression)) {
|
|
1659
|
-
// Check if expression contains multiple statements (has semicolons or newlines)
|
|
1660
|
-
const hasMultipleStatements = expression.includes(';') || expression.includes('\n');
|
|
1661
|
-
let fn;
|
|
1662
|
-
if (hasMultipleStatements) {
|
|
1663
|
-
// For multiple statements, execute them in sequence and return the last expression
|
|
1664
|
-
fn = new Function('scope', `with (scope) { return (async function() { ${expression} })(); }`);
|
|
1665
|
-
}
|
|
1666
|
-
else {
|
|
1667
|
-
// For single expressions, use return
|
|
1668
|
-
fn = new Function('scope', `with (scope) { return (async function() { return ${expression}; })(); }`);
|
|
1669
|
-
}
|
|
1670
|
-
this.expressionCache.set(expression, fn);
|
|
1671
|
-
}
|
|
1672
|
-
return this.expressionCache.get(expression);
|
|
1673
|
-
}
|
|
1674
|
-
async getMergedScope(userScope) {
|
|
1675
|
-
const pluginScopes = await this.providerService.getScopesAsync();
|
|
1676
|
-
// Merge pluginScopes and userScope (userScope takes precedence)
|
|
1677
|
-
return { ...pluginScopes, ...userScope };
|
|
1678
|
-
}
|
|
1679
|
-
async evaluate(source, scope = {}) {
|
|
1680
|
-
try {
|
|
1681
|
-
const mergedScope = await this.getMergedScope(scope);
|
|
1682
|
-
if (typeof source === 'string' && source.includes('{{')) {
|
|
1683
|
-
return await this.evaluateStringExpression(source, mergedScope);
|
|
1684
|
-
}
|
|
1685
|
-
else if (Array.isArray(source)) {
|
|
1686
|
-
const evaluatedArray = [];
|
|
1687
|
-
for (const item of source) {
|
|
1688
|
-
evaluatedArray.push(await this.evaluate(item, mergedScope));
|
|
1689
|
-
}
|
|
1690
|
-
return evaluatedArray;
|
|
1691
|
-
}
|
|
1692
|
-
else if (typeof source === 'object' && source !== null) {
|
|
1693
|
-
const evaluatedObject = {};
|
|
1694
|
-
for (const key in source) {
|
|
1695
|
-
if (source.hasOwnProperty(key)) {
|
|
1696
|
-
evaluatedObject[key] = await this.evaluate(source[key], mergedScope);
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
return evaluatedObject;
|
|
1700
|
-
}
|
|
1701
|
-
else {
|
|
1702
|
-
return source;
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
catch (error) {
|
|
1706
|
-
console.error('Expression evaluator - Error evaluating expression:', source, error);
|
|
1707
|
-
return false;
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
async evaluateStringExpression(templateExpression, scope) {
|
|
1711
|
-
// Check if the input is exactly a single {{ ... }} expression (handle multiline)
|
|
1712
|
-
const exactMatch = templateExpression.match(/^\s*\{\{\s*([\s\S]*?)\s*\}\}\s*$/);
|
|
1713
|
-
if (exactMatch) {
|
|
1714
|
-
const expression = exactMatch[1];
|
|
1715
|
-
const sandbox = this.getOrCompileFunction(expression);
|
|
1716
|
-
const result = await sandbox(scope);
|
|
1717
|
-
return result;
|
|
1718
|
-
}
|
|
1719
|
-
// Otherwise, interpolate all {{ ... }} expressions in the string
|
|
1720
|
-
const regex = /\{\{\s*([\s\S]*?)\s*\}\}/g;
|
|
1721
|
-
// Collect all matches and their positions
|
|
1722
|
-
const matches = [];
|
|
1723
|
-
let match;
|
|
1724
|
-
while ((match = regex.exec(templateExpression)) !== null) {
|
|
1725
|
-
matches.push({
|
|
1726
|
-
expression: match[1],
|
|
1727
|
-
start: match.index,
|
|
1728
|
-
end: regex.lastIndex,
|
|
1729
|
-
raw: match[0],
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
}, options.timeout);
|
|
1730
1932
|
});
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
const values = await Promise.all(matches.map((m) => {
|
|
1734
|
-
const sandbox = this.getOrCompileFunction(m.expression);
|
|
1735
|
-
return sandbox(scope);
|
|
1736
|
-
}));
|
|
1737
|
-
// Reconstruct the string with evaluated values
|
|
1738
|
-
let result = '';
|
|
1739
|
-
let lastIndex = 0;
|
|
1740
|
-
matches.forEach((m, i) => {
|
|
1741
|
-
result += templateExpression.slice(lastIndex, m.start);
|
|
1742
|
-
const value = values[i];
|
|
1743
|
-
result += value !== undefined && value !== null ? value : '';
|
|
1744
|
-
lastIndex = m.end;
|
|
1745
|
-
});
|
|
1746
|
-
result += templateExpression.slice(lastIndex);
|
|
1747
|
-
return result;
|
|
1933
|
+
};
|
|
1934
|
+
return attemptRequest(0);
|
|
1748
1935
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1936
|
+
/**
|
|
1937
|
+
* Respond to a request
|
|
1938
|
+
*/
|
|
1939
|
+
respondToRequest(requestId, response) {
|
|
1940
|
+
if (!requestId) {
|
|
1941
|
+
console.warn('Invalid requestId. Cannot send response.');
|
|
1942
|
+
return;
|
|
1752
1943
|
}
|
|
1753
|
-
|
|
1944
|
+
this.channel.postMessage({ requestId, response });
|
|
1945
|
+
}
|
|
1946
|
+
/**
|
|
1947
|
+
* Cleanup when the service is destroyed
|
|
1948
|
+
*/
|
|
1949
|
+
ngOnDestroy() {
|
|
1950
|
+
this.channel.close();
|
|
1951
|
+
// Complete all subjects
|
|
1952
|
+
this.eventSubjects.forEach((subject) => subject.complete());
|
|
1953
|
+
this.eventSubjects.clear();
|
|
1954
|
+
// Reject all pending requests to avoid dangling promises
|
|
1955
|
+
this.pendingRequests.forEach((resolve, requestId) => {
|
|
1956
|
+
resolve(Promise.reject(new Error(`Service destroyed. Request ${requestId} was not completed.`)));
|
|
1957
|
+
});
|
|
1958
|
+
this.pendingRequests.clear();
|
|
1959
|
+
// Cleanup multi-tab event history
|
|
1960
|
+
this.multiTabEventHistory.clear();
|
|
1754
1961
|
}
|
|
1755
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1756
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
1962
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPBroadcastEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1963
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPBroadcastEventService, providedIn: 'root' }); }
|
|
1757
1964
|
}
|
|
1758
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
1965
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPBroadcastEventService, decorators: [{
|
|
1759
1966
|
type: Injectable,
|
|
1760
|
-
args: [{
|
|
1761
|
-
|
|
1967
|
+
args: [{
|
|
1968
|
+
providedIn: 'root',
|
|
1969
|
+
}]
|
|
1970
|
+
}], ctorParameters: () => [] });
|
|
1762
1971
|
|
|
1763
1972
|
class AXPHookService {
|
|
1764
1973
|
constructor() {
|
|
@@ -1806,10 +2015,10 @@ class AXPHookService {
|
|
|
1806
2015
|
}
|
|
1807
2016
|
return data;
|
|
1808
2017
|
}
|
|
1809
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
1810
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2018
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPHookService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2019
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPHookService, providedIn: 'root' }); }
|
|
1811
2020
|
}
|
|
1812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2021
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPHookService, decorators: [{
|
|
1813
2022
|
type: Injectable,
|
|
1814
2023
|
args: [{ providedIn: 'root' }]
|
|
1815
2024
|
}] });
|
|
@@ -1818,21 +2027,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
|
|
|
1818
2027
|
//#endregion
|
|
1819
2028
|
|
|
1820
2029
|
//#region ---- Provider Interfaces ----
|
|
1821
|
-
/**
|
|
1822
|
-
* Injection token for edition service.
|
|
1823
|
-
* Modules should provide their implementation using this token.
|
|
1824
|
-
*/
|
|
1825
|
-
const AXP_EDITION_SERVICE = new InjectionToken('AXP_EDITION_SERVICE', {
|
|
1826
|
-
providedIn: 'root',
|
|
1827
|
-
factory: () => {
|
|
1828
|
-
return null;
|
|
1829
|
-
},
|
|
1830
|
-
});
|
|
1831
|
-
/**
|
|
1832
|
-
* Injection token for module provider loader.
|
|
1833
|
-
* Implementation: @acorex/platform/auth
|
|
1834
|
-
*/
|
|
1835
|
-
const AXP_MODULE_PROVIDER_LOADER = new InjectionToken('AXP_MODULE_PROVIDER_LOADER');
|
|
1836
2030
|
/**
|
|
1837
2031
|
* Injection token for session service.
|
|
1838
2032
|
* Implementation: @acorex/platform/auth
|
|
@@ -1845,6 +2039,41 @@ const AXP_SESSION_SERVICE = new InjectionToken('AXP_SESSION_SERVICE');
|
|
|
1845
2039
|
const AXP_MODULE_MANIFEST_PROVIDER = new InjectionToken('AXP_MODULE_MANIFEST_PROVIDER');
|
|
1846
2040
|
//#endregion
|
|
1847
2041
|
|
|
2042
|
+
//#region ---- Imports ----
|
|
2043
|
+
//#endregion
|
|
2044
|
+
//#region ---- Feature Definition Provider Interface ----
|
|
2045
|
+
/**
|
|
2046
|
+
* Context for feature definition providers.
|
|
2047
|
+
* Allows providers to add additional feature definitions dynamically.
|
|
2048
|
+
*/
|
|
2049
|
+
class AXPFeatureDefinitionProviderContext {
|
|
2050
|
+
constructor() {
|
|
2051
|
+
this.features = new Map();
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* Add a feature definition.
|
|
2055
|
+
* @param key Full feature key (ModuleName:FeatureKey format with colon separator)
|
|
2056
|
+
* @param definition Feature definition
|
|
2057
|
+
*/
|
|
2058
|
+
addFeature(key, definition) {
|
|
2059
|
+
this.features.set(key, definition);
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Get all feature definitions.
|
|
2063
|
+
*/
|
|
2064
|
+
getFeatures() {
|
|
2065
|
+
return this.features;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Injection token for feature definition providers.
|
|
2070
|
+
*/
|
|
2071
|
+
const AXP_FEATURE_DEFINITION_PROVIDER = new InjectionToken('AXP_FEATURE_DEFINITION_PROVIDER', {
|
|
2072
|
+
providedIn: 'root',
|
|
2073
|
+
factory: () => [],
|
|
2074
|
+
});
|
|
2075
|
+
//#endregion
|
|
2076
|
+
|
|
1848
2077
|
//#region ---- Imports ----
|
|
1849
2078
|
//#endregion
|
|
1850
2079
|
//#region ---- Registry Service ----
|
|
@@ -1910,6 +2139,8 @@ class AXPModuleManifestRegistry {
|
|
|
1910
2139
|
}
|
|
1911
2140
|
});
|
|
1912
2141
|
await Promise.all(registerPromises);
|
|
2142
|
+
// Load and register features from all feature definition providers
|
|
2143
|
+
await this.loadFeatureDefinitions();
|
|
1913
2144
|
this.isInitialized = true;
|
|
1914
2145
|
}
|
|
1915
2146
|
//#endregion
|
|
@@ -1946,6 +2177,53 @@ class AXPModuleManifestRegistry {
|
|
|
1946
2177
|
has(moduleName) {
|
|
1947
2178
|
return this.manifests.has(moduleName);
|
|
1948
2179
|
}
|
|
2180
|
+
/**
|
|
2181
|
+
* Load feature definitions from all registered feature definition providers.
|
|
2182
|
+
* Features are automatically associated with modules based on the module name in the feature key.
|
|
2183
|
+
*/
|
|
2184
|
+
async loadFeatureDefinitions() {
|
|
2185
|
+
try {
|
|
2186
|
+
const featureProviders = this.injector.get(AXP_FEATURE_DEFINITION_PROVIDER, []);
|
|
2187
|
+
if (!featureProviders || featureProviders.length === 0) {
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2190
|
+
const context = new AXPFeatureDefinitionProviderContext();
|
|
2191
|
+
// Call all providers to collect features
|
|
2192
|
+
for (const provider of featureProviders) {
|
|
2193
|
+
if (provider instanceof Promise) {
|
|
2194
|
+
// If provider is a promise, resolve it
|
|
2195
|
+
const resolvedProvider = await provider;
|
|
2196
|
+
await resolvedProvider.provide(context);
|
|
2197
|
+
}
|
|
2198
|
+
else {
|
|
2199
|
+
// If provider is a direct instance, use it directly
|
|
2200
|
+
await provider.provide(context);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
// Register all features and associate them with their modules
|
|
2204
|
+
const features = context.getFeatures();
|
|
2205
|
+
for (const [key, definition] of features.entries()) {
|
|
2206
|
+
// Extract module name from key (format: ModuleName:FeatureKey)
|
|
2207
|
+
const [moduleName, ...keyParts] = key.split(':');
|
|
2208
|
+
const shortKey = keyParts.join(':');
|
|
2209
|
+
// Verify that the module exists
|
|
2210
|
+
if (!this.has(moduleName)) {
|
|
2211
|
+
console.warn(`Feature '${key}' references unknown module '${moduleName}'. Skipping.`);
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
// Register feature definition
|
|
2215
|
+
this.registerFeatureDefinition({
|
|
2216
|
+
...definition,
|
|
2217
|
+
name: key,
|
|
2218
|
+
module: moduleName,
|
|
2219
|
+
key: shortKey,
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
catch (error) {
|
|
2224
|
+
console.error('Failed to load feature definitions:', error);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
1949
2227
|
//#endregion
|
|
1950
2228
|
//#region ---- Feature Definition Management ----
|
|
1951
2229
|
/**
|
|
@@ -1982,7 +2260,7 @@ class AXPModuleManifestRegistry {
|
|
|
1982
2260
|
}
|
|
1983
2261
|
/**
|
|
1984
2262
|
* Register a feature definition dynamically (e.g., from feature definition provider).
|
|
1985
|
-
* Used to add features that are defined at runtime via
|
|
2263
|
+
* Used to add features that are defined at runtime via AXP_FEATURE_DEFINITION_PROVIDER.
|
|
1986
2264
|
*/
|
|
1987
2265
|
registerFeatureDefinition(definition) {
|
|
1988
2266
|
this.featureDefinitions.set(definition.name, definition);
|
|
@@ -1992,40 +2270,113 @@ class AXPModuleManifestRegistry {
|
|
|
1992
2270
|
/**
|
|
1993
2271
|
* Check if module dependencies are satisfied.
|
|
1994
2272
|
* Returns array of missing dependencies.
|
|
2273
|
+
* Dependencies can be module names or feature keys (ModuleName.FeatureKey format).
|
|
1995
2274
|
*/
|
|
1996
2275
|
checkDependencies(moduleName) {
|
|
1997
2276
|
const manifest = this.get(moduleName);
|
|
1998
|
-
if (!manifest?.dependencies) {
|
|
2277
|
+
if (!manifest?.dependencies || manifest.dependencies.length === 0) {
|
|
1999
2278
|
return { missingModules: [], missingFeatures: [] };
|
|
2000
2279
|
}
|
|
2001
2280
|
const missingModules = [];
|
|
2002
2281
|
const missingFeatures = [];
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2282
|
+
for (const dependency of manifest.dependencies) {
|
|
2283
|
+
// If dependency contains a dot, it's a feature (ModuleName.FeatureKey)
|
|
2284
|
+
if (dependency.includes('.')) {
|
|
2285
|
+
// Convert dependency format (ModuleName.FeatureKey) to feature name format (ModuleName:Feature:FeatureKey)
|
|
2286
|
+
const [moduleName, featureKey] = dependency.split('.');
|
|
2287
|
+
const featureName = `${moduleName}:Feature:${featureKey}`;
|
|
2288
|
+
if (!this.isFeatureDefined(featureName)) {
|
|
2289
|
+
missingFeatures.push(dependency);
|
|
2008
2290
|
}
|
|
2009
2291
|
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
if (!this.isFeatureDefined(featureName)) {
|
|
2015
|
-
missingFeatures.push(featureName);
|
|
2292
|
+
else {
|
|
2293
|
+
// Otherwise, it's a module name
|
|
2294
|
+
if (!this.has(dependency)) {
|
|
2295
|
+
missingModules.push(dependency);
|
|
2016
2296
|
}
|
|
2017
2297
|
}
|
|
2018
2298
|
}
|
|
2019
2299
|
return { missingModules, missingFeatures };
|
|
2020
2300
|
}
|
|
2021
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2022
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2301
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2302
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestRegistry, providedIn: 'root' }); }
|
|
2023
2303
|
}
|
|
2024
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2304
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestRegistry, decorators: [{
|
|
2025
2305
|
type: Injectable,
|
|
2026
2306
|
args: [{ providedIn: 'root' }]
|
|
2027
2307
|
}] });
|
|
2028
2308
|
|
|
2309
|
+
//#region ---- Imports ----
|
|
2310
|
+
//#endregion
|
|
2311
|
+
//#region ---- Module manifests data source ----
|
|
2312
|
+
/**
|
|
2313
|
+
* Registered module manifests for select widgets via dataSource name {@link MODULE_MANIFESTS_DATASOURCE_NAME}.
|
|
2314
|
+
*/
|
|
2315
|
+
const MODULE_MANIFESTS_DATASOURCE_NAME = 'platform-module-manifests';
|
|
2316
|
+
/**
|
|
2317
|
+
* Data source definition for module names/titles from {@link AXPModuleManifestRegistry}.
|
|
2318
|
+
*/
|
|
2319
|
+
class AXPModuleManifestsDataSourceDefinition {
|
|
2320
|
+
constructor() {
|
|
2321
|
+
//#region ---- Services & Dependencies ----
|
|
2322
|
+
this.manifestRegistry = inject(AXPModuleManifestRegistry);
|
|
2323
|
+
//#endregion
|
|
2324
|
+
}
|
|
2325
|
+
//#endregion
|
|
2326
|
+
//#region ---- Public API ----
|
|
2327
|
+
async items() {
|
|
2328
|
+
return [
|
|
2329
|
+
{
|
|
2330
|
+
name: MODULE_MANIFESTS_DATASOURCE_NAME,
|
|
2331
|
+
title: 'Module manifests',
|
|
2332
|
+
source: () => new AXDataSource({
|
|
2333
|
+
key: 'id',
|
|
2334
|
+
load: async () => {
|
|
2335
|
+
await this.manifestRegistry.initialize();
|
|
2336
|
+
const list = this.manifestRegistry.getAll().map((m) => ({
|
|
2337
|
+
id: m.name,
|
|
2338
|
+
title: m.title || m.name,
|
|
2339
|
+
}));
|
|
2340
|
+
return { items: list, total: list.length };
|
|
2341
|
+
},
|
|
2342
|
+
byKey: async (key) => {
|
|
2343
|
+
await this.manifestRegistry.initialize();
|
|
2344
|
+
const m = this.manifestRegistry.getAll().find((x) => x.name === key);
|
|
2345
|
+
return m ? { id: m.name, title: m.title || m.name } : undefined;
|
|
2346
|
+
},
|
|
2347
|
+
pageSize: 1000,
|
|
2348
|
+
}),
|
|
2349
|
+
columns: [
|
|
2350
|
+
{
|
|
2351
|
+
name: 'id',
|
|
2352
|
+
title: 'ID',
|
|
2353
|
+
datatype: 'string',
|
|
2354
|
+
type: 'text-editor',
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
name: 'title',
|
|
2358
|
+
title: 'Title',
|
|
2359
|
+
datatype: 'string',
|
|
2360
|
+
type: 'text-editor',
|
|
2361
|
+
},
|
|
2362
|
+
],
|
|
2363
|
+
filters: [
|
|
2364
|
+
{
|
|
2365
|
+
field: 'title',
|
|
2366
|
+
title: 'Title',
|
|
2367
|
+
operator: { type: 'equal' },
|
|
2368
|
+
widget: { type: 'text-editor' },
|
|
2369
|
+
filterType: { advance: true, inline: true },
|
|
2370
|
+
},
|
|
2371
|
+
],
|
|
2372
|
+
textField: { name: 'title', title: 'Title' },
|
|
2373
|
+
valueField: { name: 'id', title: 'ID' },
|
|
2374
|
+
},
|
|
2375
|
+
];
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
//#endregion
|
|
2379
|
+
|
|
2029
2380
|
class AXPAppStartUpService {
|
|
2030
2381
|
constructor() {
|
|
2031
2382
|
this.tasks = [];
|
|
@@ -2045,10 +2396,10 @@ class AXPAppStartUpService {
|
|
|
2045
2396
|
loadingText.innerHTML = status;
|
|
2046
2397
|
}
|
|
2047
2398
|
}
|
|
2048
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2049
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2399
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPAppStartUpService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2400
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPAppStartUpService, providedIn: 'root' }); }
|
|
2050
2401
|
}
|
|
2051
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2402
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPAppStartUpService, decorators: [{
|
|
2052
2403
|
type: Injectable,
|
|
2053
2404
|
args: [{
|
|
2054
2405
|
providedIn: 'root',
|
|
@@ -2066,17 +2417,16 @@ const AXPAppStartUpProvider = provideAppInitializer(() => {
|
|
|
2066
2417
|
//#endregion
|
|
2067
2418
|
//#region ---- Module ----
|
|
2068
2419
|
/**
|
|
2069
|
-
* Module for managing module manifests
|
|
2070
|
-
* Handles the registration of manifest
|
|
2420
|
+
* Module for managing module manifests initialization.
|
|
2421
|
+
* Handles the registration of manifest startup tasks.
|
|
2071
2422
|
*/
|
|
2072
2423
|
class AXPModuleManifestModule {
|
|
2073
2424
|
/**
|
|
2074
2425
|
* @ignore
|
|
2075
|
-
* Initializes module manifest
|
|
2426
|
+
* Initializes module manifest tasks on module construction.
|
|
2076
2427
|
*/
|
|
2077
2428
|
constructor(appInitService, injector) {
|
|
2078
2429
|
const manifestRegistry = injector.get(AXPModuleManifestRegistry);
|
|
2079
|
-
const moduleProviderLoader = injector.get(AXP_MODULE_PROVIDER_LOADER);
|
|
2080
2430
|
// Register manifest initialization task
|
|
2081
2431
|
appInitService.registerTask({
|
|
2082
2432
|
name: 'ModuleManifests',
|
|
@@ -2086,97 +2436,204 @@ class AXPModuleManifestModule {
|
|
|
2086
2436
|
await manifestRegistry.initialize();
|
|
2087
2437
|
},
|
|
2088
2438
|
});
|
|
2089
|
-
// Register module provider tasks
|
|
2090
|
-
appInitService.registerTask({
|
|
2091
|
-
name: 'RequiredModuleProviders',
|
|
2092
|
-
statusText: 'Loading required modules...',
|
|
2093
|
-
priority: 1.5,
|
|
2094
|
-
run: async () => {
|
|
2095
|
-
await moduleProviderLoader.loadRequiredModules();
|
|
2096
|
-
},
|
|
2097
|
-
});
|
|
2098
|
-
appInitService.registerTask({
|
|
2099
|
-
name: 'ModuleProviders',
|
|
2100
|
-
statusText: 'Loading module providers...',
|
|
2101
|
-
priority: 3,
|
|
2102
|
-
run: async () => {
|
|
2103
|
-
await moduleProviderLoader.loadProvidersIfReady();
|
|
2104
|
-
},
|
|
2105
|
-
});
|
|
2106
2439
|
}
|
|
2107
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2108
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "
|
|
2109
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "
|
|
2440
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestModule, deps: [{ token: AXPAppStartUpService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
2441
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestModule }); }
|
|
2442
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestModule }); }
|
|
2110
2443
|
}
|
|
2111
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2444
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPModuleManifestModule, decorators: [{
|
|
2112
2445
|
type: NgModule,
|
|
2113
2446
|
args: [{
|
|
2114
2447
|
providers: [],
|
|
2115
2448
|
}]
|
|
2116
2449
|
}], ctorParameters: () => [{ type: AXPAppStartUpService }, { type: i0.Injector }] });
|
|
2117
2450
|
|
|
2118
|
-
//#region ----
|
|
2451
|
+
//#region ---- Imports ----
|
|
2119
2452
|
//#endregion
|
|
2120
|
-
//#region ----
|
|
2453
|
+
//#region ---- Public API ----
|
|
2454
|
+
const LOCALE_KEY_REGEX = /^(\*-\*|[a-z]{2}-[A-Z]{2})$/;
|
|
2121
2455
|
/**
|
|
2122
|
-
*
|
|
2123
|
-
* Allows providers to add additional feature definitions dynamically.
|
|
2456
|
+
* Checks whether value is a valid locale map (`xx-XX` or `*-*` keys, string values).
|
|
2124
2457
|
*/
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2458
|
+
function isValidMultiLanguageObject(value) {
|
|
2459
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
2460
|
+
return false;
|
|
2128
2461
|
}
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
* @param definition Feature definition
|
|
2133
|
-
*/
|
|
2134
|
-
addFeature(key, definition) {
|
|
2135
|
-
this.features.set(key, definition);
|
|
2462
|
+
const entries = Object.entries(value);
|
|
2463
|
+
if (!entries.length) {
|
|
2464
|
+
return false;
|
|
2136
2465
|
}
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2466
|
+
return entries.every(([key, entryValue]) => LOCALE_KEY_REGEX.test(key) && typeof entryValue === 'string');
|
|
2467
|
+
}
|
|
2468
|
+
/**
|
|
2469
|
+
* Resolves {@link AXPMultiLanguageString} to a single string for the given locale.
|
|
2470
|
+
* Fallback order: `currentLocale` → `en-US` → first map value.
|
|
2471
|
+
*/
|
|
2472
|
+
function resolveMultiLanguageString(content, currentLocale) {
|
|
2473
|
+
if (content == null || content === '') {
|
|
2474
|
+
return '';
|
|
2142
2475
|
}
|
|
2476
|
+
if (typeof content === 'string') {
|
|
2477
|
+
return content;
|
|
2478
|
+
}
|
|
2479
|
+
if (!isValidMultiLanguageObject(content)) {
|
|
2480
|
+
return String(content);
|
|
2481
|
+
}
|
|
2482
|
+
const record = content;
|
|
2483
|
+
const pick = record[currentLocale] ??
|
|
2484
|
+
record['en-US'] ??
|
|
2485
|
+
Object.values(record).find((v) => v != null);
|
|
2486
|
+
if (pick == null || pick === '') {
|
|
2487
|
+
return '';
|
|
2488
|
+
}
|
|
2489
|
+
if (typeof pick === 'string') {
|
|
2490
|
+
return pick;
|
|
2491
|
+
}
|
|
2492
|
+
return String(pick);
|
|
2143
2493
|
}
|
|
2144
2494
|
/**
|
|
2145
|
-
*
|
|
2495
|
+
* Creates an {@link AXPMultiLanguageString} with `en-US` and `fa-IR` entries.
|
|
2496
|
+
* Use for seed data, tests, and demos that supply English and Persian copy explicitly.
|
|
2146
2497
|
*/
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2498
|
+
function createMultiLanguageString(enUs, faIr) {
|
|
2499
|
+
return { 'en-US': enUs, 'fa-IR': faIr };
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* True when there is no displayable text in any locale (plain string or ML map).
|
|
2503
|
+
* Pure helper for predicates (e.g. default section detection); prefer widgets / pipes for display.
|
|
2504
|
+
*/
|
|
2505
|
+
function isEffectivelyEmptyLocalizedValue(value) {
|
|
2506
|
+
if (value == null)
|
|
2507
|
+
return true;
|
|
2508
|
+
if (typeof value === 'string')
|
|
2509
|
+
return value.trim() === '';
|
|
2510
|
+
if (typeof value !== 'object' || Array.isArray(value))
|
|
2511
|
+
return false;
|
|
2512
|
+
const record = value;
|
|
2513
|
+
return Object.values(record).every((v) => v == null || String(v).trim() === '');
|
|
2514
|
+
}
|
|
2151
2515
|
//#endregion
|
|
2152
2516
|
|
|
2153
|
-
//#region ----
|
|
2517
|
+
//#region ---- Imports ----
|
|
2154
2518
|
//#endregion
|
|
2155
|
-
//#region ----
|
|
2519
|
+
//#region ---- AXPMultiLanguageStringResolverService ----
|
|
2156
2520
|
/**
|
|
2157
|
-
*
|
|
2158
|
-
*
|
|
2521
|
+
* Resolves {@link AXPMultiLanguageString} using the active app locale, and exposes
|
|
2522
|
+
* {@link currentLocale$} for code that prefers an observable (e.g. manual subscriptions).
|
|
2523
|
+
* Templates usually use {@link AXPResolveMultiLanguageStringPipe} instead.
|
|
2159
2524
|
*/
|
|
2160
|
-
class
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2525
|
+
class AXPMultiLanguageStringResolverService {
|
|
2526
|
+
constructor() {
|
|
2527
|
+
//#region ---- Services & Dependencies ----
|
|
2528
|
+
this.translation = inject(AXTranslationService);
|
|
2529
|
+
//#endregion
|
|
2530
|
+
//#region ---- Locale stream ----
|
|
2531
|
+
/**
|
|
2532
|
+
* Emits the active locale on subscribe and whenever the language changes.
|
|
2533
|
+
*/
|
|
2534
|
+
this.currentLocale$ = merge$1(of(this.translation.getActiveLang()), this.translation.langChanges$).pipe(map(() => this.translation.getActiveLang()), distinctUntilChanged());
|
|
2535
|
+
}
|
|
2536
|
+
//#endregion
|
|
2537
|
+
//#region ---- Resolve ----
|
|
2538
|
+
/**
|
|
2539
|
+
* Resolves multi-language content for an optional locale (defaults to active).
|
|
2540
|
+
*/
|
|
2541
|
+
resolve(content, locale) {
|
|
2542
|
+
if (content && typeof content === 'object' && !isValidMultiLanguageObject(content)) {
|
|
2543
|
+
return '';
|
|
2544
|
+
}
|
|
2545
|
+
return resolveMultiLanguageString(content, locale ?? this.translation.getActiveLang());
|
|
2546
|
+
}
|
|
2547
|
+
/**
|
|
2548
|
+
* Checks if a value is a valid multi-language object map.
|
|
2549
|
+
* Key format must be `xx-XX` (e.g. en-US, fa-IR) or fallback `*-*`.
|
|
2550
|
+
* All values must be strings.
|
|
2551
|
+
*/
|
|
2552
|
+
isValidMultiLanguageObject(value) {
|
|
2553
|
+
return isValidMultiLanguageObject(value);
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Normalizes multi-language content to a locale map for editors (e.g. multi-language popup `values`).
|
|
2557
|
+
* If `content` is already a locale-to-string map, returns a shallow copy.
|
|
2558
|
+
* If it is a plain string or empty, wraps it as `{ [activeLocale]: text }`.
|
|
2559
|
+
*/
|
|
2560
|
+
toLocaleMap(content, activeLocale) {
|
|
2561
|
+
if (this.isValidMultiLanguageObject(content)) {
|
|
2562
|
+
return { ...content };
|
|
2563
|
+
}
|
|
2564
|
+
const txt = typeof content === 'string' ? content : '';
|
|
2565
|
+
return { [activeLocale]: txt };
|
|
2165
2566
|
}
|
|
2166
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2167
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2567
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPMultiLanguageStringResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2568
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPMultiLanguageStringResolverService, providedIn: 'root' }); }
|
|
2168
2569
|
}
|
|
2169
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2570
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPMultiLanguageStringResolverService, decorators: [{
|
|
2170
2571
|
type: Injectable,
|
|
2171
2572
|
args: [{ providedIn: 'root' }]
|
|
2172
2573
|
}] });
|
|
2574
|
+
|
|
2575
|
+
//#region ---- Imports ----
|
|
2576
|
+
//#endregion
|
|
2577
|
+
//#region ---- AXPResolveMultiLanguageStringPipe ----
|
|
2578
|
+
/**
|
|
2579
|
+
* Resolves {@link AXPMultiLanguageString} via {@link AXPMultiLanguageStringResolverService}.
|
|
2580
|
+
* Impure and subscribes to {@link AXPMultiLanguageStringResolverService#currentLocale$} so
|
|
2581
|
+
* OnPush hosts (e.g. grid cells) still refresh when the language changes.
|
|
2582
|
+
*
|
|
2583
|
+
* Optional second argument: explicit locale (e.g. from a host `locale` input). When omitted or null/empty,
|
|
2584
|
+
* the active language is used.
|
|
2585
|
+
*
|
|
2586
|
+
* @example
|
|
2587
|
+
* ```html
|
|
2588
|
+
* {{ value | axpResolveMultiLanguageString }}
|
|
2589
|
+
* {{ value | axpResolveMultiLanguageString: locale() }}
|
|
2590
|
+
* ```
|
|
2591
|
+
*/
|
|
2592
|
+
class AXPResolveMultiLanguageStringPipe {
|
|
2593
|
+
constructor() {
|
|
2594
|
+
this.resolver = inject(AXPMultiLanguageStringResolverService);
|
|
2595
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
2596
|
+
this.localeSubscription = this.resolver.currentLocale$.subscribe(() => this.cdr.markForCheck());
|
|
2597
|
+
}
|
|
2598
|
+
transform(value, locale) {
|
|
2599
|
+
const explicitLocale = locale != null && locale !== '' ? locale : undefined;
|
|
2600
|
+
return this.resolver.resolve(value, explicitLocale);
|
|
2601
|
+
}
|
|
2602
|
+
ngOnDestroy() {
|
|
2603
|
+
this.localeSubscription.unsubscribe();
|
|
2604
|
+
}
|
|
2605
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPResolveMultiLanguageStringPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
2606
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPResolveMultiLanguageStringPipe, isStandalone: true, name: "axpResolveMultiLanguageString", pure: false }); }
|
|
2607
|
+
}
|
|
2608
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPResolveMultiLanguageStringPipe, decorators: [{
|
|
2609
|
+
type: Pipe,
|
|
2610
|
+
args: [{
|
|
2611
|
+
name: 'axpResolveMultiLanguageString',
|
|
2612
|
+
standalone: true,
|
|
2613
|
+
pure: false,
|
|
2614
|
+
}]
|
|
2615
|
+
}] });
|
|
2616
|
+
|
|
2617
|
+
//#region ---- Imports ----
|
|
2173
2618
|
//#endregion
|
|
2174
|
-
//#region ----
|
|
2619
|
+
//#region ---- Compare & sort ----
|
|
2620
|
+
const DEFAULT_COLLATOR_OPTIONS = { sensitivity: 'base' };
|
|
2621
|
+
/**
|
|
2622
|
+
* Locale-aware comparison of {@link AXPMultiLanguageString} values (plain string, `@scope:key`, or locale map).
|
|
2623
|
+
* Resolves each side with {@link resolveMultiLanguageString} for `locale`, then compares with `String#localeCompare`.
|
|
2624
|
+
*/
|
|
2625
|
+
function compareMultiLanguageStrings(a, b, locale, collatorOptions = DEFAULT_COLLATOR_OPTIONS) {
|
|
2626
|
+
const sa = resolveMultiLanguageString(a ?? '', locale);
|
|
2627
|
+
const sb = resolveMultiLanguageString(b ?? '', locale);
|
|
2628
|
+
return sa.localeCompare(sb, locale, collatorOptions);
|
|
2629
|
+
}
|
|
2175
2630
|
/**
|
|
2176
|
-
*
|
|
2177
|
-
* If not provided, DefaultModuleAccessControlService will be used as fallback.
|
|
2631
|
+
* Stable sort copy: orders items by resolved string for `getValue(item)` using the active `locale`.
|
|
2178
2632
|
*/
|
|
2179
|
-
|
|
2633
|
+
function sortByMultiLanguageString(items, getValue, locale, collatorOptions) {
|
|
2634
|
+
return [...items].sort((x, y) => compareMultiLanguageStrings(getValue(x), getValue(y), locale, collatorOptions));
|
|
2635
|
+
}
|
|
2636
|
+
//#endregion
|
|
2180
2637
|
|
|
2181
2638
|
//#region ---- Tag Types ----
|
|
2182
2639
|
//#endregion
|
|
@@ -2329,10 +2786,10 @@ class AXPTagService {
|
|
|
2329
2786
|
const uniqueTags = allTags.filter((tag, index, self) => index === self.findIndex((t) => t.title.toLowerCase() === tag.title.toLowerCase()));
|
|
2330
2787
|
this.cache = uniqueTags;
|
|
2331
2788
|
}
|
|
2332
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
2333
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
2789
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2790
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTagService, providedIn: 'root' }); }
|
|
2334
2791
|
}
|
|
2335
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
2792
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPTagService, decorators: [{
|
|
2336
2793
|
type: Injectable,
|
|
2337
2794
|
args: [{
|
|
2338
2795
|
providedIn: 'root',
|
|
@@ -3264,6 +3721,9 @@ function getNestedKeys(obj, prefix = '') {
|
|
|
3264
3721
|
return keys;
|
|
3265
3722
|
}
|
|
3266
3723
|
|
|
3724
|
+
//#region ---- Imports ----
|
|
3725
|
+
//#endregion
|
|
3726
|
+
|
|
3267
3727
|
function applySystemActionDefault(action, type) {
|
|
3268
3728
|
const systemAction = getSystemActions(type);
|
|
3269
3729
|
return {
|
|
@@ -3295,8 +3755,6 @@ class AXPIconLogoConfig {
|
|
|
3295
3755
|
|
|
3296
3756
|
var AXPPlatformScope;
|
|
3297
3757
|
(function (AXPPlatformScope) {
|
|
3298
|
-
AXPPlatformScope["Environment"] = "C";
|
|
3299
|
-
AXPPlatformScope["Global"] = "G";
|
|
3300
3758
|
AXPPlatformScope["Platform"] = "P";
|
|
3301
3759
|
AXPPlatformScope["Tenant"] = "T";
|
|
3302
3760
|
AXPPlatformScope["User"] = "U";
|
|
@@ -3304,8 +3762,6 @@ var AXPPlatformScope;
|
|
|
3304
3762
|
;
|
|
3305
3763
|
function resolvePlatformScopeKey(name) {
|
|
3306
3764
|
const scopeMap = {
|
|
3307
|
-
environment: AXPPlatformScope.Environment,
|
|
3308
|
-
global: AXPPlatformScope.Global,
|
|
3309
3765
|
platform: AXPPlatformScope.Platform,
|
|
3310
3766
|
tenant: AXPPlatformScope.Tenant,
|
|
3311
3767
|
user: AXPPlatformScope.User,
|
|
@@ -3314,8 +3770,6 @@ function resolvePlatformScopeKey(name) {
|
|
|
3314
3770
|
}
|
|
3315
3771
|
function resolvePlatformScopeName(scope) {
|
|
3316
3772
|
const scopeMap = {
|
|
3317
|
-
C: 'environment',
|
|
3318
|
-
G: 'global',
|
|
3319
3773
|
P: 'platform',
|
|
3320
3774
|
T: 'tenant',
|
|
3321
3775
|
U: 'user',
|
|
@@ -3335,7 +3789,7 @@ var AXPExportTemplateToken;
|
|
|
3335
3789
|
class AXPCountdownPipe {
|
|
3336
3790
|
constructor() {
|
|
3337
3791
|
this.calendarService = inject(AXCalendarService);
|
|
3338
|
-
this.countdownSignal = signal(this.setupTimer(), ...(ngDevMode ? [{ debugName: "countdownSignal" }] : []));
|
|
3792
|
+
this.countdownSignal = signal(this.setupTimer(), ...(ngDevMode ? [{ debugName: "countdownSignal" }] : /* istanbul ignore next */ []));
|
|
3339
3793
|
this.targetDate = 0;
|
|
3340
3794
|
this.prevValue = 0;
|
|
3341
3795
|
}
|
|
@@ -3364,10 +3818,10 @@ class AXPCountdownPipe {
|
|
|
3364
3818
|
updateTargetDate(value) {
|
|
3365
3819
|
this.targetDate = new Date(value).getTime();
|
|
3366
3820
|
}
|
|
3367
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3368
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "
|
|
3821
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPCountdownPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
3822
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPCountdownPipe, isStandalone: true, name: "countdown", pure: false }); }
|
|
3369
3823
|
}
|
|
3370
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
3824
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPCountdownPipe, decorators: [{
|
|
3371
3825
|
type: Pipe,
|
|
3372
3826
|
args: [{
|
|
3373
3827
|
name: 'countdown',
|
|
@@ -3650,45 +4104,45 @@ class AXPDeviceService {
|
|
|
3650
4104
|
/**
|
|
3651
4105
|
* Current screen size (Small, Medium, Large)
|
|
3652
4106
|
*/
|
|
3653
|
-
this.screenSize = signal(getScreenSize(), ...(ngDevMode ? [{ debugName: "screenSize" }] : []));
|
|
4107
|
+
this.screenSize = signal(getScreenSize(), ...(ngDevMode ? [{ debugName: "screenSize" }] : /* istanbul ignore next */ []));
|
|
3654
4108
|
/**
|
|
3655
4109
|
* Current device type (Mobile, Tablet, Desktop)
|
|
3656
4110
|
*/
|
|
3657
|
-
this.deviceType = signal(getDeviceType(), ...(ngDevMode ? [{ debugName: "deviceType" }] : []));
|
|
4111
|
+
this.deviceType = signal(getDeviceType(), ...(ngDevMode ? [{ debugName: "deviceType" }] : /* istanbul ignore next */ []));
|
|
3658
4112
|
/**
|
|
3659
4113
|
* Whether the device supports touch input
|
|
3660
4114
|
*/
|
|
3661
|
-
this.isTouchDevice = signal(isTouchDevice(), ...(ngDevMode ? [{ debugName: "isTouchDevice" }] : []));
|
|
4115
|
+
this.isTouchDevice = signal(isTouchDevice(), ...(ngDevMode ? [{ debugName: "isTouchDevice" }] : /* istanbul ignore next */ []));
|
|
3662
4116
|
//#endregion
|
|
3663
4117
|
//#region ---- Computed Signals ----
|
|
3664
4118
|
/**
|
|
3665
4119
|
* Whether the screen size is Small
|
|
3666
4120
|
*/
|
|
3667
|
-
this.isSmall = computed(() => this.screenSize() === AXPScreenSize.Small, ...(ngDevMode ? [{ debugName: "isSmall" }] : []));
|
|
4121
|
+
this.isSmall = computed(() => this.screenSize() === AXPScreenSize.Small, ...(ngDevMode ? [{ debugName: "isSmall" }] : /* istanbul ignore next */ []));
|
|
3668
4122
|
/**
|
|
3669
4123
|
* Whether the screen size is Medium
|
|
3670
4124
|
*/
|
|
3671
|
-
this.isMedium = computed(() => this.screenSize() === AXPScreenSize.Medium, ...(ngDevMode ? [{ debugName: "isMedium" }] : []));
|
|
4125
|
+
this.isMedium = computed(() => this.screenSize() === AXPScreenSize.Medium, ...(ngDevMode ? [{ debugName: "isMedium" }] : /* istanbul ignore next */ []));
|
|
3672
4126
|
/**
|
|
3673
4127
|
* Whether the screen size is Large
|
|
3674
4128
|
*/
|
|
3675
|
-
this.isLarge = computed(() => this.screenSize() === AXPScreenSize.Large, ...(ngDevMode ? [{ debugName: "isLarge" }] : []));
|
|
4129
|
+
this.isLarge = computed(() => this.screenSize() === AXPScreenSize.Large, ...(ngDevMode ? [{ debugName: "isLarge" }] : /* istanbul ignore next */ []));
|
|
3676
4130
|
/**
|
|
3677
4131
|
* Whether the device is Mobile
|
|
3678
4132
|
*/
|
|
3679
|
-
this.isMobileDevice = computed(() => this.deviceType() === AXPDeviceType.Mobile, ...(ngDevMode ? [{ debugName: "isMobileDevice" }] : []));
|
|
4133
|
+
this.isMobileDevice = computed(() => this.deviceType() === AXPDeviceType.Mobile, ...(ngDevMode ? [{ debugName: "isMobileDevice" }] : /* istanbul ignore next */ []));
|
|
3680
4134
|
/**
|
|
3681
4135
|
* Whether the device is Tablet
|
|
3682
4136
|
*/
|
|
3683
|
-
this.isTabletDevice = computed(() => this.deviceType() === AXPDeviceType.Tablet, ...(ngDevMode ? [{ debugName: "isTabletDevice" }] : []));
|
|
4137
|
+
this.isTabletDevice = computed(() => this.deviceType() === AXPDeviceType.Tablet, ...(ngDevMode ? [{ debugName: "isTabletDevice" }] : /* istanbul ignore next */ []));
|
|
3684
4138
|
/**
|
|
3685
4139
|
* Whether the device is Desktop
|
|
3686
4140
|
*/
|
|
3687
|
-
this.isDesktopDevice = computed(() => this.deviceType() === AXPDeviceType.Desktop, ...(ngDevMode ? [{ debugName: "isDesktopDevice" }] : []));
|
|
4141
|
+
this.isDesktopDevice = computed(() => this.deviceType() === AXPDeviceType.Desktop, ...(ngDevMode ? [{ debugName: "isDesktopDevice" }] : /* istanbul ignore next */ []));
|
|
3688
4142
|
/**
|
|
3689
4143
|
* Whether the device supports touch (alias for isTouchDevice)
|
|
3690
4144
|
*/
|
|
3691
|
-
this.isTouchScreen = computed(() => this.isTouchDevice(), ...(ngDevMode ? [{ debugName: "isTouchScreen" }] : []));
|
|
4145
|
+
this.isTouchScreen = computed(() => this.isTouchDevice(), ...(ngDevMode ? [{ debugName: "isTouchScreen" }] : /* istanbul ignore next */ []));
|
|
3692
4146
|
//#endregion
|
|
3693
4147
|
//#region ---- Private Properties ----
|
|
3694
4148
|
this._resizeListener = null;
|
|
@@ -3754,10 +4208,10 @@ class AXPDeviceService {
|
|
|
3754
4208
|
destroy() {
|
|
3755
4209
|
this._removeResizeListener();
|
|
3756
4210
|
}
|
|
3757
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3758
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
4211
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDeviceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4212
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDeviceService, providedIn: 'root' }); }
|
|
3759
4213
|
}
|
|
3760
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4214
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDeviceService, decorators: [{
|
|
3761
4215
|
type: Injectable,
|
|
3762
4216
|
args: [{
|
|
3763
4217
|
providedIn: 'root',
|
|
@@ -3861,21 +4315,87 @@ class AXHighlightService {
|
|
|
3861
4315
|
resultHTML += '</span>';
|
|
3862
4316
|
return resultHTML;
|
|
3863
4317
|
}
|
|
3864
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
3865
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
4318
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXHighlightService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4319
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXHighlightService, providedIn: 'root' }); }
|
|
3866
4320
|
}
|
|
3867
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
4321
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXHighlightService, decorators: [{
|
|
3868
4322
|
type: Injectable,
|
|
3869
4323
|
args: [{
|
|
3870
4324
|
providedIn: 'root',
|
|
3871
4325
|
}]
|
|
3872
4326
|
}], ctorParameters: () => [] });
|
|
3873
4327
|
|
|
4328
|
+
/**
|
|
4329
|
+
* Creates a provider instance within an injection context.
|
|
4330
|
+
* Handles dynamic import, injector resolution, and provider instantiation.
|
|
4331
|
+
*
|
|
4332
|
+
* @param loader - Function that returns a promise resolving to the provider class
|
|
4333
|
+
* @returns Promise that resolves to the provider instance
|
|
4334
|
+
*
|
|
4335
|
+
* @example
|
|
4336
|
+
* ```typescript
|
|
4337
|
+
* useFactory: () => createProviderWithInjectionContext(() =>
|
|
4338
|
+
* import('./settings.provider').then(m => m.AXMSettingProvider)
|
|
4339
|
+
* )
|
|
4340
|
+
* ```
|
|
4341
|
+
*/
|
|
4342
|
+
async function createProviderWithInjectionContext(loader) {
|
|
4343
|
+
const injector = inject(Injector);
|
|
4344
|
+
const ProviderClass = await loader();
|
|
4345
|
+
return runInInjectionContext(injector, () => new ProviderClass());
|
|
4346
|
+
}
|
|
4347
|
+
/**
|
|
4348
|
+
* Creates a provider configuration for lazy-loaded providers with injection context.
|
|
4349
|
+
* Simplifies provider registration in NgModule providers array.
|
|
4350
|
+
*
|
|
4351
|
+
* @param token - The injection token to provide
|
|
4352
|
+
* @param loader - Function that returns a promise resolving to the provider class
|
|
4353
|
+
* @param multi - Optional. Whether the provider is a multi-provider (array of values). Defaults to `true`. Pass `false` for a single provider.
|
|
4354
|
+
* @returns Provider configuration object
|
|
4355
|
+
*
|
|
4356
|
+
* @example
|
|
4357
|
+
* ```typescript
|
|
4358
|
+
* // Multi-provider (default)
|
|
4359
|
+
* provideLazyProvider(
|
|
4360
|
+
* AXP_DATASOURCE_DEFINITION_PROVIDER,
|
|
4361
|
+
* () => import('./datasource.provider').then(m => m.AXMDataSourceProvider)
|
|
4362
|
+
* )
|
|
4363
|
+
*
|
|
4364
|
+
* // Single provider
|
|
4365
|
+
* provideLazyProvider(
|
|
4366
|
+
* SOME_TOKEN,
|
|
4367
|
+
* () => import('./my.provider').then(m => m.MyProvider),
|
|
4368
|
+
* false
|
|
4369
|
+
* )
|
|
4370
|
+
* ```
|
|
4371
|
+
*/
|
|
4372
|
+
function provideLazyProvider(token, loader, multi = true) {
|
|
4373
|
+
return {
|
|
4374
|
+
provide: token,
|
|
4375
|
+
useFactory: () => createProviderWithInjectionContext(loader),
|
|
4376
|
+
multi,
|
|
4377
|
+
};
|
|
4378
|
+
}
|
|
4379
|
+
|
|
3874
4380
|
function extractTextFromHtml(value) {
|
|
3875
4381
|
const div = document.createElement('div');
|
|
3876
4382
|
div.innerHTML = value;
|
|
3877
4383
|
return div.textContent || div.innerText || '';
|
|
3878
4384
|
}
|
|
4385
|
+
/**
|
|
4386
|
+
* True when the string likely contains HTML markup (e.g. `<p>`, `<ul>`), as opposed to plain text.
|
|
4387
|
+
* Used to choose innerHTML vs text interpolation for multilingual fields.
|
|
4388
|
+
*/
|
|
4389
|
+
function containsHtmlMarkup(value) {
|
|
4390
|
+
if (value == null) {
|
|
4391
|
+
return false;
|
|
4392
|
+
}
|
|
4393
|
+
const t = value.trim();
|
|
4394
|
+
if (!t) {
|
|
4395
|
+
return false;
|
|
4396
|
+
}
|
|
4397
|
+
return /<\/?[a-z][\s\S]*?>/i.test(t);
|
|
4398
|
+
}
|
|
3879
4399
|
/**
|
|
3880
4400
|
* Generate kebab-case group name from title
|
|
3881
4401
|
*/
|
|
@@ -3893,5 +4413,5 @@ function generateKebabCase(title) {
|
|
|
3893
4413
|
* Generated bundle index. Do not edit.
|
|
3894
4414
|
*/
|
|
3895
4415
|
|
|
3896
|
-
export {
|
|
4416
|
+
export { AXHighlightService, AXPActivityLogProvider, AXPActivityLogService, AXPAppStartUpProvider, AXPAppStartUpService, AXPBroadcastEventService, AXPColorPaletteProvider, AXPColorPaletteService, AXPColumnWidthService, AXPComponentLogoConfig, AXPComponentSlot, AXPComponentSlotDirective, AXPComponentSlotModule, AXPComponentSlotRegistryService, AXPContentCheckerDirective, AXPContextChangeEvent, AXPContextStore, AXPCountdownPipe, AXPDataGenerator, AXPDataSourceDefinitionProviderService, AXPDblClickDirective, AXPDefaultColorPalettesProvider, AXPDeviceService, AXPDeviceType, AXPDistributedEventListenerService, AXPElementDataDirective, AXPExportTemplateToken, AXPExpressionEvaluatorScopeProviderContext, AXPExpressionEvaluatorScopeProviderService, AXPExpressionEvaluatorService, AXPFeatureDefinitionProviderContext, AXPGridLayoutDirective, AXPHookService, AXPIconLogoConfig, AXPImageUrlLogoConfig, AXPModuleManifestModule, AXPModuleManifestRegistry, AXPModuleManifestsDataSourceDefinition, AXPMultiLanguageStringResolverService, AXPPlatformScope, AXPResolveMultiLanguageStringPipe, AXPScreenSize, AXPSystemActionType, AXPSystemActions, AXPTagProvider, AXPTagService, AXP_ACTIVITY_LOG_PROVIDER, AXP_COLOR_PALETTE_PROVIDER, AXP_COLUMN_WIDTH_PROVIDER, AXP_DATASOURCE_DEFINITION_PROVIDER, AXP_DISTRIBUTED_EVENT_LISTENER_PROVIDER, AXP_EXPRESSION_EVALUATOR_SCOPE_PROVIDER, AXP_FEATURE_DEFINITION_PROVIDER, AXP_MODULE_MANIFEST_PROVIDER, AXP_SESSION_SERVICE, AXP_TAG_PROVIDER, MODULE_MANIFESTS_DATASOURCE_NAME, applyFilterArray, applyPagination, applyQueryArray, applySortArray, applySystemActionDefault, cleanDeep, compareMultiLanguageStrings, containsHtmlMarkup, createMultiLanguageString, createProviderWithInjectionContext, defaultColumnWidthProvider, extractNestedFieldsWildcard, extractTextFromHtml, extractValue, generateKebabCase, getActionButton, getChangedPaths, getDetailedChanges, getEnumValues, getNestedKeys, getSmart, getSystemActions, isEffectivelyEmptyLocalizedValue, isValidMultiLanguageObject, objectKeyValueTransforms, provideLazyProvider, resolveActionLook, resolveMultiLanguageString, resolvePlatformScopeKey, resolvePlatformScopeName, setSmart, sortByMultiLanguageString };
|
|
3897
4417
|
//# sourceMappingURL=acorex-platform-core.mjs.map
|