@dereekb/dbx-core 14.9.0 → 14.10.0
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/dereekb-dbx-core.mjs +1169 -955
- package/fesm2022/dereekb-dbx-core.mjs.map +1 -1
- package/package.json +5 -5
- package/types/dereekb-dbx-core.d.ts +422 -224
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, inject, Injectable, makeEnvironmentProviders, DestroyRef, input, Directive, computed, signal, forwardRef, effect, TemplateRef, ViewContainerRef, Injector, runInInjectionContext, NgModule, Service, Input, output, model, booleanAttribute, Pipe, LOCALE_ID, viewChild, Component, Inject, Optional } from '@angular/core';
|
|
3
3
|
import { HttpClient } from '@angular/common/http';
|
|
4
|
-
import { defer, switchMap, first, distinctUntilChanged, filter, EMPTY, debounce, interval, throttle, exhaustMap, mergeMap, map, shareReplay, combineLatest, startWith, of, delay, BehaviorSubject, tap, combineLatestWith, catchError, withLatestFrom, firstValueFrom, takeUntil, Subject, Observable } from 'rxjs';
|
|
5
|
-
import { AssetLoader, SubscriptionObject, LockSet, loadingStateContext, listLoadingStateContext, filterMaybe, LoadingStateType, beginLoading, idleLoadingState, errorResult, successResult, scanCount, workFactory, asObservable, combineLatestFromMapValuesObsFn, emitDelayObs, makeIsModifiedFunctionObservable, returnIfIs, timeoutStartWith, onFalseToTrue, onTrueToFalse, setContainsAllValuesFrom, setContainsNoValueFrom, maybeValueFromObservableOrValueGetter, switchMapToDefault, asObservableFromGetter, maybeValueFromObservableOrValue, distinctUntilKeysChange, FilterSource, FilterSourceConnector, FilterSourceInstance, FilterMap, skipAllInitialMaybe, switchMapObject } from '@dereekb/rxjs';
|
|
6
|
-
import { getValueFromGetter, DestroyFunctionObject, isNotFalse, isDefinedAndNotFalse, BooleanStringKeyArrayUtility, reduceBooleansWithOrFn, asGetter, toReadableError, hasValueOrNotEmpty, isGetter, asArray, setIncludes, isAllowed, maybeSet, iterableToSet, IMPERSONATION_URL_QUERY_PARAM, expandTreeFunction, flattenTreeToArrayFunction, expandFlattenTreeFunction, mailToUrlString, telUrlString, mergeObjects, KeyValueTypleValueFilter, filterMaybeArrayValues, defaultForwardFunctionFactory, MINUTES_IN_DAY, MINUTES_IN_HOUR, millisecondsToMinutes, cutString, dollarAmountString,
|
|
4
|
+
import { defer, switchMap, first, distinctUntilChanged, filter, EMPTY, debounce, interval, throttle, exhaustMap, mergeMap, map, shareReplay, combineLatest, startWith, of, delay, BehaviorSubject, tap, combineLatestWith, catchError, withLatestFrom, firstValueFrom, takeUntil, Subject, Observable, skip } from 'rxjs';
|
|
5
|
+
import { AssetLoader, SubscriptionObject, LockSet, loadingStateContext, listLoadingStateContext, filterMaybe, LoadingStateType, beginLoading, idleLoadingState, errorResult, successResult, scanCount, workFactory, asObservable, combineLatestFromMapValuesObsFn, emitDelayObs, makeIsModifiedFunctionObservable, returnIfIs, timeoutStartWith, onFalseToTrue, onTrueToFalse, setContainsAllValuesFrom, setContainsNoValueFrom, maybeValueFromObservableOrValueGetter, switchMapToDefault, asObservableFromGetter, maybeValueFromObservableOrValue, distinctUntilKeysChange, FilterSource, FilterSourceConnector, FilterSourceInstance, FilterMap, distinctUntilObjectValuesChanged, skipAllInitialMaybe, switchMapObject } from '@dereekb/rxjs';
|
|
6
|
+
import { getValueFromGetter, DestroyFunctionObject, isNotFalse, isDefinedAndNotFalse, BooleanStringKeyArrayUtility, reduceBooleansWithOrFn, asGetter, toReadableError, hasValueOrNotEmpty, isGetter, asArray, setIncludes, isAllowed, maybeSet, iterableToSet, IMPERSONATION_URL_QUERY_PARAM, expandTreeFunction, flattenTreeToArrayFunction, expandFlattenTreeFunction, mailToUrlString, telUrlString, mergeObjects, KeyValueTypleValueFilter, filterMaybeArrayValues, defaultForwardFunctionFactory, MINUTES_IN_DAY, MINUTES_IN_HOUR, millisecondsToMinutes, cutString, dollarAmountString, DataIsExpiredError, DataDoesNotExistError, hasNonNullValue, unixDateTimeSecondsNumberForNow, isThrottled, splitJoinRemainder, StorageObjectUtility, objectHasKey, objectHasKeys, safeEqualityComparatorFunction, mergeArrays, flattenArrayOrValueArray, promiseReference, SHARED_MEMORY_STORAGE } from '@dereekb/util';
|
|
7
7
|
import { toObservable, toSignal, outputToObservable } from '@angular/core/rxjs-interop';
|
|
8
8
|
import { ComponentStore } from '@ngrx/component-store';
|
|
9
9
|
import { Actions, ofType, createEffect, provideEffects } from '@ngrx/effects';
|
|
@@ -8225,1196 +8225,1410 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
8225
8225
|
}] });
|
|
8226
8226
|
|
|
8227
8227
|
/**
|
|
8228
|
-
*
|
|
8229
|
-
*
|
|
8230
|
-
* @param preset - The object to check.
|
|
8231
|
-
* @returns `true` if the object has a `presetValue` property.
|
|
8232
|
-
*/
|
|
8233
|
-
function isClickableFilterPreset(preset) {
|
|
8234
|
-
return objectHasKey(preset, 'presetValue');
|
|
8235
|
-
}
|
|
8236
|
-
/**
|
|
8237
|
-
* Type guard that checks if an object is a {@link ClickablePartialFilterPreset}.
|
|
8228
|
+
* Provides a read-only {@link FilterSource} that merges the filters of several keys in an ancestor {@link FilterMap} into one filter. Lets separate filter controls (e.g. a date popover and an attributes popover) each own a key while children consume a single combined filter.
|
|
8238
8229
|
*
|
|
8239
|
-
*
|
|
8240
|
-
* @returns `true` if the object has `partialPresetValue` and `isActive` properties.
|
|
8241
|
-
*/
|
|
8242
|
-
function isClickablePartialFilterPreset(preset) {
|
|
8243
|
-
return objectHasKeys(preset, ['partialPresetValue', 'isActive']);
|
|
8244
|
-
}
|
|
8245
|
-
|
|
8246
|
-
/**
|
|
8247
|
-
* Provides a {@link FilterSource} in DI so child components can inject and consume the current filter value. Use this on a wrapper element when the child is the canonical owner of the filter (a filter form, a chip group).
|
|
8230
|
+
* Keys later in the array win when two keys set the same field, and the merged filter has no `preset`. Every key needs a value (e.g. a default filter) before the merged filter emits.
|
|
8248
8231
|
*
|
|
8249
8232
|
* @dbxFilter
|
|
8250
|
-
* @dbxFilterSlug source
|
|
8251
|
-
* @dbxFilterRelated
|
|
8233
|
+
* @dbxFilterSlug map-merge-source
|
|
8234
|
+
* @dbxFilterRelated map, map-source, map-source-connector
|
|
8252
8235
|
* @dbxFilterSkillRefs dbx__ref__dbx-component-patterns
|
|
8253
8236
|
*
|
|
8254
8237
|
* @example
|
|
8255
8238
|
* ```html
|
|
8256
|
-
* <div
|
|
8257
|
-
* <my-filter-
|
|
8239
|
+
* <div dbxFilterMap>
|
|
8240
|
+
* <my-date-filter-button [dbxFilterMapSourceConnector]="'date'"></my-date-filter-button>
|
|
8241
|
+
* <my-attributes-filter-button [dbxFilterMapSourceConnector]="'attributes'"></my-attributes-filter-button>
|
|
8242
|
+
* <div [dbxFilterMapMergeSource]="['date', 'attributes']">
|
|
8243
|
+
* <my-filtered-list></my-filtered-list>
|
|
8244
|
+
* </div>
|
|
8258
8245
|
* </div>
|
|
8259
8246
|
* ```
|
|
8260
8247
|
*/
|
|
8261
|
-
class
|
|
8262
|
-
|
|
8263
|
-
|
|
8248
|
+
class DbxFilterMapMergeSourceDirective {
|
|
8249
|
+
dbxFilterMap = inject((FilterMap));
|
|
8250
|
+
/**
|
|
8251
|
+
* The map keys to merge, in priority order.
|
|
8252
|
+
*/
|
|
8253
|
+
dbxFilterMapMergeSource = input(/* @ts-ignore */
|
|
8254
|
+
...(ngDevMode ? [undefined, { debugName: "dbxFilterMapMergeSource" }] : /* istanbul ignore next */ []));
|
|
8255
|
+
filterMapKeys$ = toObservable(this.dbxFilterMapMergeSource).pipe(filterMaybe(), distinctUntilObjectValuesChanged());
|
|
8256
|
+
filter$ = this.filterMapKeys$.pipe(switchMap((keys) => this.dbxFilterMap.mergedFilterForKeys(keys)), shareReplay(1));
|
|
8257
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterMapMergeSourceDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
8258
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.4", type: DbxFilterMapMergeSourceDirective, isStandalone: true, selector: "[dbxFilterMapMergeSource]", inputs: { dbxFilterMapMergeSource: { classPropertyName: "dbxFilterMapMergeSource", publicName: "dbxFilterMapMergeSource", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideFilterSource(DbxFilterMapMergeSourceDirective)], exportAs: ["dbxFilterMapMergeSource"], ngImport: i0 });
|
|
8264
8259
|
}
|
|
8265
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
8260
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterMapMergeSourceDirective, decorators: [{
|
|
8266
8261
|
type: Directive,
|
|
8267
8262
|
args: [{
|
|
8268
|
-
selector: '[
|
|
8269
|
-
|
|
8270
|
-
|
|
8271
|
-
}] });
|
|
8272
|
-
|
|
8273
|
-
const importsAndExports = [DbxFilterSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterConnectSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterMapDirective, DbxFilterMapSourceDirective];
|
|
8274
|
-
class DbxCoreFilterModule {
|
|
8275
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
8276
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule, imports: [DbxFilterSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterConnectSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterMapDirective, DbxFilterMapSourceDirective], exports: [DbxFilterSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterConnectSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterMapDirective, DbxFilterMapSourceDirective] });
|
|
8277
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule });
|
|
8278
|
-
}
|
|
8279
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule, decorators: [{
|
|
8280
|
-
type: NgModule,
|
|
8281
|
-
args: [{
|
|
8282
|
-
imports: importsAndExports,
|
|
8283
|
-
exports: importsAndExports
|
|
8263
|
+
selector: '[dbxFilterMapMergeSource]',
|
|
8264
|
+
exportAs: 'dbxFilterMapMergeSource',
|
|
8265
|
+
providers: [provideFilterSource(DbxFilterMapMergeSourceDirective)]
|
|
8284
8266
|
}]
|
|
8285
|
-
}] });
|
|
8267
|
+
}], propDecorators: { dbxFilterMapMergeSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxFilterMapMergeSource", required: false }] }] } });
|
|
8286
8268
|
|
|
8287
8269
|
/**
|
|
8288
|
-
*
|
|
8289
|
-
*
|
|
8290
|
-
* Components created via {@link DbxInjectionComponentConfig} can inject this token
|
|
8291
|
-
* to access the `data` property from their configuration.
|
|
8270
|
+
* Default {@link SimpleStorageAccessorConverter} that uses `JSON.stringify`/`JSON.parse` for conversion.
|
|
8292
8271
|
*
|
|
8293
|
-
* @
|
|
8294
|
-
* ```typescript
|
|
8295
|
-
* // In a dynamically injected component:
|
|
8296
|
-
* readonly data = inject(DBX_INJECTION_COMPONENT_DATA);
|
|
8297
|
-
* ```
|
|
8272
|
+
* @typeParam T - The type of value being converted.
|
|
8298
8273
|
*/
|
|
8299
|
-
|
|
8274
|
+
class StringifySimpleStorageAccessorConverter {
|
|
8275
|
+
stringifyValue(value) {
|
|
8276
|
+
return JSON.stringify(value);
|
|
8277
|
+
}
|
|
8278
|
+
parseValue(data) {
|
|
8279
|
+
return JSON.parse(data);
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
8300
8282
|
/**
|
|
8301
|
-
*
|
|
8302
|
-
*
|
|
8303
|
-
* Compares `componentClass`, `data`, `init`, and `injector` by reference. Does NOT compare
|
|
8304
|
-
* `providers` or `ngModuleRef`, as provider arrays typically change on every list data update
|
|
8305
|
-
* (e.g., with new `DBX_VALUE_LIST_VIEW_ITEM` values) without requiring component recreation.
|
|
8283
|
+
* Composes a {@link StorageAccessor} and a {@link SimpleStorageAccessorConverter} into a single
|
|
8284
|
+
* {@link SimpleStorageAccessorDelegate} implementation.
|
|
8306
8285
|
*
|
|
8307
|
-
*
|
|
8308
|
-
* `null === undefined` is `false`). The comparator is only invoked when both are non-nullish.
|
|
8286
|
+
* @typeParam T - The type of value being stored.
|
|
8309
8287
|
*/
|
|
8310
|
-
|
|
8288
|
+
class WrapperSimpleStorageAccessorDelegate {
|
|
8289
|
+
_delegate;
|
|
8290
|
+
_converter;
|
|
8291
|
+
constructor(delegate, converter) {
|
|
8292
|
+
this._delegate = delegate;
|
|
8293
|
+
this._converter = converter;
|
|
8294
|
+
}
|
|
8295
|
+
get(key) {
|
|
8296
|
+
return this._delegate.get(key);
|
|
8297
|
+
}
|
|
8298
|
+
set(key, value) {
|
|
8299
|
+
return this._delegate.set(key, value);
|
|
8300
|
+
}
|
|
8301
|
+
remove(key) {
|
|
8302
|
+
return this._delegate.remove(key);
|
|
8303
|
+
}
|
|
8304
|
+
clear() {
|
|
8305
|
+
return this._delegate.clear();
|
|
8306
|
+
}
|
|
8307
|
+
all(prefix) {
|
|
8308
|
+
return this._delegate.all(prefix);
|
|
8309
|
+
}
|
|
8310
|
+
allKeys(prefix) {
|
|
8311
|
+
return this._delegate.allKeys(prefix);
|
|
8312
|
+
}
|
|
8313
|
+
stringifyValue(value) {
|
|
8314
|
+
return this._converter.stringifyValue(value);
|
|
8315
|
+
}
|
|
8316
|
+
parseValue(data) {
|
|
8317
|
+
return this._converter.parseValue(data);
|
|
8318
|
+
}
|
|
8319
|
+
}
|
|
8311
8320
|
/**
|
|
8312
|
-
*
|
|
8313
|
-
*
|
|
8314
|
-
* Provider arrays are concatenated so that all providers from all configs are preserved.
|
|
8315
|
-
* All other properties are merged with later values taking precedence.
|
|
8321
|
+
* Validates that a storage key prefix is non-empty and does not contain the prefix splitter character.
|
|
8316
8322
|
*
|
|
8317
|
-
* @param
|
|
8318
|
-
* @
|
|
8323
|
+
* @param prefix - The prefix string to validate.
|
|
8324
|
+
* @param prefixSplitter - The splitter string that separates the prefix from the key.
|
|
8325
|
+
* @throws {Error} If the prefix is invalid or the splitter is empty.
|
|
8319
8326
|
*/
|
|
8320
|
-
function
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8327
|
+
function assertValidStorageKeyPrefix(prefix, prefixSplitter) {
|
|
8328
|
+
if (!prefixSplitter) {
|
|
8329
|
+
throw new Error('Invalid storage key prefix splitter. Must be defined and not empty.'); // TODO(FUTURE): Consider changing to a concrete error type
|
|
8330
|
+
}
|
|
8331
|
+
if (!isValidStorageKeyPrefix(prefix, prefixSplitter)) {
|
|
8332
|
+
throw new Error('Invalid storage key prefix.');
|
|
8333
|
+
}
|
|
8325
8334
|
}
|
|
8326
|
-
|
|
8327
8335
|
/**
|
|
8328
|
-
*
|
|
8329
|
-
*
|
|
8330
|
-
* Each argument can be a single `StaticProvider`, an array of providers, or `undefined`/`null`.
|
|
8331
|
-
* All values are flattened into a single array with nullish entries removed.
|
|
8332
|
-
*
|
|
8333
|
-
* @param providers - Any number of provider values or arrays to merge.
|
|
8334
|
-
* @returns A flat array of all non-nullish static providers.
|
|
8336
|
+
* Checks whether a storage key prefix is valid (non-empty and does not contain the splitter).
|
|
8335
8337
|
*
|
|
8336
|
-
* @
|
|
8337
|
-
*
|
|
8338
|
-
*
|
|
8339
|
-
* { provide: TOKEN_A, useValue: 'a' },
|
|
8340
|
-
* undefined,
|
|
8341
|
-
* [{ provide: TOKEN_B, useValue: 'b' }]
|
|
8342
|
-
* );
|
|
8343
|
-
* // Result: [{ provide: TOKEN_A, useValue: 'a' }, { provide: TOKEN_B, useValue: 'b' }]
|
|
8344
|
-
* ```
|
|
8338
|
+
* @param prefix - The prefix string to validate.
|
|
8339
|
+
* @param prefixSpltter - The splitter string that separates the prefix from the key.
|
|
8340
|
+
* @returns `true` if the prefix is valid.
|
|
8345
8341
|
*/
|
|
8346
|
-
function
|
|
8347
|
-
return
|
|
8342
|
+
function isValidStorageKeyPrefix(prefix, prefixSpltter) {
|
|
8343
|
+
return Boolean(prefix?.indexOf(prefixSpltter) === -1);
|
|
8348
8344
|
}
|
|
8349
8345
|
/**
|
|
8350
|
-
*
|
|
8351
|
-
*
|
|
8346
|
+
* Full-featured {@link StorageAccessor} that adds key namespacing, JSON serialization,
|
|
8347
|
+
* and optional time-based expiration on top of a raw string storage backend.
|
|
8352
8348
|
*
|
|
8353
|
-
*
|
|
8349
|
+
* Values are stored as JSON with metadata (timestamp) and automatically checked
|
|
8350
|
+
* for expiration on read.
|
|
8354
8351
|
*
|
|
8355
|
-
* @
|
|
8356
|
-
*
|
|
8352
|
+
* @typeParam T - The type of values stored.
|
|
8353
|
+
*
|
|
8354
|
+
* @throws {DataDoesNotExistError} When reading a key that does not exist.
|
|
8355
|
+
* @throws {DataIsExpiredError} When reading a key whose stored data has expired.
|
|
8357
8356
|
*
|
|
8358
8357
|
* @example
|
|
8359
8358
|
* ```typescript
|
|
8360
|
-
* const
|
|
8361
|
-
*
|
|
8362
|
-
*
|
|
8359
|
+
* const accessor = factory.createStorageAccessor<UserSettings>({
|
|
8360
|
+
* prefix: 'user_prefs',
|
|
8361
|
+
* expiresIn: 3600000,
|
|
8363
8362
|
* });
|
|
8363
|
+
*
|
|
8364
|
+
* accessor.set('theme', { dark: true }).subscribe();
|
|
8365
|
+
* accessor.get('theme').subscribe(settings => console.log(settings));
|
|
8364
8366
|
* ```
|
|
8365
|
-
* @__NO_SIDE_EFFECTS__
|
|
8366
8367
|
*/
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8368
|
+
class SimpleStorageAccessor {
|
|
8369
|
+
static PREFIX_SPLITTER = '::';
|
|
8370
|
+
_delegate;
|
|
8371
|
+
_config;
|
|
8372
|
+
constructor(delegate, config) {
|
|
8373
|
+
const prefix = config.prefix;
|
|
8374
|
+
const prefixSplitter = config.prefixSplitter ?? SimpleStorageAccessor.PREFIX_SPLITTER;
|
|
8375
|
+
assertValidStorageKeyPrefix(prefix, prefixSplitter);
|
|
8376
|
+
const fullPrefix = `${prefix}${prefixSplitter}`;
|
|
8377
|
+
this._delegate = delegate;
|
|
8378
|
+
this._config = {
|
|
8379
|
+
...config,
|
|
8380
|
+
prefixSplitter,
|
|
8381
|
+
fullPrefix
|
|
8382
|
+
};
|
|
8374
8383
|
}
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
parent,
|
|
8378
|
-
providers: mergeStaticProviders({ provide: DBX_INJECTION_COMPONENT_DATA, useValue: data }, providers)
|
|
8379
|
-
});
|
|
8384
|
+
get delegate() {
|
|
8385
|
+
return this._delegate;
|
|
8380
8386
|
}
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
/**
|
|
8384
|
-
* Runs the init callback from a {@link DbxInjectionComponentConfig} on the given component ref,
|
|
8385
|
-
* executing within the component's injection context so that `inject()` is available inside the callback.
|
|
8386
|
-
*
|
|
8387
|
-
* @param componentRef - The component reference whose instance will be passed to the init callback.
|
|
8388
|
-
* @param config - The injection component config containing the optional init callback.
|
|
8389
|
-
*
|
|
8390
|
-
* @example
|
|
8391
|
-
* ```typescript
|
|
8392
|
-
* const ref = viewContainerRef.createComponent(config.componentClass, { injector });
|
|
8393
|
-
* initInjectionComponent(ref, config);
|
|
8394
|
-
* ```
|
|
8395
|
-
*/
|
|
8396
|
-
function initInjectionComponent(componentRef, config) {
|
|
8397
|
-
const { init } = config;
|
|
8398
|
-
if (init) {
|
|
8399
|
-
runInInjectionContext(componentRef.injector, () => init(componentRef.instance));
|
|
8387
|
+
get config() {
|
|
8388
|
+
return this._config;
|
|
8400
8389
|
}
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
* @see {@link AbstractDbxInjectionDirective}
|
|
8421
|
-
*/
|
|
8422
|
-
class DbxInjectionInstance {
|
|
8423
|
-
_subscriptionObject = new SubscriptionObject();
|
|
8424
|
-
_config = new BehaviorSubject(undefined);
|
|
8425
|
-
_template = new BehaviorSubject(undefined);
|
|
8426
|
-
_content = new BehaviorSubject(undefined);
|
|
8427
|
-
_componentRef = new BehaviorSubject(undefined);
|
|
8428
|
-
_injector;
|
|
8429
|
-
config$ = this._config.pipe(maybeValueFromObservableOrValueGetter(), distinctUntilChanged(dbxInjectionComponentConfigIsEqual), shareReplay(1));
|
|
8430
|
-
template$ = this._template.pipe(maybeValueFromObservableOrValueGetter(), distinctUntilChanged(), shareReplay(1));
|
|
8431
|
-
content$ = this._content.pipe(filterMaybe(), distinctUntilChanged(), shareReplay(1));
|
|
8432
|
-
get config() {
|
|
8433
|
-
return this._config.value;
|
|
8434
|
-
}
|
|
8435
|
-
set config(config) {
|
|
8436
|
-
this._config.next(config);
|
|
8390
|
+
// MARK: LimitedStorageAccessor
|
|
8391
|
+
get(inputKey) {
|
|
8392
|
+
const storeKey = this.makeStorageKey(inputKey);
|
|
8393
|
+
return this._delegate.get(storeKey).pipe(map((storedData) => {
|
|
8394
|
+
let result;
|
|
8395
|
+
if (storedData) {
|
|
8396
|
+
const readStoredData = this.readStoredData(storedData);
|
|
8397
|
+
if (readStoredData.expired) {
|
|
8398
|
+
throw new DataIsExpiredError(readStoredData);
|
|
8399
|
+
}
|
|
8400
|
+
else {
|
|
8401
|
+
result = readStoredData.convertedData;
|
|
8402
|
+
}
|
|
8403
|
+
}
|
|
8404
|
+
else {
|
|
8405
|
+
throw new DataDoesNotExistError();
|
|
8406
|
+
}
|
|
8407
|
+
return result;
|
|
8408
|
+
}));
|
|
8437
8409
|
}
|
|
8438
|
-
|
|
8439
|
-
|
|
8410
|
+
set(inputKey, inputValue) {
|
|
8411
|
+
const storeKey = this.makeStorageKey(inputKey);
|
|
8412
|
+
const storeData = this.buildStoredData(inputValue);
|
|
8413
|
+
const data = JSON.stringify(storeData);
|
|
8414
|
+
return this._delegate.set(storeKey, data);
|
|
8440
8415
|
}
|
|
8441
|
-
|
|
8442
|
-
this.
|
|
8416
|
+
remove(key) {
|
|
8417
|
+
const storeKey = this.makeStorageKey(key);
|
|
8418
|
+
return this._delegate.remove(storeKey);
|
|
8443
8419
|
}
|
|
8444
|
-
|
|
8445
|
-
return this.
|
|
8420
|
+
all() {
|
|
8421
|
+
return this._delegate.all(this._config.fullPrefix).pipe(map((allStoredData) => {
|
|
8422
|
+
return allStoredData
|
|
8423
|
+
.map((storedData) => {
|
|
8424
|
+
const readStoredData = this.readStoredData(storedData);
|
|
8425
|
+
return readStoredData.expired ? null : readStoredData.convertedData;
|
|
8426
|
+
})
|
|
8427
|
+
.filter(hasNonNullValue);
|
|
8428
|
+
}));
|
|
8446
8429
|
}
|
|
8447
|
-
|
|
8448
|
-
this.
|
|
8430
|
+
allKeys() {
|
|
8431
|
+
return this._delegate.allKeys(this._config.fullPrefix).pipe(map((keys) => keys.map((x) => this.decodeStorageKey(x))));
|
|
8449
8432
|
}
|
|
8450
|
-
|
|
8451
|
-
return this.
|
|
8433
|
+
clear() {
|
|
8434
|
+
return this._delegate.clear();
|
|
8452
8435
|
}
|
|
8453
|
-
|
|
8454
|
-
|
|
8436
|
+
// MARK: Stored Values
|
|
8437
|
+
readStoredData(storedDataString) {
|
|
8438
|
+
const storedData = JSON.parse(storedDataString);
|
|
8439
|
+
const expired = this.isExpiredStoredData(storedData);
|
|
8440
|
+
const convertedData = this._delegate.parseValue(storedData.data);
|
|
8441
|
+
return {
|
|
8442
|
+
...storedData,
|
|
8443
|
+
expired,
|
|
8444
|
+
convertedData
|
|
8445
|
+
};
|
|
8455
8446
|
}
|
|
8456
|
-
|
|
8457
|
-
|
|
8447
|
+
buildStoredData(value) {
|
|
8448
|
+
return {
|
|
8449
|
+
storedAt: unixDateTimeSecondsNumberForNow(),
|
|
8450
|
+
data: this.stringifyValue(value)
|
|
8451
|
+
};
|
|
8458
8452
|
}
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
this._subscriptionObject.subscription = combineLatest([configTemplateObs, this.content$]).subscribe(([inputConfig, content]) => {
|
|
8466
|
-
const { config, template } = inputConfig ?? {};
|
|
8467
|
-
this._reset(content);
|
|
8468
|
-
if (config) {
|
|
8469
|
-
this._initComponent(config, content);
|
|
8453
|
+
isExpiredStoredData(storeData) {
|
|
8454
|
+
const expiresIn = this._config.expiresIn;
|
|
8455
|
+
let result;
|
|
8456
|
+
if (expiresIn) {
|
|
8457
|
+
if (storeData.storedAt) {
|
|
8458
|
+
result = isThrottled(expiresIn, storeData.storedAt);
|
|
8470
8459
|
}
|
|
8471
|
-
else
|
|
8472
|
-
|
|
8460
|
+
else {
|
|
8461
|
+
result = true;
|
|
8473
8462
|
}
|
|
8474
|
-
}
|
|
8463
|
+
}
|
|
8464
|
+
else {
|
|
8465
|
+
result = false;
|
|
8466
|
+
}
|
|
8467
|
+
return result;
|
|
8475
8468
|
}
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
this._config.
|
|
8479
|
-
this._template.complete();
|
|
8480
|
-
this._content.complete();
|
|
8481
|
-
this._componentRef.complete();
|
|
8469
|
+
// MARK: Internal
|
|
8470
|
+
makeStorageKey(key) {
|
|
8471
|
+
return `${this._config.prefix}${this._config.prefixSplitter}${String(key)}`;
|
|
8482
8472
|
}
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
const { componentClass, ngModuleRef } = config;
|
|
8486
|
-
if (!componentClass) {
|
|
8487
|
-
throw new Error('DbxInjectionInstance: componentClass was expected in the config but it was unavailable.');
|
|
8488
|
-
}
|
|
8489
|
-
const injector = createInjectorForInjectionComponentConfig({ config, parentInjector: this._injector });
|
|
8490
|
-
const componentRef = content.createComponent(componentClass, { injector, ngModuleRef });
|
|
8491
|
-
initInjectionComponent(componentRef, config);
|
|
8492
|
-
this.componentRef = componentRef;
|
|
8473
|
+
isKeyOfAccessor(storageKey) {
|
|
8474
|
+
return storageKey.startsWith(this._config.fullPrefix);
|
|
8493
8475
|
}
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
if (templateRef) {
|
|
8498
|
-
content.createEmbeddedView(templateRef);
|
|
8499
|
-
// TODO: Figure out if these items need to be destroyed or not when this item is destroyed. If so, we need a reference to destroy.
|
|
8500
|
-
}
|
|
8501
|
-
else if (viewRef) {
|
|
8502
|
-
content.insert(viewRef);
|
|
8503
|
-
}
|
|
8476
|
+
decodeStorageKey(storageKey) {
|
|
8477
|
+
const split = splitJoinRemainder(storageKey, this._config.prefixSplitter, 2);
|
|
8478
|
+
return split[1];
|
|
8504
8479
|
}
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
content.clear();
|
|
8508
|
-
this.componentRef = undefined;
|
|
8509
|
-
}
|
|
8480
|
+
stringifyValue(value) {
|
|
8481
|
+
return this._delegate.stringifyValue(value);
|
|
8510
8482
|
}
|
|
8511
8483
|
}
|
|
8512
8484
|
|
|
8513
8485
|
/**
|
|
8514
|
-
*
|
|
8515
|
-
*
|
|
8516
|
-
* Manages a {@link DbxInjectionInstance} lifecycle, initializing it on `ngOnInit` and
|
|
8517
|
-
* destroying it on `ngOnDestroy`. Subclasses are responsible for wiring their inputs
|
|
8518
|
-
* (config, template, content) to the corresponding setter methods.
|
|
8486
|
+
* {@link StorageAccessor} implementation that wraps a {@link FullStorageObject} and stores raw strings.
|
|
8519
8487
|
*
|
|
8520
|
-
*
|
|
8488
|
+
* Each operation completes synchronously within an observable wrapper.
|
|
8521
8489
|
*
|
|
8522
|
-
* @
|
|
8523
|
-
*
|
|
8490
|
+
* @example
|
|
8491
|
+
* ```typescript
|
|
8492
|
+
* const accessor = new StringStorageAccessor(localStorage);
|
|
8493
|
+
* accessor.set('key', 'value').subscribe();
|
|
8494
|
+
* accessor.get('key').subscribe(value => console.log(value)); // 'value'
|
|
8495
|
+
* ```
|
|
8524
8496
|
*/
|
|
8525
|
-
class
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
this.
|
|
8497
|
+
class StringStorageAccessor {
|
|
8498
|
+
_storage;
|
|
8499
|
+
constructor(storage) {
|
|
8500
|
+
this._storage = storage;
|
|
8529
8501
|
}
|
|
8530
|
-
|
|
8531
|
-
|
|
8502
|
+
get(key) {
|
|
8503
|
+
return new Observable((x) => {
|
|
8504
|
+
const value = this._storage.getItem(key);
|
|
8505
|
+
x.next(value);
|
|
8506
|
+
x.complete();
|
|
8507
|
+
});
|
|
8532
8508
|
}
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
this._instance.config = config;
|
|
8509
|
+
set(key, value) {
|
|
8510
|
+
return new Observable((x) => {
|
|
8511
|
+
this._storage.setItem(key, value);
|
|
8512
|
+
x.next();
|
|
8513
|
+
x.complete();
|
|
8514
|
+
});
|
|
8540
8515
|
}
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
this._instance.template = template;
|
|
8516
|
+
remove(key) {
|
|
8517
|
+
return new Observable((x) => {
|
|
8518
|
+
this._storage.removeItem(key);
|
|
8519
|
+
x.next();
|
|
8520
|
+
x.complete();
|
|
8521
|
+
});
|
|
8548
8522
|
}
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8523
|
+
clear() {
|
|
8524
|
+
const removed = this._storage.removeAll();
|
|
8525
|
+
return new Observable((x) => {
|
|
8526
|
+
x.next(removed);
|
|
8527
|
+
x.complete();
|
|
8528
|
+
});
|
|
8529
|
+
}
|
|
8530
|
+
all() {
|
|
8531
|
+
return this.allKeys().pipe(map((x) => filterMaybeArrayValues(x.map((y) => this._storage.getItem(y)))), shareReplay(1));
|
|
8532
|
+
}
|
|
8533
|
+
allKeys() {
|
|
8534
|
+
return new Observable((x) => {
|
|
8535
|
+
const result = StorageObjectUtility.allKeysFromStorageObject(this._storage);
|
|
8536
|
+
x.next(result);
|
|
8537
|
+
x.complete();
|
|
8538
|
+
});
|
|
8556
8539
|
}
|
|
8557
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractDbxInjectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
8558
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: AbstractDbxInjectionDirective, isStandalone: true, ngImport: i0 });
|
|
8559
8540
|
}
|
|
8560
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractDbxInjectionDirective, decorators: [{
|
|
8561
|
-
type: Directive
|
|
8562
|
-
}] });
|
|
8563
8541
|
|
|
8564
8542
|
/**
|
|
8565
|
-
*
|
|
8566
|
-
*
|
|
8567
|
-
* Accepts a {@link DbxInjectionComponentConfig} (to create a component) or a
|
|
8568
|
-
* {@link DbxInjectionTemplateConfig} (to embed a template/view). When the config changes,
|
|
8569
|
-
* the previous content is destroyed and the new content is created in its place.
|
|
8543
|
+
* DI token for the application's default {@link FullStorageObject} instance.
|
|
8570
8544
|
*
|
|
8571
|
-
*
|
|
8572
|
-
|
|
8545
|
+
* Provided by {@link provideDbxStorage}.
|
|
8546
|
+
*/
|
|
8547
|
+
const DEFAULT_STORAGE_OBJECT_TOKEN = new InjectionToken('DBX_CORE_DEFAULT_STORAGE_OBJECT');
|
|
8548
|
+
/**
|
|
8549
|
+
* DI token for the application's default {@link SimpleStorageAccessorFactory} instance.
|
|
8573
8550
|
*
|
|
8574
|
-
*
|
|
8551
|
+
* Provided by {@link provideDbxStorage}.
|
|
8552
|
+
*/
|
|
8553
|
+
const DEFAULT_STORAGE_ACCESSOR_FACTORY_TOKEN = new InjectionToken('DBX_CORE_DEFAULT_STORAGE_ACCESSOR_FACTORY');
|
|
8554
|
+
|
|
8555
|
+
/**
|
|
8556
|
+
* Injectable factory for creating namespaced {@link SimpleStorageAccessor} instances
|
|
8557
|
+
* backed by the application's default storage object.
|
|
8575
8558
|
*
|
|
8576
8559
|
* @example
|
|
8577
|
-
* ```
|
|
8578
|
-
*
|
|
8579
|
-
*
|
|
8580
|
-
*
|
|
8581
|
-
*
|
|
8582
|
-
* <dbx-injection [template]="myTemplateConfig"></dbx-injection>
|
|
8560
|
+
* ```typescript
|
|
8561
|
+
* @Injectable()
|
|
8562
|
+
* export class UserPrefsService {
|
|
8563
|
+
* private readonly storage = inject(SimpleStorageAccessorFactory)
|
|
8564
|
+
* .createStorageAccessor<UserPrefs>({ prefix: 'user_prefs' });
|
|
8583
8565
|
*
|
|
8584
|
-
*
|
|
8585
|
-
*
|
|
8566
|
+
* save(prefs: UserPrefs) { return this.storage.set('current', prefs); }
|
|
8567
|
+
* load() { return this.storage.get('current'); }
|
|
8568
|
+
* }
|
|
8586
8569
|
* ```
|
|
8570
|
+
*/
|
|
8571
|
+
class SimpleStorageAccessorFactory {
|
|
8572
|
+
storageObject = inject(DEFAULT_STORAGE_OBJECT_TOKEN);
|
|
8573
|
+
createStorageAccessor(config) {
|
|
8574
|
+
const storage = config.storage ?? new StringStorageAccessor(this.storageObject);
|
|
8575
|
+
const converter = config.converter ?? new StringifySimpleStorageAccessorConverter();
|
|
8576
|
+
const delegate = new WrapperSimpleStorageAccessorDelegate(storage, converter);
|
|
8577
|
+
const accessorConfig = {
|
|
8578
|
+
prefix: config.prefix
|
|
8579
|
+
};
|
|
8580
|
+
return new SimpleStorageAccessor(delegate, accessorConfig);
|
|
8581
|
+
}
|
|
8582
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: SimpleStorageAccessorFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
8583
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: SimpleStorageAccessorFactory });
|
|
8584
|
+
}
|
|
8585
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: SimpleStorageAccessorFactory, decorators: [{
|
|
8586
|
+
type: Injectable
|
|
8587
|
+
}] });
|
|
8588
|
+
|
|
8589
|
+
/**
|
|
8590
|
+
* Default storage key prefix used by {@link DbxFilterStorageService}.
|
|
8591
|
+
*/
|
|
8592
|
+
const DEFAULT_DBX_FILTER_STORAGE_PREFIX = 'dbxf';
|
|
8593
|
+
/**
|
|
8594
|
+
* Optional injection token for the {@link DbxFilterStorageServiceConfig}.
|
|
8595
|
+
*/
|
|
8596
|
+
const DBX_FILTER_STORAGE_SERVICE_CONFIG_TOKEN = new InjectionToken('DbxFilterStorageServiceConfig');
|
|
8597
|
+
/**
|
|
8598
|
+
* Saves and loads filters to storage (localStorage by default, via {@link SimpleStorageAccessorFactory}).
|
|
8587
8599
|
*
|
|
8588
|
-
*
|
|
8589
|
-
*
|
|
8590
|
-
* @
|
|
8600
|
+
* Filters are saved as JSON. Filters with fields that JSON cannot represent, such as Date or Set fields, pass a {@link FilterJsonConverter}.
|
|
8601
|
+
*
|
|
8602
|
+
* To save and load the filter of a {@link FilterMap} key, use the {@link DbxFilterMapStorageDirective} in the template instead of calling this service directly.
|
|
8603
|
+
*
|
|
8604
|
+
* Provided by {@link provideDbxFilterStorage}, which requires {@link provideDbxStorage}.
|
|
8591
8605
|
*/
|
|
8592
|
-
class
|
|
8606
|
+
class DbxFilterStorageService {
|
|
8607
|
+
storageAccessorFactory = inject(SimpleStorageAccessorFactory);
|
|
8608
|
+
config = inject(DBX_FILTER_STORAGE_SERVICE_CONFIG_TOKEN, { optional: true });
|
|
8609
|
+
prefix = this.config?.prefix ?? DEFAULT_DBX_FILTER_STORAGE_PREFIX;
|
|
8610
|
+
storageAccessor = this.storageAccessorFactory.createStorageAccessor({
|
|
8611
|
+
prefix: this.prefix
|
|
8612
|
+
});
|
|
8593
8613
|
/**
|
|
8594
|
-
*
|
|
8614
|
+
* Loads the saved filter for the given storage key.
|
|
8615
|
+
*
|
|
8616
|
+
* @param storageKey - Key the filter was saved under.
|
|
8617
|
+
* @param jsonConverter - Converts the saved JSON value back to the filter. Without one, the saved value is returned as-is.
|
|
8618
|
+
* @returns Observable of the saved filter, or undefined if nothing is saved or the saved value cannot be read.
|
|
8595
8619
|
*/
|
|
8596
|
-
|
|
8620
|
+
loadFilter(storageKey, jsonConverter) {
|
|
8621
|
+
return this.storageAccessor.get(storageKey).pipe(map((json) => {
|
|
8622
|
+
let result;
|
|
8623
|
+
if (json != null) {
|
|
8624
|
+
result = jsonConverter ? jsonConverter.fromJson(json) : json;
|
|
8625
|
+
}
|
|
8626
|
+
return result;
|
|
8627
|
+
}), catchError(() => of(undefined)));
|
|
8628
|
+
}
|
|
8597
8629
|
/**
|
|
8598
|
-
*
|
|
8630
|
+
* Saves the filter under the given storage key.
|
|
8631
|
+
*
|
|
8632
|
+
* @param storageKey - Key to save the filter under.
|
|
8633
|
+
* @param filter - Filter to save.
|
|
8634
|
+
* @param jsonConverter - Converts the filter to the JSON value that is saved. Without one, the filter is saved as-is.
|
|
8635
|
+
* @returns Observable that emits once the filter is saved.
|
|
8599
8636
|
*/
|
|
8600
|
-
|
|
8601
|
-
|
|
8637
|
+
saveFilter(storageKey, filter, jsonConverter) {
|
|
8638
|
+
return this.storageAccessor.set(storageKey, jsonConverter ? jsonConverter.toJson(filter) : filter);
|
|
8639
|
+
}
|
|
8602
8640
|
/**
|
|
8603
|
-
*
|
|
8604
|
-
*
|
|
8641
|
+
* Removes the saved filter for the given storage key.
|
|
8642
|
+
*
|
|
8643
|
+
* @param storageKey - Key the filter was saved under.
|
|
8644
|
+
* @returns Observable that emits once the filter is removed.
|
|
8605
8645
|
*/
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
_configEffect = effect(() => this.setConfig(this.config()), /* @ts-ignore */
|
|
8612
|
-
...(ngDevMode ? [{ debugName: "_configEffect" }] : /* istanbul ignore next */ []));
|
|
8613
|
-
_templateEffect = effect(() => this.setTemplate(this.template()), /* @ts-ignore */
|
|
8614
|
-
...(ngDevMode ? [{ debugName: "_templateEffect" }] : /* istanbul ignore next */ []));
|
|
8615
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
8616
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: DbxInjectionComponent, isStandalone: true, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
8617
|
-
<ng-template #content></ng-template>
|
|
8618
|
-
`, isInline: true });
|
|
8646
|
+
clearFilter(storageKey) {
|
|
8647
|
+
return this.storageAccessor.remove(storageKey);
|
|
8648
|
+
}
|
|
8649
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
8650
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterStorageService });
|
|
8619
8651
|
}
|
|
8620
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
8621
|
-
type:
|
|
8622
|
-
|
|
8623
|
-
selector: 'dbx-injection, [dbxInjection], [dbx-injection]',
|
|
8624
|
-
template: `
|
|
8625
|
-
<ng-template #content></ng-template>
|
|
8626
|
-
`,
|
|
8627
|
-
imports: []
|
|
8628
|
-
}]
|
|
8629
|
-
}], propDecorators: { content: [{ type: i0.ViewChild, args: ['content', { ...{ read: ViewContainerRef }, isSignal: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }] } });
|
|
8652
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterStorageService, decorators: [{
|
|
8653
|
+
type: Injectable
|
|
8654
|
+
}] });
|
|
8630
8655
|
|
|
8631
8656
|
/**
|
|
8632
|
-
*
|
|
8657
|
+
* Saves the filter of a keyed entry in an ancestor {@link FilterMap} to storage (localStorage by default), and loads it again when the page loads. The saved filter becomes the key's default filter, and every later change to the key is saved.
|
|
8633
8658
|
*
|
|
8634
|
-
*
|
|
8635
|
-
* using a nested {@link DbxInjectionComponent}.
|
|
8659
|
+
* Use {@link reset} to set the key back to its default filter and remove the saved filter.
|
|
8636
8660
|
*
|
|
8637
|
-
* @
|
|
8638
|
-
*
|
|
8639
|
-
*
|
|
8640
|
-
*
|
|
8661
|
+
* Requires {@link provideDbxFilterStorage}.
|
|
8662
|
+
*
|
|
8663
|
+
* @dbxFilter
|
|
8664
|
+
* @dbxFilterSlug map-storage
|
|
8665
|
+
* @dbxFilterRelated map, map-source-connector, map-merge-source
|
|
8666
|
+
* @dbxFilterSkillRefs dbx__ref__dbx-component-patterns
|
|
8641
8667
|
*
|
|
8642
8668
|
* @example
|
|
8643
|
-
* ```
|
|
8644
|
-
*
|
|
8645
|
-
*
|
|
8646
|
-
*
|
|
8647
|
-
* { key: 'table', injectionConfig: { componentClass: TableComponent } }
|
|
8648
|
-
* ];
|
|
8669
|
+
* ```html
|
|
8670
|
+
* <div dbxFilterMap>
|
|
8671
|
+
* <my-filter-button [dbxFilterMapSourceConnector]="'list'" [dbxFilterMapStorage]="{ key: 'list', storageKey: 'my.list.filter', defaultFilter: {} }"></my-filter-button>
|
|
8672
|
+
* </div>
|
|
8649
8673
|
* ```
|
|
8650
|
-
*
|
|
8651
|
-
* @see {@link DbxInjectionArrayEntry}
|
|
8652
|
-
* @see {@link DbxInjectionComponent}
|
|
8653
8674
|
*/
|
|
8654
|
-
class
|
|
8675
|
+
class DbxFilterMapStorageDirective {
|
|
8676
|
+
dbxFilterMap = inject((FilterMap));
|
|
8677
|
+
dbxFilterStorageService = inject(DbxFilterStorageService);
|
|
8655
8678
|
/**
|
|
8656
|
-
* The
|
|
8679
|
+
* The key to save and how to save it.
|
|
8657
8680
|
*/
|
|
8658
|
-
|
|
8659
|
-
...(ngDevMode ? [{ debugName: "
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8681
|
+
dbxFilterMapStorage = input(/* @ts-ignore */
|
|
8682
|
+
...(ngDevMode ? [undefined, { debugName: "dbxFilterMapStorage" }] : /* istanbul ignore next */ []));
|
|
8683
|
+
config$ = toObservable(this.dbxFilterMapStorage).pipe(filterMaybe(), distinctUntilChanged(), shareReplay(1));
|
|
8684
|
+
/**
|
|
8685
|
+
* Set while reset() sets the key back to the default filter, so the default filter is not saved.
|
|
8686
|
+
*/
|
|
8687
|
+
_resetting = false;
|
|
8688
|
+
constructor() {
|
|
8689
|
+
cleanSubscription(this.config$.pipe(switchMap((config) => this._loadAndSaveFilter(config))).subscribe());
|
|
8664
8690
|
}
|
|
8665
|
-
|
|
8691
|
+
/**
|
|
8692
|
+
* Sets the key back to the default filter and removes the saved filter.
|
|
8693
|
+
*
|
|
8694
|
+
* The default filter is not saved, so the next page load also starts from the default filter.
|
|
8695
|
+
*
|
|
8696
|
+
* @returns Observable that emits once the key is reset and the saved filter is removed.
|
|
8697
|
+
*/
|
|
8698
|
+
reset() {
|
|
8699
|
+
return this.config$.pipe(first(), switchMap((config) => asObservable(config.defaultFilter).pipe(first(), tap((defaultFilter) => {
|
|
8700
|
+
if (defaultFilter != null) {
|
|
8701
|
+
this._resetting = true;
|
|
8702
|
+
this.dbxFilterMap.setFilterForKey(config.key, defaultFilter);
|
|
8703
|
+
this._resetting = false;
|
|
8704
|
+
}
|
|
8705
|
+
}), switchMap(() => this.dbxFilterStorageService.clearFilter(storageKeyForConfig(config))))));
|
|
8706
|
+
}
|
|
8707
|
+
/**
|
|
8708
|
+
* Loads the saved filter as the key's default filter, then returns an observable that saves every later change to the key.
|
|
8709
|
+
*
|
|
8710
|
+
* @param config - The key to save and how to save it.
|
|
8711
|
+
* @returns Observable that saves the key's filter while subscribed.
|
|
8712
|
+
*/
|
|
8713
|
+
_loadAndSaveFilter(config) {
|
|
8714
|
+
const { key, defaultFilter, mapLoadedFilter, jsonConverter } = config;
|
|
8715
|
+
const storageKey = storageKeyForConfig(config);
|
|
8716
|
+
const loadedFilter$ = this.dbxFilterStorageService.loadFilter(storageKey, jsonConverter).pipe(map((savedFilter) => (savedFilter != null && mapLoadedFilter ? mapLoadedFilter(savedFilter) : savedFilter)), switchMap((savedFilter) => (savedFilter == null ? asObservable(defaultFilter) : of(savedFilter))), filterMaybe());
|
|
8717
|
+
this.dbxFilterMap.addDefaultFilterObs(key, loadedFilter$);
|
|
8718
|
+
return this.dbxFilterMap.filterForKey(key).pipe(distinctUntilObjectValuesChanged(), skip(1), // the first value is the loaded/default filter
|
|
8719
|
+
filter(() => !this._resetting), switchMap((nextFilter) => this.dbxFilterStorageService.saveFilter(storageKey, nextFilter, jsonConverter)));
|
|
8720
|
+
}
|
|
8721
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterMapStorageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
8722
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.4", type: DbxFilterMapStorageDirective, isStandalone: true, selector: "[dbxFilterMapStorage]", inputs: { dbxFilterMapStorage: { classPropertyName: "dbxFilterMapStorage", publicName: "dbxFilterMapStorage", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["dbxFilterMapStorage"], ngImport: i0 });
|
|
8666
8723
|
}
|
|
8667
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
8668
|
-
type:
|
|
8724
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterMapStorageDirective, decorators: [{
|
|
8725
|
+
type: Directive,
|
|
8669
8726
|
args: [{
|
|
8670
|
-
selector: '
|
|
8671
|
-
|
|
8672
|
-
@for (entry of entries(); track entry.key) {
|
|
8673
|
-
<dbx-injection [config]="entry.injectionConfig"></dbx-injection>
|
|
8674
|
-
}
|
|
8675
|
-
`,
|
|
8676
|
-
imports: [DbxInjectionComponent]
|
|
8727
|
+
selector: '[dbxFilterMapStorage]',
|
|
8728
|
+
exportAs: 'dbxFilterMapStorage'
|
|
8677
8729
|
}]
|
|
8678
|
-
}], propDecorators: {
|
|
8730
|
+
}], ctorParameters: () => [], propDecorators: { dbxFilterMapStorage: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxFilterMapStorage", required: false }] }] } });
|
|
8731
|
+
function storageKeyForConfig(config) {
|
|
8732
|
+
return config.storageKey ?? config.key;
|
|
8733
|
+
}
|
|
8679
8734
|
|
|
8680
8735
|
/**
|
|
8681
|
-
*
|
|
8682
|
-
* then restoring the original content when done.
|
|
8683
|
-
*
|
|
8684
|
-
* Unlike `*ngIf` or `*ngSwitch`, the original child content is **hidden** rather than destroyed,
|
|
8685
|
-
* preserving component state. Once the injected context's promise resolves (or is reset), the
|
|
8686
|
-
* original content is re-displayed.
|
|
8687
|
-
*
|
|
8688
|
-
* This is useful for overlay-like workflows such as inline editors, confirmation dialogs,
|
|
8689
|
-
* or multi-step flows where destroying and recreating the underlying view would lose state.
|
|
8736
|
+
* Type guard that checks if an object is a {@link ClickableFilterPreset}.
|
|
8690
8737
|
*
|
|
8691
|
-
* @
|
|
8692
|
-
* @
|
|
8738
|
+
* @param preset - The object to check.
|
|
8739
|
+
* @returns `true` if the object has a `presetValue` property.
|
|
8693
8740
|
*/
|
|
8694
|
-
|
|
8741
|
+
function isClickableFilterPreset(preset) {
|
|
8742
|
+
return objectHasKey(preset, 'presetValue');
|
|
8695
8743
|
}
|
|
8696
8744
|
/**
|
|
8697
|
-
*
|
|
8698
|
-
* under the abstract `DbxInjectionContext` token via `useExisting`.
|
|
8699
|
-
*
|
|
8700
|
-
* This enables dependency injection consumers to request `DbxInjectionContext` and receive
|
|
8701
|
-
* the specific directive or service implementation.
|
|
8702
|
-
*
|
|
8703
|
-
* @param type - The concrete class to register as the existing provider.
|
|
8704
|
-
* @returns Array of Angular providers.
|
|
8745
|
+
* Type guard that checks if an object is a {@link ClickablePartialFilterPreset}.
|
|
8705
8746
|
*
|
|
8706
|
-
* @
|
|
8747
|
+
* @param preset - The object to check.
|
|
8748
|
+
* @returns `true` if the object has `partialPresetValue` and `isActive` properties.
|
|
8707
8749
|
*/
|
|
8708
|
-
function
|
|
8709
|
-
return [
|
|
8710
|
-
{
|
|
8711
|
-
provide: DbxInjectionContext,
|
|
8712
|
-
useExisting: type
|
|
8713
|
-
}
|
|
8714
|
-
];
|
|
8750
|
+
function isClickablePartialFilterPreset(preset) {
|
|
8751
|
+
return objectHasKeys(preset, ['partialPresetValue', 'isActive']);
|
|
8715
8752
|
}
|
|
8716
8753
|
|
|
8717
8754
|
/**
|
|
8718
|
-
*
|
|
8719
|
-
* to be temporarily replaced with a dynamically injected component and then restored.
|
|
8720
|
-
*
|
|
8721
|
-
* Unlike `*ngIf` or `*ngSwitch`, the original child content is **detached** (hidden) rather than
|
|
8722
|
-
* destroyed, so component state is preserved while the injected context is active. When the
|
|
8723
|
-
* context's promise resolves or {@link resetContext} is called, the original view is re-attached.
|
|
8724
|
-
*
|
|
8725
|
-
* The directive also accepts an optional `[dbxInjectionContext]` input to set a static component
|
|
8726
|
-
* config directly, which replaces the default content until cleared.
|
|
8755
|
+
* Provides a {@link FilterSource} in DI so child components can inject and consume the current filter value. Use this on a wrapper element when the child is the canonical owner of the filter (a filter form, a chip group).
|
|
8727
8756
|
*
|
|
8728
|
-
* @
|
|
8757
|
+
* @dbxFilter
|
|
8758
|
+
* @dbxFilterSlug source
|
|
8759
|
+
* @dbxFilterRelated connect-source, source-connector, map-source
|
|
8760
|
+
* @dbxFilterSkillRefs dbx__ref__dbx-component-patterns
|
|
8729
8761
|
*
|
|
8730
8762
|
* @example
|
|
8731
8763
|
* ```html
|
|
8732
|
-
*
|
|
8733
|
-
*
|
|
8734
|
-
* <p>Original content preserved while context is active</p>
|
|
8764
|
+
* <div dbxFilterSource>
|
|
8765
|
+
* <my-filter-form></my-filter-form>
|
|
8735
8766
|
* </div>
|
|
8736
8767
|
* ```
|
|
8768
|
+
*/
|
|
8769
|
+
class DbxFilterSourceDirective extends AbstractFilterSourceDirective {
|
|
8770
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterSourceDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
8771
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: DbxFilterSourceDirective, isStandalone: true, selector: "[dbxFilterSource]", providers: provideFilterSourceDirective(DbxFilterSourceDirective), usesInheritance: true, ngImport: i0 });
|
|
8772
|
+
}
|
|
8773
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxFilterSourceDirective, decorators: [{
|
|
8774
|
+
type: Directive,
|
|
8775
|
+
args: [{
|
|
8776
|
+
selector: '[dbxFilterSource]',
|
|
8777
|
+
providers: provideFilterSourceDirective(DbxFilterSourceDirective)
|
|
8778
|
+
}]
|
|
8779
|
+
}] });
|
|
8780
|
+
|
|
8781
|
+
const importsAndExports = [DbxFilterSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterConnectSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterMapDirective, DbxFilterMapSourceDirective, DbxFilterMapMergeSourceDirective, DbxFilterMapStorageDirective];
|
|
8782
|
+
class DbxCoreFilterModule {
|
|
8783
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
8784
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule, imports: [DbxFilterSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterConnectSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterMapDirective, DbxFilterMapSourceDirective, DbxFilterMapMergeSourceDirective, DbxFilterMapStorageDirective], exports: [DbxFilterSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterConnectSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterMapDirective, DbxFilterMapSourceDirective, DbxFilterMapMergeSourceDirective, DbxFilterMapStorageDirective] });
|
|
8785
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule });
|
|
8786
|
+
}
|
|
8787
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxCoreFilterModule, decorators: [{
|
|
8788
|
+
type: NgModule,
|
|
8789
|
+
args: [{
|
|
8790
|
+
imports: importsAndExports,
|
|
8791
|
+
exports: importsAndExports
|
|
8792
|
+
}]
|
|
8793
|
+
}] });
|
|
8794
|
+
|
|
8795
|
+
/**
|
|
8796
|
+
* Registers {@link DbxFilterStorageService} as an environment-level provider.
|
|
8797
|
+
*
|
|
8798
|
+
* Requires {@link provideDbxStorage} to also be provided.
|
|
8799
|
+
*
|
|
8800
|
+
* @param config - Optional service configuration.
|
|
8801
|
+
* @returns The environment providers for filter storage.
|
|
8737
8802
|
*
|
|
8738
8803
|
* @example
|
|
8739
8804
|
* ```typescript
|
|
8740
|
-
*
|
|
8741
|
-
*
|
|
8742
|
-
*
|
|
8743
|
-
* use: (editor) => editor.waitForSave()
|
|
8744
|
-
* });
|
|
8805
|
+
* export const appConfig: ApplicationConfig = {
|
|
8806
|
+
* providers: [provideDbxStorage(), provideDbxFilterStorage()],
|
|
8807
|
+
* };
|
|
8745
8808
|
* ```
|
|
8746
|
-
*
|
|
8747
|
-
* @see {@link DbxInjectionContext}
|
|
8748
|
-
* @see {@link DbxInjectionContextConfig}
|
|
8749
8809
|
*/
|
|
8750
|
-
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
_isDetached = false;
|
|
8758
|
-
/**
|
|
8759
|
-
* Optional static component config input. When set, the directive replaces its content
|
|
8760
|
-
* with the specified component. When cleared (`undefined`), the original content is restored.
|
|
8761
|
-
*/
|
|
8762
|
-
config = input(/* @ts-ignore */
|
|
8763
|
-
...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
|
|
8764
|
-
_configEffect = effect(() => {
|
|
8765
|
-
this.setConfig(this.config());
|
|
8766
|
-
// NOTE: we have/call setConfig() because the effect() may not respond to all value changes,
|
|
8767
|
-
// especially when setConfig() ends up being called twice quickly in quick succession.
|
|
8768
|
-
}, /* @ts-ignore */
|
|
8769
|
-
...(ngDevMode ? [{ debugName: "_configEffect" }] : /* istanbul ignore next */ []));
|
|
8770
|
-
ngOnInit() {
|
|
8771
|
-
this._instance.content = this._viewContainer;
|
|
8772
|
-
this._instance.init();
|
|
8773
|
-
this._embeddedView = this._viewContainer.createEmbeddedView(this._templateRef);
|
|
8774
|
-
// detach the embedded view
|
|
8775
|
-
this._viewContainer.detach();
|
|
8776
|
-
// reattach it through the template configuration.
|
|
8777
|
-
// the template configuration acts as the default.
|
|
8778
|
-
this._instance.template = {
|
|
8779
|
-
viewRef: this._embeddedView
|
|
8780
|
-
};
|
|
8781
|
-
}
|
|
8782
|
-
ngOnDestroy() {
|
|
8783
|
-
this._instance.destroy();
|
|
8784
|
-
this._embeddedView?.destroy(); // destroy our embedded view too if it is set.
|
|
8785
|
-
}
|
|
8786
|
-
/**
|
|
8787
|
-
* {@inheritDoc DbxInjectionContext.showContext}
|
|
8788
|
-
*
|
|
8789
|
-
* @param config - The injection context configuration describing the component and its usage.
|
|
8790
|
-
* @returns Resolves to the output of the injected component's usage.
|
|
8791
|
-
*/
|
|
8792
|
-
async showContext(config) {
|
|
8793
|
-
// clear the current context before showing something new.
|
|
8794
|
-
this.resetContext();
|
|
8795
|
-
let promiseRef;
|
|
8796
|
-
let result;
|
|
8797
|
-
let error;
|
|
8798
|
-
// wait for the promise to resolve and use to finish using that instance.
|
|
8799
|
-
try {
|
|
8800
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
8801
|
-
promiseRef = promiseReference(async (resolve, reject) => {
|
|
8802
|
-
const injectionConfig = {
|
|
8803
|
-
...config.config,
|
|
8804
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
8805
|
-
init: async (instance) => {
|
|
8806
|
-
// init if available in the base config.
|
|
8807
|
-
if (config.config.init) {
|
|
8808
|
-
config.config.init(instance);
|
|
8809
|
-
}
|
|
8810
|
-
try {
|
|
8811
|
-
const result = (await config.use(instance));
|
|
8812
|
-
resolve(result);
|
|
8813
|
-
}
|
|
8814
|
-
catch (e) {
|
|
8815
|
-
reject(e);
|
|
8816
|
-
}
|
|
8817
|
-
}
|
|
8818
|
-
};
|
|
8819
|
-
this.setConfig(injectionConfig);
|
|
8820
|
-
});
|
|
8821
|
-
this._currentPromise = promiseRef;
|
|
8822
|
-
// await the promise
|
|
8823
|
-
result = await promiseRef.promise;
|
|
8824
|
-
}
|
|
8825
|
-
catch (e) {
|
|
8826
|
-
error = e;
|
|
8827
|
-
}
|
|
8828
|
-
// if we're still using the same promiseRef
|
|
8829
|
-
if (promiseRef && promiseRef === this._currentPromise) {
|
|
8830
|
-
// clear the config to reshow the view
|
|
8831
|
-
this.setConfig(undefined);
|
|
8832
|
-
// clear the current promise
|
|
8833
|
-
this._currentPromise = undefined;
|
|
8834
|
-
}
|
|
8835
|
-
if (error != null) {
|
|
8836
|
-
if (error instanceof Error) {
|
|
8837
|
-
throw error;
|
|
8838
|
-
}
|
|
8839
|
-
let message;
|
|
8840
|
-
if (error == null) {
|
|
8841
|
-
message = String(error);
|
|
8842
|
-
}
|
|
8843
|
-
else if (typeof error === 'object') {
|
|
8844
|
-
message = JSON.stringify(error);
|
|
8845
|
-
}
|
|
8846
|
-
else {
|
|
8847
|
-
message = String(error);
|
|
8848
|
-
}
|
|
8849
|
-
throw new Error(message);
|
|
8850
|
-
}
|
|
8851
|
-
return result;
|
|
8852
|
-
}
|
|
8853
|
-
/**
|
|
8854
|
-
* {@inheritDoc DbxInjectionContext.resetContext}
|
|
8855
|
-
*
|
|
8856
|
-
* @returns `true` if an active context was cleared, `false` otherwise.
|
|
8857
|
-
*/
|
|
8858
|
-
resetContext() {
|
|
8859
|
-
let clearedValue = false;
|
|
8860
|
-
if (this._currentPromise) {
|
|
8861
|
-
const promise = this._currentPromise;
|
|
8862
|
-
// clear the current promise too
|
|
8863
|
-
this._currentPromise = undefined;
|
|
8864
|
-
// clear the config.
|
|
8865
|
-
this.setConfig(undefined);
|
|
8866
|
-
// send a rejection signal to bail out.
|
|
8867
|
-
promise.reject(new Error('dbxInjectionContext bailout'));
|
|
8868
|
-
clearedValue = true;
|
|
8869
|
-
}
|
|
8870
|
-
return clearedValue;
|
|
8871
|
-
}
|
|
8872
|
-
/**
|
|
8873
|
-
* Sets or clears the active component configuration.
|
|
8874
|
-
*
|
|
8875
|
-
* When a config is provided, the original embedded view is detached and the component is injected.
|
|
8876
|
-
* When `undefined` is provided, the injected component is removed and the original view is re-attached.
|
|
8877
|
-
*
|
|
8878
|
-
* @param config - The component config to display, or `undefined` to restore the original content.
|
|
8879
|
-
*/
|
|
8880
|
-
setConfig(config) {
|
|
8881
|
-
let reattach = false;
|
|
8882
|
-
if (config) {
|
|
8883
|
-
if (!this._isDetached) {
|
|
8884
|
-
// detach the original view before setting config.
|
|
8885
|
-
this._viewContainer.detach();
|
|
8886
|
-
this._isDetached = true;
|
|
8887
|
-
}
|
|
8888
|
-
}
|
|
8889
|
-
else if (this._isDetached) {
|
|
8890
|
-
reattach = true;
|
|
8891
|
-
}
|
|
8892
|
-
this._instance.config = config;
|
|
8893
|
-
if (reattach) {
|
|
8894
|
-
this._viewContainer.insert(this._embeddedView);
|
|
8895
|
-
this._isDetached = false;
|
|
8896
|
-
}
|
|
8810
|
+
function provideDbxFilterStorage(config) {
|
|
8811
|
+
const providers = [DbxFilterStorageService];
|
|
8812
|
+
if (config) {
|
|
8813
|
+
providers.push({
|
|
8814
|
+
provide: DBX_FILTER_STORAGE_SERVICE_CONFIG_TOKEN,
|
|
8815
|
+
useValue: config
|
|
8816
|
+
});
|
|
8897
8817
|
}
|
|
8898
|
-
|
|
8899
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.4", type: DbxInjectionContextDirective, isStandalone: true, selector: "[dbxInjectionContext]", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, providers: provideDbxInjectionContext(DbxInjectionContextDirective), ngImport: i0 });
|
|
8818
|
+
return makeEnvironmentProviders(providers);
|
|
8900
8819
|
}
|
|
8901
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionContextDirective, decorators: [{
|
|
8902
|
-
type: Directive,
|
|
8903
|
-
args: [{
|
|
8904
|
-
selector: '[dbxInjectionContext]',
|
|
8905
|
-
providers: provideDbxInjectionContext(DbxInjectionContextDirective)
|
|
8906
|
-
}]
|
|
8907
|
-
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
|
|
8908
8820
|
|
|
8909
8821
|
/**
|
|
8910
|
-
*
|
|
8911
|
-
* `DbxInjectionContext` obtained via Angular's dependency injection (`{ host: true }`).
|
|
8822
|
+
* Injection token used to provide arbitrary data to dynamically created components.
|
|
8912
8823
|
*
|
|
8913
|
-
*
|
|
8914
|
-
*
|
|
8915
|
-
* {@link DbxInjectionContextDirective}.
|
|
8824
|
+
* Components created via {@link DbxInjectionComponentConfig} can inject this token
|
|
8825
|
+
* to access the `data` property from their configuration.
|
|
8916
8826
|
*
|
|
8917
8827
|
* @example
|
|
8918
8828
|
* ```typescript
|
|
8919
|
-
*
|
|
8920
|
-
*
|
|
8829
|
+
* // In a dynamically injected component:
|
|
8830
|
+
* readonly data = inject(DBX_INJECTION_COMPONENT_DATA);
|
|
8921
8831
|
* ```
|
|
8922
|
-
*
|
|
8923
|
-
* @see {@link DbxInjectionContext}
|
|
8924
|
-
* @see {@link DbxInjectionContextDirective}
|
|
8925
8832
|
*/
|
|
8926
|
-
|
|
8927
|
-
/**
|
|
8928
|
-
* The host-level {@link DbxInjectionContext} that all operations are forwarded to.
|
|
8929
|
-
*/
|
|
8930
|
-
dbxInjectionContext = inject(DbxInjectionContext, { host: true });
|
|
8931
|
-
// MARK: DbxInjectionContext
|
|
8932
|
-
/**
|
|
8933
|
-
* {@inheritDoc DbxInjectionContext.showContext}
|
|
8934
|
-
*
|
|
8935
|
-
* @param config - The injection context configuration to forward to the host context.
|
|
8936
|
-
* @returns Resolves to the output of the injected component's usage.
|
|
8937
|
-
*/
|
|
8938
|
-
showContext(config) {
|
|
8939
|
-
return this.dbxInjectionContext.showContext(config);
|
|
8940
|
-
}
|
|
8941
|
-
/**
|
|
8942
|
-
* {@inheritDoc DbxInjectionContext.resetContext}
|
|
8943
|
-
*
|
|
8944
|
-
* @returns `true` if an active context was cleared, `false` otherwise.
|
|
8945
|
-
*/
|
|
8946
|
-
resetContext() {
|
|
8947
|
-
return this.dbxInjectionContext.resetContext();
|
|
8948
|
-
}
|
|
8949
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractForwardDbxInjectionContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
8950
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: AbstractForwardDbxInjectionContextDirective, isStandalone: true, ngImport: i0 });
|
|
8951
|
-
}
|
|
8952
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractForwardDbxInjectionContextDirective, decorators: [{
|
|
8953
|
-
type: Directive
|
|
8954
|
-
}] });
|
|
8955
|
-
|
|
8833
|
+
const DBX_INJECTION_COMPONENT_DATA = new InjectionToken('DbxInjectionComponentConfigData');
|
|
8956
8834
|
/**
|
|
8957
|
-
*
|
|
8958
|
-
* default config when the source emits `null`, `undefined`, or `true`.
|
|
8959
|
-
*
|
|
8960
|
-
* If the `defaultConfig` resolves to a class (function), it is automatically wrapped into a
|
|
8961
|
-
* `{ componentClass }` config object.
|
|
8835
|
+
* Compares two {@link DbxInjectionComponentConfig} values for structural equality, safely handling nullish values.
|
|
8962
8836
|
*
|
|
8963
|
-
*
|
|
8964
|
-
*
|
|
8837
|
+
* Compares `componentClass`, `data`, `init`, and `injector` by reference. Does NOT compare
|
|
8838
|
+
* `providers` or `ngModuleRef`, as provider arrays typically change on every list data update
|
|
8839
|
+
* (e.g., with new `DBX_VALUE_LIST_VIEW_ITEM` values) without requiring component recreation.
|
|
8965
8840
|
*
|
|
8966
|
-
*
|
|
8967
|
-
*
|
|
8841
|
+
* When both values are nullish, uses strict equality (`null === null` is `true`,
|
|
8842
|
+
* `null === undefined` is `false`). The comparator is only invoked when both are non-nullish.
|
|
8843
|
+
*/
|
|
8844
|
+
const dbxInjectionComponentConfigIsEqual = safeEqualityComparatorFunction((a, b) => a.componentClass === b.componentClass && a.data === b.data && a.init === b.init && a.injector === b.injector);
|
|
8845
|
+
/**
|
|
8846
|
+
* Merges multiple partial {@link DbxInjectionComponentConfig} objects into a single configuration.
|
|
8968
8847
|
*
|
|
8969
|
-
*
|
|
8970
|
-
*
|
|
8971
|
-
* @typeParam X - The component type.
|
|
8848
|
+
* Provider arrays are concatenated so that all providers from all configs are preserved.
|
|
8849
|
+
* All other properties are merged with later values taking precedence.
|
|
8972
8850
|
*
|
|
8973
|
-
* @
|
|
8974
|
-
*
|
|
8975
|
-
* config$.pipe(
|
|
8976
|
-
* switchMapDbxInjectionComponentConfig(MyDefaultComponent)
|
|
8977
|
-
* ).subscribe(config => {
|
|
8978
|
-
* // config is always a DbxInjectionComponentConfig or undefined
|
|
8979
|
-
* });
|
|
8980
|
-
* ```
|
|
8851
|
+
* @param configs - The partial configs to merge. May contain `undefined`/`null` entries which are filtered out.
|
|
8852
|
+
* @returns A single merged partial configuration.
|
|
8981
8853
|
*/
|
|
8982
|
-
function
|
|
8983
|
-
const
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
// if value is a function, it is a component class
|
|
8988
|
-
return typeof value === 'function' ? { componentClass: value } : value;
|
|
8989
|
-
}
|
|
8990
|
-
});
|
|
8854
|
+
function mergeDbxInjectionComponentConfigs(configs) {
|
|
8855
|
+
const providers = mergeArrays(filterMaybeArrayValues(configs).map((x) => x.providers));
|
|
8856
|
+
const result = mergeObjects(configs);
|
|
8857
|
+
result.providers = providers;
|
|
8858
|
+
return result;
|
|
8991
8859
|
}
|
|
8992
8860
|
|
|
8993
8861
|
/**
|
|
8994
|
-
*
|
|
8995
|
-
* resolves an instance of that type.
|
|
8996
|
-
*
|
|
8997
|
-
* This is a convenience for one-off instantiation of an injectable class using a specific
|
|
8998
|
-
* parent injector, without needing to manually configure `Injector.create()`.
|
|
8862
|
+
* Flattens and merges multiple provider sources into a single `StaticProvider[]` array.
|
|
8999
8863
|
*
|
|
9000
|
-
*
|
|
9001
|
-
*
|
|
9002
|
-
* @returns A new instance of `T`.
|
|
8864
|
+
* Each argument can be a single `StaticProvider`, an array of providers, or `undefined`/`null`.
|
|
8865
|
+
* All values are flattened into a single array with nullish entries removed.
|
|
9003
8866
|
*
|
|
9004
|
-
* @
|
|
8867
|
+
* @param providers - Any number of provider values or arrays to merge.
|
|
8868
|
+
* @returns A flat array of all non-nullish static providers.
|
|
9005
8869
|
*
|
|
9006
8870
|
* @example
|
|
9007
8871
|
* ```typescript
|
|
9008
|
-
* const
|
|
9009
|
-
*
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
|
|
9013
|
-
|
|
8872
|
+
* const providers = mergeStaticProviders(
|
|
8873
|
+
* { provide: TOKEN_A, useValue: 'a' },
|
|
8874
|
+
* undefined,
|
|
8875
|
+
* [{ provide: TOKEN_B, useValue: 'b' }]
|
|
8876
|
+
* );
|
|
8877
|
+
* // Result: [{ provide: TOKEN_A, useValue: 'a' }, { provide: TOKEN_B, useValue: 'b' }]
|
|
8878
|
+
* ```
|
|
8879
|
+
*/
|
|
8880
|
+
function mergeStaticProviders(...providers) {
|
|
8881
|
+
return flattenArrayOrValueArray(providers);
|
|
9014
8882
|
}
|
|
9015
|
-
|
|
9016
8883
|
/**
|
|
9017
|
-
*
|
|
9018
|
-
*
|
|
8884
|
+
* Builds an element injector from a {@link DbxInjectionComponentConfig},
|
|
8885
|
+
* merging the config's providers and {@link DBX_INJECTION_COMPONENT_DATA} into a child injector.
|
|
9019
8886
|
*
|
|
9020
|
-
*
|
|
9021
|
-
* On destroy, the store waits for all locks to unlock before completing cleanup,
|
|
9022
|
-
* preventing premature teardown of in-flight operations.
|
|
8887
|
+
* Returns the config's injector (or parent) unchanged if no providers or data are specified.
|
|
9023
8888
|
*
|
|
9024
|
-
* @
|
|
8889
|
+
* @param params - The config and parent injector to build from.
|
|
8890
|
+
* @returns A child {@link Injector} with the config's providers and data, or the parent injector if none are specified.
|
|
9025
8891
|
*
|
|
9026
8892
|
* @example
|
|
9027
8893
|
* ```typescript
|
|
9028
|
-
*
|
|
9029
|
-
*
|
|
9030
|
-
*
|
|
9031
|
-
*
|
|
9032
|
-
* constructor() {
|
|
9033
|
-
* super({ items: [] });
|
|
9034
|
-
* }
|
|
9035
|
-
* }
|
|
8894
|
+
* const injector = createInjectorForInjectionComponentConfig({
|
|
8895
|
+
* config: { componentClass: MyComponent, data: { id: 1 }, providers: [myProvider] },
|
|
8896
|
+
* parentInjector: this._injector
|
|
8897
|
+
* });
|
|
9036
8898
|
* ```
|
|
8899
|
+
* @__NO_SIDE_EFFECTS__
|
|
9037
8900
|
*/
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
constructor(initialState) {
|
|
9046
|
-
super(initialState);
|
|
9047
|
-
this.initialState = initialState;
|
|
9048
|
-
}
|
|
9049
|
-
// MARK: State Changes
|
|
9050
|
-
resetStore = this.updater(() => ({ ...this.initialState }));
|
|
9051
|
-
// MARK: Locks
|
|
9052
|
-
setupLockSet({ parent, locks }) {
|
|
9053
|
-
if (parent) {
|
|
9054
|
-
this.setParentLockSet(parent);
|
|
9055
|
-
}
|
|
9056
|
-
if (locks) {
|
|
9057
|
-
for (const key in locks) {
|
|
9058
|
-
if (locks[key]) {
|
|
9059
|
-
this.addLock(key, locks[key]);
|
|
9060
|
-
}
|
|
9061
|
-
}
|
|
9062
|
-
}
|
|
9063
|
-
}
|
|
9064
|
-
setParentLockSet(obs) {
|
|
9065
|
-
this.lockSet.setParentLockSet(asObservable(obs).pipe(map((x) => x?.lockSet)));
|
|
9066
|
-
}
|
|
9067
|
-
addLock(key, obs) {
|
|
9068
|
-
this.lockSet.addLock(key, obs);
|
|
9069
|
-
}
|
|
9070
|
-
// MARK: Cleanup
|
|
9071
|
-
ngOnDestroy() {
|
|
9072
|
-
// Wait for any actions to complete before destroying.
|
|
9073
|
-
this.lockSet.destroyOnNextUnlock({
|
|
9074
|
-
fn: () => {
|
|
9075
|
-
this._destroyNow();
|
|
9076
|
-
},
|
|
9077
|
-
timeout: this.lockSetDestroyTimeoutMs
|
|
9078
|
-
}, this.lockSetDestroyDelayMs);
|
|
8901
|
+
function createInjectorForInjectionComponentConfig(params) {
|
|
8902
|
+
const { config, parentInjector } = params;
|
|
8903
|
+
const { injector: inputInjector, providers, data } = config;
|
|
8904
|
+
const parent = inputInjector ?? parentInjector;
|
|
8905
|
+
let result;
|
|
8906
|
+
if (!providers && data == null) {
|
|
8907
|
+
result = parent;
|
|
9079
8908
|
}
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
this.lockSet.destroy();
|
|
8909
|
+
else {
|
|
8910
|
+
result = Injector.create({
|
|
8911
|
+
parent,
|
|
8912
|
+
providers: mergeStaticProviders({ provide: DBX_INJECTION_COMPONENT_DATA, useValue: data }, providers)
|
|
8913
|
+
});
|
|
9086
8914
|
}
|
|
9087
|
-
|
|
9088
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: LockSetComponentStore });
|
|
8915
|
+
return result;
|
|
9089
8916
|
}
|
|
9090
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: LockSetComponentStore, decorators: [{
|
|
9091
|
-
type: Injectable
|
|
9092
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
9093
|
-
type: Inject,
|
|
9094
|
-
args: [null]
|
|
9095
|
-
}, {
|
|
9096
|
-
type: Optional
|
|
9097
|
-
}] }] });
|
|
9098
|
-
|
|
9099
8917
|
/**
|
|
9100
|
-
*
|
|
8918
|
+
* Runs the init callback from a {@link DbxInjectionComponentConfig} on the given component ref,
|
|
8919
|
+
* executing within the component's injection context so that `inject()` is available inside the callback.
|
|
9101
8920
|
*
|
|
9102
|
-
* @
|
|
8921
|
+
* @param componentRef - The component reference whose instance will be passed to the init callback.
|
|
8922
|
+
* @param config - The injection component config containing the optional init callback.
|
|
8923
|
+
*
|
|
8924
|
+
* @example
|
|
8925
|
+
* ```typescript
|
|
8926
|
+
* const ref = viewContainerRef.createComponent(config.componentClass, { injector });
|
|
8927
|
+
* initInjectionComponent(ref, config);
|
|
8928
|
+
* ```
|
|
9103
8929
|
*/
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
parseValue(data) {
|
|
9109
|
-
return JSON.parse(data);
|
|
8930
|
+
function initInjectionComponent(componentRef, config) {
|
|
8931
|
+
const { init } = config;
|
|
8932
|
+
if (init) {
|
|
8933
|
+
runInInjectionContext(componentRef.injector, () => init(componentRef.instance));
|
|
9110
8934
|
}
|
|
9111
8935
|
}
|
|
8936
|
+
|
|
9112
8937
|
/**
|
|
9113
|
-
*
|
|
9114
|
-
*
|
|
8938
|
+
* Core runtime engine for the dbx-injection system. Manages the lifecycle of dynamically injected
|
|
8939
|
+
* components and templates within an Angular `ViewContainerRef`.
|
|
9115
8940
|
*
|
|
9116
|
-
*
|
|
8941
|
+
* This class reactively listens to configuration and template observables. When a new
|
|
8942
|
+
* {@link DbxInjectionComponentConfig} or {@link DbxInjectionTemplateConfig} is emitted, it tears
|
|
8943
|
+
* down the previous content and creates the new component or template in the target view container.
|
|
8944
|
+
*
|
|
8945
|
+
* Component configs take precedence over template configs when both are provided.
|
|
8946
|
+
*
|
|
8947
|
+
* Typically used internally by {@link AbstractDbxInjectionDirective} and {@link DbxInjectionComponent}
|
|
8948
|
+
* rather than consumed directly.
|
|
8949
|
+
*
|
|
8950
|
+
* @typeParam T - The type of the dynamically created component.
|
|
8951
|
+
*
|
|
8952
|
+
* @see {@link DbxInjectionComponentConfig}
|
|
8953
|
+
* @see {@link DbxInjectionTemplateConfig}
|
|
8954
|
+
* @see {@link AbstractDbxInjectionDirective}
|
|
9117
8955
|
*/
|
|
9118
|
-
class
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
8956
|
+
class DbxInjectionInstance {
|
|
8957
|
+
_subscriptionObject = new SubscriptionObject();
|
|
8958
|
+
_config = new BehaviorSubject(undefined);
|
|
8959
|
+
_template = new BehaviorSubject(undefined);
|
|
8960
|
+
_content = new BehaviorSubject(undefined);
|
|
8961
|
+
_componentRef = new BehaviorSubject(undefined);
|
|
8962
|
+
_injector;
|
|
8963
|
+
config$ = this._config.pipe(maybeValueFromObservableOrValueGetter(), distinctUntilChanged(dbxInjectionComponentConfigIsEqual), shareReplay(1));
|
|
8964
|
+
template$ = this._template.pipe(maybeValueFromObservableOrValueGetter(), distinctUntilChanged(), shareReplay(1));
|
|
8965
|
+
content$ = this._content.pipe(filterMaybe(), distinctUntilChanged(), shareReplay(1));
|
|
8966
|
+
get config() {
|
|
8967
|
+
return this._config.value;
|
|
9124
8968
|
}
|
|
9125
|
-
|
|
9126
|
-
|
|
8969
|
+
set config(config) {
|
|
8970
|
+
this._config.next(config);
|
|
9127
8971
|
}
|
|
9128
|
-
|
|
9129
|
-
return this.
|
|
8972
|
+
get template() {
|
|
8973
|
+
return this._template.value;
|
|
9130
8974
|
}
|
|
9131
|
-
|
|
9132
|
-
|
|
8975
|
+
set template(template) {
|
|
8976
|
+
this._template.next(template);
|
|
9133
8977
|
}
|
|
9134
|
-
|
|
9135
|
-
return this.
|
|
8978
|
+
get content() {
|
|
8979
|
+
return this._content.value;
|
|
9136
8980
|
}
|
|
9137
|
-
|
|
9138
|
-
|
|
8981
|
+
set content(content) {
|
|
8982
|
+
this._content.next(content);
|
|
9139
8983
|
}
|
|
9140
|
-
|
|
9141
|
-
return this.
|
|
8984
|
+
get componentRef() {
|
|
8985
|
+
return this._componentRef.value;
|
|
9142
8986
|
}
|
|
9143
|
-
|
|
9144
|
-
|
|
8987
|
+
set componentRef(componentRef) {
|
|
8988
|
+
this._componentRef.next(componentRef);
|
|
9145
8989
|
}
|
|
9146
|
-
|
|
9147
|
-
|
|
8990
|
+
constructor(injector) {
|
|
8991
|
+
this._injector = injector;
|
|
8992
|
+
}
|
|
8993
|
+
init() {
|
|
8994
|
+
// Wait until the first of either of the two inputs comes in as not defined, and then emit.
|
|
8995
|
+
// We filter the first maybe here between the two items.
|
|
8996
|
+
const configTemplateObs = combineLatest([this.config$, this.template$]).pipe(map(([config, template]) => {
|
|
8997
|
+
return config || template ? { config, template } : undefined;
|
|
8998
|
+
}), skipAllInitialMaybe());
|
|
8999
|
+
this._subscriptionObject.subscription = combineLatest([configTemplateObs, this.content$]).subscribe(([inputConfig, content]) => {
|
|
9000
|
+
const { config, template } = inputConfig ?? {};
|
|
9001
|
+
this._reset(content);
|
|
9002
|
+
if (config) {
|
|
9003
|
+
this._initComponent(config, content);
|
|
9004
|
+
}
|
|
9005
|
+
else if (template) {
|
|
9006
|
+
this._initTemplate(template, content);
|
|
9007
|
+
}
|
|
9008
|
+
});
|
|
9009
|
+
}
|
|
9010
|
+
destroy() {
|
|
9011
|
+
this._subscriptionObject.destroy();
|
|
9012
|
+
this._config.complete();
|
|
9013
|
+
this._template.complete();
|
|
9014
|
+
this._content.complete();
|
|
9015
|
+
this._componentRef.complete();
|
|
9016
|
+
}
|
|
9017
|
+
_initComponent(config, content) {
|
|
9018
|
+
content.clear();
|
|
9019
|
+
const { componentClass, ngModuleRef } = config;
|
|
9020
|
+
if (!componentClass) {
|
|
9021
|
+
throw new Error('DbxInjectionInstance: componentClass was expected in the config but it was unavailable.');
|
|
9022
|
+
}
|
|
9023
|
+
const injector = createInjectorForInjectionComponentConfig({ config, parentInjector: this._injector });
|
|
9024
|
+
const componentRef = content.createComponent(componentClass, { injector, ngModuleRef });
|
|
9025
|
+
initInjectionComponent(componentRef, config);
|
|
9026
|
+
this.componentRef = componentRef;
|
|
9027
|
+
}
|
|
9028
|
+
_initTemplate(config, content) {
|
|
9029
|
+
content.clear();
|
|
9030
|
+
const { templateRef, viewRef } = config;
|
|
9031
|
+
if (templateRef) {
|
|
9032
|
+
content.createEmbeddedView(templateRef);
|
|
9033
|
+
// TODO: Figure out if these items need to be destroyed or not when this item is destroyed. If so, we need a reference to destroy.
|
|
9034
|
+
}
|
|
9035
|
+
else if (viewRef) {
|
|
9036
|
+
content.insert(viewRef);
|
|
9037
|
+
}
|
|
9038
|
+
}
|
|
9039
|
+
_reset(content) {
|
|
9040
|
+
if (this.componentRef) {
|
|
9041
|
+
content.clear();
|
|
9042
|
+
this.componentRef = undefined;
|
|
9043
|
+
}
|
|
9148
9044
|
}
|
|
9149
9045
|
}
|
|
9046
|
+
|
|
9150
9047
|
/**
|
|
9151
|
-
*
|
|
9048
|
+
* Abstract base directive for dynamically injecting components or templates into a view.
|
|
9152
9049
|
*
|
|
9153
|
-
* @
|
|
9154
|
-
*
|
|
9155
|
-
*
|
|
9050
|
+
* Manages a {@link DbxInjectionInstance} lifecycle, initializing it on `ngOnInit` and
|
|
9051
|
+
* destroying it on `ngOnDestroy`. Subclasses are responsible for wiring their inputs
|
|
9052
|
+
* (config, template, content) to the corresponding setter methods.
|
|
9053
|
+
*
|
|
9054
|
+
* @typeParam T - The type of the dynamically created component.
|
|
9055
|
+
*
|
|
9056
|
+
* @see {@link DbxInjectionComponent} - The concrete standalone component implementation.
|
|
9057
|
+
* @see {@link DbxInjectionInstance}
|
|
9156
9058
|
*/
|
|
9157
|
-
|
|
9158
|
-
|
|
9159
|
-
|
|
9059
|
+
class AbstractDbxInjectionDirective {
|
|
9060
|
+
_instance = new DbxInjectionInstance(inject(Injector));
|
|
9061
|
+
ngOnInit() {
|
|
9062
|
+
this._instance.init();
|
|
9160
9063
|
}
|
|
9161
|
-
|
|
9162
|
-
|
|
9064
|
+
ngOnDestroy() {
|
|
9065
|
+
this._instance.destroy();
|
|
9163
9066
|
}
|
|
9067
|
+
/**
|
|
9068
|
+
* Sets the component injection configuration on the underlying {@link DbxInjectionInstance}.
|
|
9069
|
+
*
|
|
9070
|
+
* @param config - The component config, observable, or getter to use.
|
|
9071
|
+
*/
|
|
9072
|
+
setConfig(config) {
|
|
9073
|
+
this._instance.config = config;
|
|
9074
|
+
}
|
|
9075
|
+
/**
|
|
9076
|
+
* Sets the template injection configuration on the underlying {@link DbxInjectionInstance}.
|
|
9077
|
+
*
|
|
9078
|
+
* @param template - The template config, observable, or getter to use.
|
|
9079
|
+
*/
|
|
9080
|
+
setTemplate(template) {
|
|
9081
|
+
this._instance.template = template;
|
|
9082
|
+
}
|
|
9083
|
+
/**
|
|
9084
|
+
* Sets the target `ViewContainerRef` where dynamic content will be inserted.
|
|
9085
|
+
*
|
|
9086
|
+
* @param content - The view container reference for content projection.
|
|
9087
|
+
*/
|
|
9088
|
+
setContent(content) {
|
|
9089
|
+
this._instance.content = content;
|
|
9090
|
+
}
|
|
9091
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractDbxInjectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9092
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: AbstractDbxInjectionDirective, isStandalone: true, ngImport: i0 });
|
|
9164
9093
|
}
|
|
9094
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractDbxInjectionDirective, decorators: [{
|
|
9095
|
+
type: Directive
|
|
9096
|
+
}] });
|
|
9097
|
+
|
|
9165
9098
|
/**
|
|
9166
|
-
*
|
|
9099
|
+
* Standalone component for dynamically injecting a component or template into the DOM.
|
|
9167
9100
|
*
|
|
9168
|
-
* @
|
|
9169
|
-
* @
|
|
9170
|
-
*
|
|
9101
|
+
* Accepts a {@link DbxInjectionComponentConfig} (to create a component) or a
|
|
9102
|
+
* {@link DbxInjectionTemplateConfig} (to embed a template/view). When the config changes,
|
|
9103
|
+
* the previous content is destroyed and the new content is created in its place.
|
|
9104
|
+
*
|
|
9105
|
+
* Can be used as an element (`<dbx-injection>`) or as an attribute directive
|
|
9106
|
+
* (`[dbxInjection]` / `[dbx-injection]`).
|
|
9107
|
+
*
|
|
9108
|
+
* @typeParam T - The type of the dynamically created component.
|
|
9109
|
+
*
|
|
9110
|
+
* @example
|
|
9111
|
+
* ```html
|
|
9112
|
+
* <!-- Element usage with a component config -->
|
|
9113
|
+
* <dbx-injection [config]="myComponentConfig"></dbx-injection>
|
|
9114
|
+
*
|
|
9115
|
+
* <!-- Element usage with a template config -->
|
|
9116
|
+
* <dbx-injection [template]="myTemplateConfig"></dbx-injection>
|
|
9117
|
+
*
|
|
9118
|
+
* <!-- Attribute usage -->
|
|
9119
|
+
* <div dbxInjection [config]="myComponentConfig"></div>
|
|
9120
|
+
* ```
|
|
9121
|
+
*
|
|
9122
|
+
* @see {@link DbxInjectionComponentConfig}
|
|
9123
|
+
* @see {@link DbxInjectionTemplateConfig}
|
|
9124
|
+
* @see {@link AbstractDbxInjectionDirective}
|
|
9171
9125
|
*/
|
|
9172
|
-
|
|
9173
|
-
|
|
9126
|
+
class DbxInjectionComponent extends AbstractDbxInjectionDirective {
|
|
9127
|
+
/**
|
|
9128
|
+
* Reference to the internal view container where dynamic content is projected.
|
|
9129
|
+
*/
|
|
9130
|
+
content = viewChild('content', { ...(ngDevMode ? { debugName: "content" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
9131
|
+
/**
|
|
9132
|
+
* The component injection configuration. Accepts an observable, getter, or static value.
|
|
9133
|
+
*/
|
|
9134
|
+
config = input(/* @ts-ignore */
|
|
9135
|
+
...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
|
|
9136
|
+
/**
|
|
9137
|
+
* The template injection configuration. Accepts an observable, getter, or static value.
|
|
9138
|
+
* Only used when `config` is not provided.
|
|
9139
|
+
*/
|
|
9140
|
+
template = input(/* @ts-ignore */
|
|
9141
|
+
...(ngDevMode ? [undefined, { debugName: "template" }] : /* istanbul ignore next */ []));
|
|
9142
|
+
// allow signal writes for each as during their initialization they may write to a signal in some cases when initializing
|
|
9143
|
+
_contentEffect = effect(() => this.setContent(this.content()), /* @ts-ignore */
|
|
9144
|
+
...(ngDevMode ? [{ debugName: "_contentEffect" }] : /* istanbul ignore next */ []));
|
|
9145
|
+
_configEffect = effect(() => this.setConfig(this.config()), /* @ts-ignore */
|
|
9146
|
+
...(ngDevMode ? [{ debugName: "_configEffect" }] : /* istanbul ignore next */ []));
|
|
9147
|
+
_templateEffect = effect(() => this.setTemplate(this.template()), /* @ts-ignore */
|
|
9148
|
+
...(ngDevMode ? [{ debugName: "_templateEffect" }] : /* istanbul ignore next */ []));
|
|
9149
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
9150
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: DbxInjectionComponent, isStandalone: true, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
|
|
9151
|
+
<ng-template #content></ng-template>
|
|
9152
|
+
`, isInline: true });
|
|
9174
9153
|
}
|
|
9154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionComponent, decorators: [{
|
|
9155
|
+
type: Component,
|
|
9156
|
+
args: [{
|
|
9157
|
+
selector: 'dbx-injection, [dbxInjection], [dbx-injection]',
|
|
9158
|
+
template: `
|
|
9159
|
+
<ng-template #content></ng-template>
|
|
9160
|
+
`,
|
|
9161
|
+
imports: []
|
|
9162
|
+
}]
|
|
9163
|
+
}], propDecorators: { content: [{ type: i0.ViewChild, args: ['content', { ...{ read: ViewContainerRef }, isSignal: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }] } });
|
|
9164
|
+
|
|
9175
9165
|
/**
|
|
9176
|
-
*
|
|
9177
|
-
* and optional time-based expiration on top of a raw string storage backend.
|
|
9166
|
+
* Renders a list of dynamically injected components from an array of {@link DbxInjectionArrayEntry} items.
|
|
9178
9167
|
*
|
|
9179
|
-
*
|
|
9180
|
-
*
|
|
9168
|
+
* Each entry is tracked by its `key` property for efficient change detection, and rendered
|
|
9169
|
+
* using a nested {@link DbxInjectionComponent}.
|
|
9181
9170
|
*
|
|
9182
|
-
* @
|
|
9171
|
+
* @example
|
|
9172
|
+
* ```html
|
|
9173
|
+
* <dbx-injection-array [entries]="myEntries" />
|
|
9174
|
+
* ```
|
|
9183
9175
|
*
|
|
9184
|
-
* @
|
|
9185
|
-
*
|
|
9176
|
+
* @example
|
|
9177
|
+
* ```typescript
|
|
9178
|
+
* // In the host component:
|
|
9179
|
+
* myEntries: DbxInjectionArrayEntry[] = [
|
|
9180
|
+
* { key: 'chart', injectionConfig: { componentClass: ChartComponent } },
|
|
9181
|
+
* { key: 'table', injectionConfig: { componentClass: TableComponent } }
|
|
9182
|
+
* ];
|
|
9183
|
+
* ```
|
|
9184
|
+
*
|
|
9185
|
+
* @see {@link DbxInjectionArrayEntry}
|
|
9186
|
+
* @see {@link DbxInjectionComponent}
|
|
9187
|
+
*/
|
|
9188
|
+
class DbxInjectionArrayComponent {
|
|
9189
|
+
/**
|
|
9190
|
+
* The array of keyed injection entries to render. Each entry produces a `<dbx-injection>` component.
|
|
9191
|
+
*/
|
|
9192
|
+
entries = input(undefined, /* @ts-ignore */
|
|
9193
|
+
...(ngDevMode ? [{ debugName: "entries" }] : /* istanbul ignore next */ []));
|
|
9194
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionArrayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9195
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: DbxInjectionArrayComponent, isStandalone: true, selector: "dbx-injection-array", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
9196
|
+
@for (entry of entries(); track entry.key) {
|
|
9197
|
+
<dbx-injection [config]="entry.injectionConfig"></dbx-injection>
|
|
9198
|
+
}
|
|
9199
|
+
`, isInline: true, dependencies: [{ kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }] });
|
|
9200
|
+
}
|
|
9201
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionArrayComponent, decorators: [{
|
|
9202
|
+
type: Component,
|
|
9203
|
+
args: [{
|
|
9204
|
+
selector: 'dbx-injection-array',
|
|
9205
|
+
template: `
|
|
9206
|
+
@for (entry of entries(); track entry.key) {
|
|
9207
|
+
<dbx-injection [config]="entry.injectionConfig"></dbx-injection>
|
|
9208
|
+
}
|
|
9209
|
+
`,
|
|
9210
|
+
imports: [DbxInjectionComponent]
|
|
9211
|
+
}]
|
|
9212
|
+
}], propDecorators: { entries: [{ type: i0.Input, args: [{ isSignal: true, alias: "entries", required: false }] }] } });
|
|
9213
|
+
|
|
9214
|
+
/**
|
|
9215
|
+
* Abstract service for temporarily replacing a view's content with a dynamically injected component,
|
|
9216
|
+
* then restoring the original content when done.
|
|
9217
|
+
*
|
|
9218
|
+
* Unlike `*ngIf` or `*ngSwitch`, the original child content is **hidden** rather than destroyed,
|
|
9219
|
+
* preserving component state. Once the injected context's promise resolves (or is reset), the
|
|
9220
|
+
* original content is re-displayed.
|
|
9221
|
+
*
|
|
9222
|
+
* This is useful for overlay-like workflows such as inline editors, confirmation dialogs,
|
|
9223
|
+
* or multi-step flows where destroying and recreating the underlying view would lose state.
|
|
9224
|
+
*
|
|
9225
|
+
* @see {@link DbxInjectionContextConfig}
|
|
9226
|
+
* @see {@link DbxInjectionContextDirective} - The concrete structural directive implementation.
|
|
9227
|
+
*/
|
|
9228
|
+
class DbxInjectionContext {
|
|
9229
|
+
}
|
|
9230
|
+
/**
|
|
9231
|
+
* Creates Angular providers that register a concrete {@link DbxInjectionContext} implementation
|
|
9232
|
+
* under the abstract `DbxInjectionContext` token via `useExisting`.
|
|
9233
|
+
*
|
|
9234
|
+
* This enables dependency injection consumers to request `DbxInjectionContext` and receive
|
|
9235
|
+
* the specific directive or service implementation.
|
|
9236
|
+
*
|
|
9237
|
+
* @param type - The concrete class to register as the existing provider.
|
|
9238
|
+
* @returns Array of Angular providers.
|
|
9239
|
+
*
|
|
9240
|
+
* @typeParam T - The concrete type that extends {@link DbxInjectionContext}.
|
|
9241
|
+
*/
|
|
9242
|
+
function provideDbxInjectionContext(type) {
|
|
9243
|
+
return [
|
|
9244
|
+
{
|
|
9245
|
+
provide: DbxInjectionContext,
|
|
9246
|
+
useExisting: type
|
|
9247
|
+
}
|
|
9248
|
+
];
|
|
9249
|
+
}
|
|
9250
|
+
|
|
9251
|
+
/**
|
|
9252
|
+
* Structural directive that implements {@link DbxInjectionContext}, allowing its host content
|
|
9253
|
+
* to be temporarily replaced with a dynamically injected component and then restored.
|
|
9254
|
+
*
|
|
9255
|
+
* Unlike `*ngIf` or `*ngSwitch`, the original child content is **detached** (hidden) rather than
|
|
9256
|
+
* destroyed, so component state is preserved while the injected context is active. When the
|
|
9257
|
+
* context's promise resolves or {@link resetContext} is called, the original view is re-attached.
|
|
9258
|
+
*
|
|
9259
|
+
* The directive also accepts an optional `[dbxInjectionContext]` input to set a static component
|
|
9260
|
+
* config directly, which replaces the default content until cleared.
|
|
9261
|
+
*
|
|
9262
|
+
* @typeParam O - The output type produced by {@link showContext}.
|
|
9263
|
+
*
|
|
9264
|
+
* @example
|
|
9265
|
+
* ```html
|
|
9266
|
+
* <!-- Wrap content that should be temporarily replaceable -->
|
|
9267
|
+
* <div *dbxInjectionContext>
|
|
9268
|
+
* <p>Original content preserved while context is active</p>
|
|
9269
|
+
* </div>
|
|
9270
|
+
* ```
|
|
9186
9271
|
*
|
|
9187
9272
|
* @example
|
|
9188
9273
|
* ```typescript
|
|
9189
|
-
*
|
|
9190
|
-
*
|
|
9191
|
-
*
|
|
9274
|
+
* // Programmatically show a temporary editor overlay:
|
|
9275
|
+
* const result = await injectionContext.showContext({
|
|
9276
|
+
* config: { componentClass: InlineEditorComponent },
|
|
9277
|
+
* use: (editor) => editor.waitForSave()
|
|
9192
9278
|
* });
|
|
9193
|
-
*
|
|
9194
|
-
* accessor.set('theme', { dark: true }).subscribe();
|
|
9195
|
-
* accessor.get('theme').subscribe(settings => console.log(settings));
|
|
9196
9279
|
* ```
|
|
9280
|
+
*
|
|
9281
|
+
* @see {@link DbxInjectionContext}
|
|
9282
|
+
* @see {@link DbxInjectionContextConfig}
|
|
9197
9283
|
*/
|
|
9198
|
-
class
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9284
|
+
class DbxInjectionContextDirective {
|
|
9285
|
+
_injector = inject(Injector);
|
|
9286
|
+
_templateRef = inject((TemplateRef));
|
|
9287
|
+
_viewContainer = inject(ViewContainerRef);
|
|
9288
|
+
_instance = new DbxInjectionInstance(this._injector);
|
|
9289
|
+
_currentPromise;
|
|
9290
|
+
_embeddedView;
|
|
9291
|
+
_isDetached = false;
|
|
9292
|
+
/**
|
|
9293
|
+
* Optional static component config input. When set, the directive replaces its content
|
|
9294
|
+
* with the specified component. When cleared (`undefined`), the original content is restored.
|
|
9295
|
+
*/
|
|
9296
|
+
config = input(/* @ts-ignore */
|
|
9297
|
+
...(ngDevMode ? [undefined, { debugName: "config" }] : /* istanbul ignore next */ []));
|
|
9298
|
+
_configEffect = effect(() => {
|
|
9299
|
+
this.setConfig(this.config());
|
|
9300
|
+
// NOTE: we have/call setConfig() because the effect() may not respond to all value changes,
|
|
9301
|
+
// especially when setConfig() ends up being called twice quickly in quick succession.
|
|
9302
|
+
}, /* @ts-ignore */
|
|
9303
|
+
...(ngDevMode ? [{ debugName: "_configEffect" }] : /* istanbul ignore next */ []));
|
|
9304
|
+
ngOnInit() {
|
|
9305
|
+
this._instance.content = this._viewContainer;
|
|
9306
|
+
this._instance.init();
|
|
9307
|
+
this._embeddedView = this._viewContainer.createEmbeddedView(this._templateRef);
|
|
9308
|
+
// detach the embedded view
|
|
9309
|
+
this._viewContainer.detach();
|
|
9310
|
+
// reattach it through the template configuration.
|
|
9311
|
+
// the template configuration acts as the default.
|
|
9312
|
+
this._instance.template = {
|
|
9313
|
+
viewRef: this._embeddedView
|
|
9212
9314
|
};
|
|
9213
9315
|
}
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
get config() {
|
|
9218
|
-
return this._config;
|
|
9316
|
+
ngOnDestroy() {
|
|
9317
|
+
this._instance.destroy();
|
|
9318
|
+
this._embeddedView?.destroy(); // destroy our embedded view too if it is set.
|
|
9219
9319
|
}
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9320
|
+
/**
|
|
9321
|
+
* {@inheritDoc DbxInjectionContext.showContext}
|
|
9322
|
+
*
|
|
9323
|
+
* @param config - The injection context configuration describing the component and its usage.
|
|
9324
|
+
* @returns Resolves to the output of the injected component's usage.
|
|
9325
|
+
*/
|
|
9326
|
+
async showContext(config) {
|
|
9327
|
+
// clear the current context before showing something new.
|
|
9328
|
+
this.resetContext();
|
|
9329
|
+
let promiseRef;
|
|
9330
|
+
let result;
|
|
9331
|
+
let error;
|
|
9332
|
+
// wait for the promise to resolve and use to finish using that instance.
|
|
9333
|
+
try {
|
|
9334
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
9335
|
+
promiseRef = promiseReference(async (resolve, reject) => {
|
|
9336
|
+
const injectionConfig = {
|
|
9337
|
+
...config.config,
|
|
9338
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
9339
|
+
init: async (instance) => {
|
|
9340
|
+
// init if available in the base config.
|
|
9341
|
+
if (config.config.init) {
|
|
9342
|
+
config.config.init(instance);
|
|
9343
|
+
}
|
|
9344
|
+
try {
|
|
9345
|
+
const result = (await config.use(instance));
|
|
9346
|
+
resolve(result);
|
|
9347
|
+
}
|
|
9348
|
+
catch (e) {
|
|
9349
|
+
reject(e);
|
|
9350
|
+
}
|
|
9351
|
+
}
|
|
9352
|
+
};
|
|
9353
|
+
this.setConfig(injectionConfig);
|
|
9354
|
+
});
|
|
9355
|
+
this._currentPromise = promiseRef;
|
|
9356
|
+
// await the promise
|
|
9357
|
+
result = await promiseRef.promise;
|
|
9358
|
+
}
|
|
9359
|
+
catch (e) {
|
|
9360
|
+
error = e;
|
|
9361
|
+
}
|
|
9362
|
+
// if we're still using the same promiseRef
|
|
9363
|
+
if (promiseRef && promiseRef === this._currentPromise) {
|
|
9364
|
+
// clear the config to reshow the view
|
|
9365
|
+
this.setConfig(undefined);
|
|
9366
|
+
// clear the current promise
|
|
9367
|
+
this._currentPromise = undefined;
|
|
9368
|
+
}
|
|
9369
|
+
if (error != null) {
|
|
9370
|
+
if (error instanceof Error) {
|
|
9371
|
+
throw error;
|
|
9233
9372
|
}
|
|
9234
|
-
|
|
9235
|
-
|
|
9373
|
+
let message;
|
|
9374
|
+
if (error == null) {
|
|
9375
|
+
message = String(error);
|
|
9236
9376
|
}
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
}
|
|
9240
|
-
set(inputKey, inputValue) {
|
|
9241
|
-
const storeKey = this.makeStorageKey(inputKey);
|
|
9242
|
-
const storeData = this.buildStoredData(inputValue);
|
|
9243
|
-
const data = JSON.stringify(storeData);
|
|
9244
|
-
return this._delegate.set(storeKey, data);
|
|
9245
|
-
}
|
|
9246
|
-
remove(key) {
|
|
9247
|
-
const storeKey = this.makeStorageKey(key);
|
|
9248
|
-
return this._delegate.remove(storeKey);
|
|
9249
|
-
}
|
|
9250
|
-
all() {
|
|
9251
|
-
return this._delegate.all(this._config.fullPrefix).pipe(map((allStoredData) => {
|
|
9252
|
-
return allStoredData
|
|
9253
|
-
.map((storedData) => {
|
|
9254
|
-
const readStoredData = this.readStoredData(storedData);
|
|
9255
|
-
return readStoredData.expired ? null : readStoredData.convertedData;
|
|
9256
|
-
})
|
|
9257
|
-
.filter(hasNonNullValue);
|
|
9258
|
-
}));
|
|
9259
|
-
}
|
|
9260
|
-
allKeys() {
|
|
9261
|
-
return this._delegate.allKeys(this._config.fullPrefix).pipe(map((keys) => keys.map((x) => this.decodeStorageKey(x))));
|
|
9262
|
-
}
|
|
9263
|
-
clear() {
|
|
9264
|
-
return this._delegate.clear();
|
|
9265
|
-
}
|
|
9266
|
-
// MARK: Stored Values
|
|
9267
|
-
readStoredData(storedDataString) {
|
|
9268
|
-
const storedData = JSON.parse(storedDataString);
|
|
9269
|
-
const expired = this.isExpiredStoredData(storedData);
|
|
9270
|
-
const convertedData = this._delegate.parseValue(storedData.data);
|
|
9271
|
-
return {
|
|
9272
|
-
...storedData,
|
|
9273
|
-
expired,
|
|
9274
|
-
convertedData
|
|
9275
|
-
};
|
|
9276
|
-
}
|
|
9277
|
-
buildStoredData(value) {
|
|
9278
|
-
return {
|
|
9279
|
-
storedAt: unixDateTimeSecondsNumberForNow(),
|
|
9280
|
-
data: this.stringifyValue(value)
|
|
9281
|
-
};
|
|
9282
|
-
}
|
|
9283
|
-
isExpiredStoredData(storeData) {
|
|
9284
|
-
const expiresIn = this._config.expiresIn;
|
|
9285
|
-
let result;
|
|
9286
|
-
if (expiresIn) {
|
|
9287
|
-
if (storeData.storedAt) {
|
|
9288
|
-
result = isThrottled(expiresIn, storeData.storedAt);
|
|
9377
|
+
else if (typeof error === 'object') {
|
|
9378
|
+
message = JSON.stringify(error);
|
|
9289
9379
|
}
|
|
9290
9380
|
else {
|
|
9291
|
-
|
|
9381
|
+
message = String(error);
|
|
9292
9382
|
}
|
|
9293
|
-
|
|
9294
|
-
else {
|
|
9295
|
-
result = false;
|
|
9383
|
+
throw new Error(message);
|
|
9296
9384
|
}
|
|
9297
9385
|
return result;
|
|
9298
9386
|
}
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9387
|
+
/**
|
|
9388
|
+
* {@inheritDoc DbxInjectionContext.resetContext}
|
|
9389
|
+
*
|
|
9390
|
+
* @returns `true` if an active context was cleared, `false` otherwise.
|
|
9391
|
+
*/
|
|
9392
|
+
resetContext() {
|
|
9393
|
+
let clearedValue = false;
|
|
9394
|
+
if (this._currentPromise) {
|
|
9395
|
+
const promise = this._currentPromise;
|
|
9396
|
+
// clear the current promise too
|
|
9397
|
+
this._currentPromise = undefined;
|
|
9398
|
+
// clear the config.
|
|
9399
|
+
this.setConfig(undefined);
|
|
9400
|
+
// send a rejection signal to bail out.
|
|
9401
|
+
promise.reject(new Error('dbxInjectionContext bailout'));
|
|
9402
|
+
clearedValue = true;
|
|
9403
|
+
}
|
|
9404
|
+
return clearedValue;
|
|
9309
9405
|
}
|
|
9310
|
-
|
|
9311
|
-
|
|
9406
|
+
/**
|
|
9407
|
+
* Sets or clears the active component configuration.
|
|
9408
|
+
*
|
|
9409
|
+
* When a config is provided, the original embedded view is detached and the component is injected.
|
|
9410
|
+
* When `undefined` is provided, the injected component is removed and the original view is re-attached.
|
|
9411
|
+
*
|
|
9412
|
+
* @param config - The component config to display, or `undefined` to restore the original content.
|
|
9413
|
+
*/
|
|
9414
|
+
setConfig(config) {
|
|
9415
|
+
let reattach = false;
|
|
9416
|
+
if (config) {
|
|
9417
|
+
if (!this._isDetached) {
|
|
9418
|
+
// detach the original view before setting config.
|
|
9419
|
+
this._viewContainer.detach();
|
|
9420
|
+
this._isDetached = true;
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9423
|
+
else if (this._isDetached) {
|
|
9424
|
+
reattach = true;
|
|
9425
|
+
}
|
|
9426
|
+
this._instance.config = config;
|
|
9427
|
+
if (reattach) {
|
|
9428
|
+
this._viewContainer.insert(this._embeddedView);
|
|
9429
|
+
this._isDetached = false;
|
|
9430
|
+
}
|
|
9312
9431
|
}
|
|
9432
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9433
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.4", type: DbxInjectionContextDirective, isStandalone: true, selector: "[dbxInjectionContext]", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, providers: provideDbxInjectionContext(DbxInjectionContextDirective), ngImport: i0 });
|
|
9313
9434
|
}
|
|
9435
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: DbxInjectionContextDirective, decorators: [{
|
|
9436
|
+
type: Directive,
|
|
9437
|
+
args: [{
|
|
9438
|
+
selector: '[dbxInjectionContext]',
|
|
9439
|
+
providers: provideDbxInjectionContext(DbxInjectionContextDirective)
|
|
9440
|
+
}]
|
|
9441
|
+
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
|
|
9314
9442
|
|
|
9315
9443
|
/**
|
|
9316
|
-
*
|
|
9444
|
+
* Abstract directive that delegates {@link DbxInjectionContext} operations to a host-level
|
|
9445
|
+
* `DbxInjectionContext` obtained via Angular's dependency injection (`{ host: true }`).
|
|
9317
9446
|
*
|
|
9318
|
-
*
|
|
9447
|
+
* This is useful for creating specialized injection context subtypes that can be injected
|
|
9448
|
+
* by their own token while still forwarding the actual show/reset behavior to a parent
|
|
9449
|
+
* {@link DbxInjectionContextDirective}.
|
|
9319
9450
|
*
|
|
9320
9451
|
* @example
|
|
9321
9452
|
* ```typescript
|
|
9322
|
-
*
|
|
9323
|
-
*
|
|
9324
|
-
* accessor.get('key').subscribe(value => console.log(value)); // 'value'
|
|
9453
|
+
* @Directive({ providers: [{ provide: MySpecialContext, useExisting: MyForwardDirective }] })
|
|
9454
|
+
* class MyForwardDirective extends AbstractForwardDbxInjectionContextDirective {}
|
|
9325
9455
|
* ```
|
|
9456
|
+
*
|
|
9457
|
+
* @see {@link DbxInjectionContext}
|
|
9458
|
+
* @see {@link DbxInjectionContextDirective}
|
|
9326
9459
|
*/
|
|
9327
|
-
class
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
}
|
|
9332
|
-
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
return
|
|
9341
|
-
this._storage.setItem(key, value);
|
|
9342
|
-
x.next();
|
|
9343
|
-
x.complete();
|
|
9344
|
-
});
|
|
9345
|
-
}
|
|
9346
|
-
remove(key) {
|
|
9347
|
-
return new Observable((x) => {
|
|
9348
|
-
this._storage.removeItem(key);
|
|
9349
|
-
x.next();
|
|
9350
|
-
x.complete();
|
|
9351
|
-
});
|
|
9352
|
-
}
|
|
9353
|
-
clear() {
|
|
9354
|
-
const removed = this._storage.removeAll();
|
|
9355
|
-
return new Observable((x) => {
|
|
9356
|
-
x.next(removed);
|
|
9357
|
-
x.complete();
|
|
9358
|
-
});
|
|
9359
|
-
}
|
|
9360
|
-
all() {
|
|
9361
|
-
return this.allKeys().pipe(map((x) => filterMaybeArrayValues(x.map((y) => this._storage.getItem(y)))), shareReplay(1));
|
|
9460
|
+
class AbstractForwardDbxInjectionContextDirective {
|
|
9461
|
+
/**
|
|
9462
|
+
* The host-level {@link DbxInjectionContext} that all operations are forwarded to.
|
|
9463
|
+
*/
|
|
9464
|
+
dbxInjectionContext = inject(DbxInjectionContext, { host: true });
|
|
9465
|
+
// MARK: DbxInjectionContext
|
|
9466
|
+
/**
|
|
9467
|
+
* {@inheritDoc DbxInjectionContext.showContext}
|
|
9468
|
+
*
|
|
9469
|
+
* @param config - The injection context configuration to forward to the host context.
|
|
9470
|
+
* @returns Resolves to the output of the injected component's usage.
|
|
9471
|
+
*/
|
|
9472
|
+
showContext(config) {
|
|
9473
|
+
return this.dbxInjectionContext.showContext(config);
|
|
9362
9474
|
}
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9475
|
+
/**
|
|
9476
|
+
* {@inheritDoc DbxInjectionContext.resetContext}
|
|
9477
|
+
*
|
|
9478
|
+
* @returns `true` if an active context was cleared, `false` otherwise.
|
|
9479
|
+
*/
|
|
9480
|
+
resetContext() {
|
|
9481
|
+
return this.dbxInjectionContext.resetContext();
|
|
9369
9482
|
}
|
|
9483
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractForwardDbxInjectionContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
9484
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.4", type: AbstractForwardDbxInjectionContextDirective, isStandalone: true, ngImport: i0 });
|
|
9370
9485
|
}
|
|
9486
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: AbstractForwardDbxInjectionContextDirective, decorators: [{
|
|
9487
|
+
type: Directive
|
|
9488
|
+
}] });
|
|
9371
9489
|
|
|
9372
9490
|
/**
|
|
9373
|
-
*
|
|
9491
|
+
* Creates an RxJS operator that switches between injection component configs, falling back to a
|
|
9492
|
+
* default config when the source emits `null`, `undefined`, or `true`.
|
|
9374
9493
|
*
|
|
9375
|
-
*
|
|
9494
|
+
* If the `defaultConfig` resolves to a class (function), it is automatically wrapped into a
|
|
9495
|
+
* `{ componentClass }` config object.
|
|
9496
|
+
*
|
|
9497
|
+
* This is useful for reactive streams where an upstream value may indicate "use the default component"
|
|
9498
|
+
* rather than providing an explicit configuration.
|
|
9499
|
+
*
|
|
9500
|
+
* @param defaultConfig - A static value, getter, or component class to use as the fallback config.
|
|
9501
|
+
* @returns An RxJS operator compatible with `pipe()`.
|
|
9502
|
+
*
|
|
9503
|
+
* @see {@link DbxInjectionComponentConfig}
|
|
9504
|
+
* @typeParam T - The specific {@link DbxInjectionComponentConfig} subtype.
|
|
9505
|
+
* @typeParam X - The component type.
|
|
9506
|
+
*
|
|
9507
|
+
* @example
|
|
9508
|
+
* ```typescript
|
|
9509
|
+
* config$.pipe(
|
|
9510
|
+
* switchMapDbxInjectionComponentConfig(MyDefaultComponent)
|
|
9511
|
+
* ).subscribe(config => {
|
|
9512
|
+
* // config is always a DbxInjectionComponentConfig or undefined
|
|
9513
|
+
* });
|
|
9514
|
+
* ```
|
|
9376
9515
|
*/
|
|
9377
|
-
|
|
9516
|
+
function switchMapDbxInjectionComponentConfig(defaultConfig) {
|
|
9517
|
+
const defaultAsGetter = asGetter(defaultConfig);
|
|
9518
|
+
return switchMapObject({
|
|
9519
|
+
defaultGetter: () => {
|
|
9520
|
+
const value = defaultAsGetter();
|
|
9521
|
+
// if value is a function, it is a component class
|
|
9522
|
+
return typeof value === 'function' ? { componentClass: value } : value;
|
|
9523
|
+
}
|
|
9524
|
+
});
|
|
9525
|
+
}
|
|
9526
|
+
|
|
9378
9527
|
/**
|
|
9379
|
-
*
|
|
9528
|
+
* Creates a child injector with the given `type` as its sole provider and immediately
|
|
9529
|
+
* resolves an instance of that type.
|
|
9380
9530
|
*
|
|
9381
|
-
*
|
|
9531
|
+
* This is a convenience for one-off instantiation of an injectable class using a specific
|
|
9532
|
+
* parent injector, without needing to manually configure `Injector.create()`.
|
|
9533
|
+
*
|
|
9534
|
+
* @param type - The injectable class to provide and resolve.
|
|
9535
|
+
* @param parent - The parent injector that supplies the type's dependencies.
|
|
9536
|
+
* @returns A new instance of `T`.
|
|
9537
|
+
*
|
|
9538
|
+
* @typeParam T - The type to instantiate.
|
|
9539
|
+
*
|
|
9540
|
+
* @example
|
|
9541
|
+
* ```typescript
|
|
9542
|
+
* const service = newWithInjector(MyService, parentInjector);
|
|
9543
|
+
* ```
|
|
9382
9544
|
*/
|
|
9383
|
-
|
|
9545
|
+
function newWithInjector(type, parent) {
|
|
9546
|
+
const injector = Injector.create({ providers: [type], parent });
|
|
9547
|
+
return injector.get(type);
|
|
9548
|
+
}
|
|
9384
9549
|
|
|
9385
9550
|
/**
|
|
9386
|
-
*
|
|
9387
|
-
*
|
|
9551
|
+
* Abstract NgRx `ComponentStore` extension that integrates a {@link LockSet} for coordinating
|
|
9552
|
+
* async operations and delays destruction until all locks are released.
|
|
9553
|
+
*
|
|
9554
|
+
* Subclasses call {@link setupLockSet} to register parent lock sets and named locks.
|
|
9555
|
+
* On destroy, the store waits for all locks to unlock before completing cleanup,
|
|
9556
|
+
* preventing premature teardown of in-flight operations.
|
|
9557
|
+
*
|
|
9558
|
+
* @typeParam S - The shape of the component store's state object.
|
|
9388
9559
|
*
|
|
9389
9560
|
* @example
|
|
9390
9561
|
* ```typescript
|
|
9391
|
-
*
|
|
9392
|
-
* export class UserPrefsService {
|
|
9393
|
-
* private readonly storage = inject(SimpleStorageAccessorFactory)
|
|
9394
|
-
* .createStorageAccessor<UserPrefs>({ prefix: 'user_prefs' });
|
|
9562
|
+
* interface MyState { items: string[]; }
|
|
9395
9563
|
*
|
|
9396
|
-
*
|
|
9397
|
-
*
|
|
9564
|
+
* @Injectable()
|
|
9565
|
+
* export class MyStore extends LockSetComponentStore<MyState> {
|
|
9566
|
+
* constructor() {
|
|
9567
|
+
* super({ items: [] });
|
|
9568
|
+
* }
|
|
9398
9569
|
* }
|
|
9399
9570
|
* ```
|
|
9400
9571
|
*/
|
|
9401
|
-
class
|
|
9402
|
-
|
|
9403
|
-
|
|
9404
|
-
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9572
|
+
class LockSetComponentStore extends ComponentStore {
|
|
9573
|
+
initialState;
|
|
9574
|
+
lockSet = new LockSet();
|
|
9575
|
+
lockSetDestroyDelayMs = 2000;
|
|
9576
|
+
lockSetDestroyTimeoutMs;
|
|
9577
|
+
// NOTE: Injection does not occur here, but we need @Injectable to compile properly for Angular usage
|
|
9578
|
+
// eslint-disable-next-line @angular-eslint/prefer-inject
|
|
9579
|
+
constructor(initialState) {
|
|
9580
|
+
super(initialState);
|
|
9581
|
+
this.initialState = initialState;
|
|
9411
9582
|
}
|
|
9412
|
-
|
|
9413
|
-
|
|
9583
|
+
// MARK: State Changes
|
|
9584
|
+
resetStore = this.updater(() => ({ ...this.initialState }));
|
|
9585
|
+
// MARK: Locks
|
|
9586
|
+
setupLockSet({ parent, locks }) {
|
|
9587
|
+
if (parent) {
|
|
9588
|
+
this.setParentLockSet(parent);
|
|
9589
|
+
}
|
|
9590
|
+
if (locks) {
|
|
9591
|
+
for (const key in locks) {
|
|
9592
|
+
if (locks[key]) {
|
|
9593
|
+
this.addLock(key, locks[key]);
|
|
9594
|
+
}
|
|
9595
|
+
}
|
|
9596
|
+
}
|
|
9597
|
+
}
|
|
9598
|
+
setParentLockSet(obs) {
|
|
9599
|
+
this.lockSet.setParentLockSet(asObservable(obs).pipe(map((x) => x?.lockSet)));
|
|
9600
|
+
}
|
|
9601
|
+
addLock(key, obs) {
|
|
9602
|
+
this.lockSet.addLock(key, obs);
|
|
9603
|
+
}
|
|
9604
|
+
// MARK: Cleanup
|
|
9605
|
+
ngOnDestroy() {
|
|
9606
|
+
// Wait for any actions to complete before destroying.
|
|
9607
|
+
this.lockSet.destroyOnNextUnlock({
|
|
9608
|
+
fn: () => {
|
|
9609
|
+
this._destroyNow();
|
|
9610
|
+
},
|
|
9611
|
+
timeout: this.lockSetDestroyTimeoutMs
|
|
9612
|
+
}, this.lockSetDestroyDelayMs);
|
|
9613
|
+
}
|
|
9614
|
+
/**
|
|
9615
|
+
* Immediately completes cleanup by destroying the lock set.
|
|
9616
|
+
* Called after all locks are released during the deferred destruction process.
|
|
9617
|
+
*/
|
|
9618
|
+
_destroyNow() {
|
|
9619
|
+
this.lockSet.destroy();
|
|
9620
|
+
}
|
|
9621
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: LockSetComponentStore, deps: [{ token: null, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
9622
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: LockSetComponentStore });
|
|
9414
9623
|
}
|
|
9415
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type:
|
|
9624
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: LockSetComponentStore, decorators: [{
|
|
9416
9625
|
type: Injectable
|
|
9417
|
-
}]
|
|
9626
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
9627
|
+
type: Inject,
|
|
9628
|
+
args: [null]
|
|
9629
|
+
}, {
|
|
9630
|
+
type: Optional
|
|
9631
|
+
}] }] });
|
|
9418
9632
|
|
|
9419
9633
|
/**
|
|
9420
9634
|
* Abstract storage accessor providing key-value get/set/remove operations and a clear-all method.
|
|
@@ -9652,5 +9866,5 @@ function hasNonTrivialChildNodes(element) {
|
|
|
9652
9866
|
* Generated bundle index. Do not edit.
|
|
9653
9867
|
*/
|
|
9654
9868
|
|
|
9655
|
-
export { ACTION_CONTEXT_STORE_LOCKSET_DESTROY_DELAY_TIME, APP_ACTION_DISABLED_DIRECTIVE_KEY, APP_ACTION_DISABLED_ON_SUCCESS_DIRECTIVE_KEY, APP_ACTION_ENFORCE_MODIFIED_DIRECTIVE_KEY, AbstractDbxActionHandlerDirective, AbstractDbxActionValueGetterDirective, AbstractDbxAnchorDirective, AbstractDbxButtonDirective, AbstractDbxFilterMapInstanceDirective, AbstractDbxFilterMapSourceDirective, AbstractDbxInjectionDirective, AbstractFilterSourceConnectorDirective, AbstractFilterSourceDirective, AbstractForwardDbxInjectionContextDirective, AbstractIfDirective, AbstractTransitionDirective, AbstractTransitionWatcherDirective, ActionContextStore, ActionContextStoreSource, ActionContextStoreSourceMap, AsObservablePipe, CutTextPipe, DBX_ACTION_BUTTON_ECHO_CONFIG, DBX_ACTION_HANDLER_LOCK_KEY, DBX_APP_APP_CONTEXT_STATE, DBX_APP_AUTH_ROUTER_EFFECTS_TOKEN, DBX_ASSET_LOADER_CONFIG_TOKEN, DBX_AUTH_APP_CONTEXT_STATE, DBX_INIT_APP_CONTEXT_STATE, DBX_INJECTION_COMPONENT_DATA, DBX_KNOWN_APP_CONTEXT_STATES, DBX_OAUTH_APP_CONTEXT_STATE, DBX_ONBOARD_APP_CONTEXT_STATE, DBX_PUBLIC_APP_CONTEXT_STATE, DEFAULT_ACTION_DISABLED_KEY, DEFAULT_ACTION_MAP_WORKING_DISABLED_KEY, DEFAULT_DBX_ACTION_BUTTON_ECHO_CONFIG, DEFAULT_DBX_ACTION_BUTTON_ERROR_ECHO, DEFAULT_DBX_ACTION_BUTTON_SUCCESS_ECHO, DEFAULT_DBX_BUTTON_ECHO_DURATION, DEFAULT_DBX_ROUTE_MODEL_ID_PARAM_ID_PARAM_KEY, DEFAULT_DBX_ROUTE_MODEL_ID_PARAM_KEY_PARAM_KEY, DEFAULT_DBX_ROUTE_MODEL_ID_PARAM_USE_PARAM_VALUE, DEFAULT_FILTER_SOURCE_DIRECTIVE_FILTER_TOKEN, DEFAULT_LOCAL_ASSET_BASE_URL, DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_KEY, DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_VALUE, DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_KEY, DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_VALUE, DEFAULT_STORAGE_ACCESSOR_FACTORY_TOKEN, DEFAULT_STORAGE_OBJECT_TOKEN, DateDayRangePipe, DateDayTimeRangePipe, DateDistancePipe, DateFormatDistancePipe, DateFormatFromToPipe, DateRangeDistancePipe, DateTimeRangeOnlyDistancePipe, DateTimeRangeOnlyPipe, DateTimeRangePipe, DbxActionAutoModifyDirective, DbxActionAutoTriggerDirective, DbxActionButtonDirective, DbxActionButtonTriggerDirective, DbxActionContextBaseSource, DbxActionContextLoggerDirective, DbxActionContextMachine, DbxActionContextMachineAsService, DbxActionContextMapDirective, DbxActionContextStoreSourceInstance, DbxActionDirective, DbxActionDisabledDirective, DbxActionDisabledOnSuccessDirective, DbxActionEnforceModifiedDirective, DbxActionErrorHandlerDirective, DbxActionFromMapDirective, DbxActionHandlerDirective, DbxActionHandlerInstance, DbxActionHandlerValueDirective, DbxActionHasSuccessDirective, DbxActionIdleDirective, DbxActionIsModifiedDirective, DbxActionIsWorkingDirective, DbxActionMapSourceDirective, DbxActionMapWorkingDisableDirective, DbxActionPreSuccessDirective, DbxActionSourceDirective, DbxActionState, DbxActionSuccessHandlerDirective, DbxActionTriggeredDirective, DbxActionValueDirective, DbxActionValueGetterInstance, DbxActionValueStreamDirective, DbxActionValueTriggerDirective, DbxActionWorkInstanceDelegate, DbxActionWorkable, DbxAnchor, DbxAngularRouterService, DbxAppAuthRouterEffects, DbxAppAuthRouterService, DbxAppAuthRoutes, DbxAppAuthStateService, DbxAppContextService, DbxAppContextStateDirective, DbxAppEnvironment, DbxAppEnvironmentService, DbxAuthHasAnyRoleDirective, DbxAuthHasRolesDirective, DbxAuthImpersonationDelegate, DbxAuthImpersonationQuerySyncDirective, DbxAuthImpersonationService, DbxAuthImpersonationTriggerDirective, DbxAuthNotAnyRoleDirective, DbxAuthService, DbxButton, DbxButtonDirective, DbxButtonSegueDirective, DbxCoreActionModule, DbxCoreAngularRouterSegueModule, DbxCoreAssetLoader, DbxCoreButtonModule, DbxCoreFilterModule, DbxFilterConnectSourceDirective, DbxFilterMapDirective, DbxFilterMapSourceConnectorDirective, DbxFilterMapSourceDirective, DbxFilterSourceConnectorDirective, DbxFilterSourceDirective, DbxInjectionArrayComponent, DbxInjectionComponent, DbxInjectionContext, DbxInjectionContextDirective, DbxInjectionInstance, DbxLoadingButtonDirective, DbxRouteModelIdDirective, DbxRouteModelIdDirectiveDelegate, DbxRouteModelIdFromAuthUserIdDirective, DbxRouteModelKeyDirective, DbxRouteModelKeyDirectiveDelegate, DbxRouteParamDefaultRedirectInstance, DbxRouterService, DbxRouterTransitionEventType, DbxRouterTransitionService, DbxUIRouterService, DollarAmountPipe, FilterSourceDirective, FullLocalStorageObject, GetValueOncePipe, GetValuePipe, InstantStorageAccessor, LimitedStorageAccessor, LockSetComponentStore, MemoryStorageObject, MinutesStringPipe, NO_AUTH_USER_IDENTIFIER, PrettyJsonPipe, SecondaryActionContextStoreSource, SimpleStorageAccessor, SimpleStorageAccessorFactory, StorageAccessor, StringStorageAccessor, StringifySimpleStorageAccessorConverter, SystemDateToTargetDatePipe, TargetDateToSystemDatePipe, TimeDistanceCountdownPipe, TimeDistancePipe, TimezoneAbbreviationPipe, ToJsDatePipe, ToMinutesPipe, WrapperSimpleStorageAccessorDelegate, actionContextHasNoErrorAndIsModifiedAndCanTrigger, actionContextIsModifiedAndCanTrigger, actionContextStoreSourceMap, actionContextStoreSourceMapReader, actionContextStoreSourcePipe, anchorTypeForAnchor, asSegueRef, asSegueRefString, assertValidStorageKeyPrefix, authRolesSetContainsAllRolesFrom, authRolesSetContainsAnyRoleFrom, authRolesSetContainsNoRolesFrom, authUserIdentifier, canReadyValue, canTriggerAction, canTriggerActionState, checkNgContentWrapperHasContent, clean, cleanDestroy, cleanListLoadingContext, cleanLoadingContext, cleanLockSet, cleanSubscription, cleanSubscriptionWithLockSet, cleanWithLockSet, clickableUrlInNewTab, clickableUrlMailTo, clickableUrlTel, completeOnDestroy, createInjectorForInjectionComponentConfig, dbxActionWorkProgress, dbxButtonDisplayType, dbxInjectionComponentConfigIsEqual, dbxRouteModelIdParamRedirect, dbxRouteModelKeyParamRedirect, dbxRouteParamReaderInstance, defaultStorageObjectFactory, enableHasAuthRoleHook, enableHasAuthStateHook, enableIsLoggedInHook, expandClickableAnchorLinkTree, expandClickableAnchorLinkTreeNode, expandClickableAnchorLinkTrees, filterTransitionEvent, filterTransitionSuccess, flattenExpandedClickableAnchorLinkTree, flattenExpandedClickableAnchorLinkTreeToLinks, fromAllActionContextStoreSourceMapSources, index as fromDbxAppAuth, index$2 as fromDbxAppContext, goWithRouter, hasAuthRoleDecisionPipe, hasNonTrivialChildNodes, initInjectionComponent, isActionContextDisabled, isActionContextEnabled, isClickableFilterPreset, isClickablePartialFilterPreset, isDisabledActionContextState, isIdleActionState, isLatestSuccessfulRoute, isSegueRef, isSegueRefActive, isSegueRefActiveFunction, isSegueRefActiveOnTransitionSuccess, isValidStorageKeyPrefix, isWorkingActionState, latestSuccessfulRoutes, loadingStateForActionContextState, loadingStateTypeForActionContextState, loadingStateTypeForActionState, loggedInObsFromIsLoggedIn, loggedOutObsFromIsLoggedIn, makeAuthTransitionHook, makeDbxActionContextSourceReference, mapRefStringObsToSegueRefObs, mergeDbxInjectionComponentConfigs, mergeStaticProviders, newWithInjector, index$1 as onDbxAppAuth, index$3 as onDbxAppContext, onRouterTransitionEventType, onRouterTransitionSuccessEvent, pipeActionStore, provideActionStoreSource, provideDbxActionButtonEchoConfig, provideDbxActionWorkable, provideDbxAnchor, provideDbxAppAuth, provideDbxAppAuthRouter, provideDbxAppAuthRouterState, provideDbxAppAuthState, provideDbxAppContextState, provideDbxAppEnvironment, provideDbxAssetLoader, provideDbxAuthImpersonation, provideDbxAuthImpersonationDelegate, provideDbxButton, provideDbxInjectionContext, provideDbxRouteModelIdDirectiveDelegate, provideDbxRouteModelKeyDirectiveDelegate, provideDbxStorage, provideDbxUIRouterService, provideFilterSource, provideFilterSourceConnector, provideFilterSourceDirective, provideSecondaryActionStoreSource, redirectBasedOnAuthUserState, redirectForIdentifierParamHook, redirectForUserIdentifierParamHook, refStringToSegueRef, successTransition, switchMapDbxInjectionComponentConfig, transformEmptyStringInputToUndefined, useActionStore };
|
|
9869
|
+
export { ACTION_CONTEXT_STORE_LOCKSET_DESTROY_DELAY_TIME, APP_ACTION_DISABLED_DIRECTIVE_KEY, APP_ACTION_DISABLED_ON_SUCCESS_DIRECTIVE_KEY, APP_ACTION_ENFORCE_MODIFIED_DIRECTIVE_KEY, AbstractDbxActionHandlerDirective, AbstractDbxActionValueGetterDirective, AbstractDbxAnchorDirective, AbstractDbxButtonDirective, AbstractDbxFilterMapInstanceDirective, AbstractDbxFilterMapSourceDirective, AbstractDbxInjectionDirective, AbstractFilterSourceConnectorDirective, AbstractFilterSourceDirective, AbstractForwardDbxInjectionContextDirective, AbstractIfDirective, AbstractTransitionDirective, AbstractTransitionWatcherDirective, ActionContextStore, ActionContextStoreSource, ActionContextStoreSourceMap, AsObservablePipe, CutTextPipe, DBX_ACTION_BUTTON_ECHO_CONFIG, DBX_ACTION_HANDLER_LOCK_KEY, DBX_APP_APP_CONTEXT_STATE, DBX_APP_AUTH_ROUTER_EFFECTS_TOKEN, DBX_ASSET_LOADER_CONFIG_TOKEN, DBX_AUTH_APP_CONTEXT_STATE, DBX_FILTER_STORAGE_SERVICE_CONFIG_TOKEN, DBX_INIT_APP_CONTEXT_STATE, DBX_INJECTION_COMPONENT_DATA, DBX_KNOWN_APP_CONTEXT_STATES, DBX_OAUTH_APP_CONTEXT_STATE, DBX_ONBOARD_APP_CONTEXT_STATE, DBX_PUBLIC_APP_CONTEXT_STATE, DEFAULT_ACTION_DISABLED_KEY, DEFAULT_ACTION_MAP_WORKING_DISABLED_KEY, DEFAULT_DBX_ACTION_BUTTON_ECHO_CONFIG, DEFAULT_DBX_ACTION_BUTTON_ERROR_ECHO, DEFAULT_DBX_ACTION_BUTTON_SUCCESS_ECHO, DEFAULT_DBX_BUTTON_ECHO_DURATION, DEFAULT_DBX_FILTER_STORAGE_PREFIX, DEFAULT_DBX_ROUTE_MODEL_ID_PARAM_ID_PARAM_KEY, DEFAULT_DBX_ROUTE_MODEL_ID_PARAM_KEY_PARAM_KEY, DEFAULT_DBX_ROUTE_MODEL_ID_PARAM_USE_PARAM_VALUE, DEFAULT_FILTER_SOURCE_DIRECTIVE_FILTER_TOKEN, DEFAULT_LOCAL_ASSET_BASE_URL, DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_KEY, DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_VALUE, DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_KEY, DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_VALUE, DEFAULT_STORAGE_ACCESSOR_FACTORY_TOKEN, DEFAULT_STORAGE_OBJECT_TOKEN, DateDayRangePipe, DateDayTimeRangePipe, DateDistancePipe, DateFormatDistancePipe, DateFormatFromToPipe, DateRangeDistancePipe, DateTimeRangeOnlyDistancePipe, DateTimeRangeOnlyPipe, DateTimeRangePipe, DbxActionAutoModifyDirective, DbxActionAutoTriggerDirective, DbxActionButtonDirective, DbxActionButtonTriggerDirective, DbxActionContextBaseSource, DbxActionContextLoggerDirective, DbxActionContextMachine, DbxActionContextMachineAsService, DbxActionContextMapDirective, DbxActionContextStoreSourceInstance, DbxActionDirective, DbxActionDisabledDirective, DbxActionDisabledOnSuccessDirective, DbxActionEnforceModifiedDirective, DbxActionErrorHandlerDirective, DbxActionFromMapDirective, DbxActionHandlerDirective, DbxActionHandlerInstance, DbxActionHandlerValueDirective, DbxActionHasSuccessDirective, DbxActionIdleDirective, DbxActionIsModifiedDirective, DbxActionIsWorkingDirective, DbxActionMapSourceDirective, DbxActionMapWorkingDisableDirective, DbxActionPreSuccessDirective, DbxActionSourceDirective, DbxActionState, DbxActionSuccessHandlerDirective, DbxActionTriggeredDirective, DbxActionValueDirective, DbxActionValueGetterInstance, DbxActionValueStreamDirective, DbxActionValueTriggerDirective, DbxActionWorkInstanceDelegate, DbxActionWorkable, DbxAnchor, DbxAngularRouterService, DbxAppAuthRouterEffects, DbxAppAuthRouterService, DbxAppAuthRoutes, DbxAppAuthStateService, DbxAppContextService, DbxAppContextStateDirective, DbxAppEnvironment, DbxAppEnvironmentService, DbxAuthHasAnyRoleDirective, DbxAuthHasRolesDirective, DbxAuthImpersonationDelegate, DbxAuthImpersonationQuerySyncDirective, DbxAuthImpersonationService, DbxAuthImpersonationTriggerDirective, DbxAuthNotAnyRoleDirective, DbxAuthService, DbxButton, DbxButtonDirective, DbxButtonSegueDirective, DbxCoreActionModule, DbxCoreAngularRouterSegueModule, DbxCoreAssetLoader, DbxCoreButtonModule, DbxCoreFilterModule, DbxFilterConnectSourceDirective, DbxFilterMapDirective, DbxFilterMapMergeSourceDirective, DbxFilterMapSourceConnectorDirective, DbxFilterMapSourceDirective, DbxFilterMapStorageDirective, DbxFilterSourceConnectorDirective, DbxFilterSourceDirective, DbxFilterStorageService, DbxInjectionArrayComponent, DbxInjectionComponent, DbxInjectionContext, DbxInjectionContextDirective, DbxInjectionInstance, DbxLoadingButtonDirective, DbxRouteModelIdDirective, DbxRouteModelIdDirectiveDelegate, DbxRouteModelIdFromAuthUserIdDirective, DbxRouteModelKeyDirective, DbxRouteModelKeyDirectiveDelegate, DbxRouteParamDefaultRedirectInstance, DbxRouterService, DbxRouterTransitionEventType, DbxRouterTransitionService, DbxUIRouterService, DollarAmountPipe, FilterSourceDirective, FullLocalStorageObject, GetValueOncePipe, GetValuePipe, InstantStorageAccessor, LimitedStorageAccessor, LockSetComponentStore, MemoryStorageObject, MinutesStringPipe, NO_AUTH_USER_IDENTIFIER, PrettyJsonPipe, SecondaryActionContextStoreSource, SimpleStorageAccessor, SimpleStorageAccessorFactory, StorageAccessor, StringStorageAccessor, StringifySimpleStorageAccessorConverter, SystemDateToTargetDatePipe, TargetDateToSystemDatePipe, TimeDistanceCountdownPipe, TimeDistancePipe, TimezoneAbbreviationPipe, ToJsDatePipe, ToMinutesPipe, WrapperSimpleStorageAccessorDelegate, actionContextHasNoErrorAndIsModifiedAndCanTrigger, actionContextIsModifiedAndCanTrigger, actionContextStoreSourceMap, actionContextStoreSourceMapReader, actionContextStoreSourcePipe, anchorTypeForAnchor, asSegueRef, asSegueRefString, assertValidStorageKeyPrefix, authRolesSetContainsAllRolesFrom, authRolesSetContainsAnyRoleFrom, authRolesSetContainsNoRolesFrom, authUserIdentifier, canReadyValue, canTriggerAction, canTriggerActionState, checkNgContentWrapperHasContent, clean, cleanDestroy, cleanListLoadingContext, cleanLoadingContext, cleanLockSet, cleanSubscription, cleanSubscriptionWithLockSet, cleanWithLockSet, clickableUrlInNewTab, clickableUrlMailTo, clickableUrlTel, completeOnDestroy, createInjectorForInjectionComponentConfig, dbxActionWorkProgress, dbxButtonDisplayType, dbxInjectionComponentConfigIsEqual, dbxRouteModelIdParamRedirect, dbxRouteModelKeyParamRedirect, dbxRouteParamReaderInstance, defaultStorageObjectFactory, enableHasAuthRoleHook, enableHasAuthStateHook, enableIsLoggedInHook, expandClickableAnchorLinkTree, expandClickableAnchorLinkTreeNode, expandClickableAnchorLinkTrees, filterTransitionEvent, filterTransitionSuccess, flattenExpandedClickableAnchorLinkTree, flattenExpandedClickableAnchorLinkTreeToLinks, fromAllActionContextStoreSourceMapSources, index as fromDbxAppAuth, index$2 as fromDbxAppContext, goWithRouter, hasAuthRoleDecisionPipe, hasNonTrivialChildNodes, initInjectionComponent, isActionContextDisabled, isActionContextEnabled, isClickableFilterPreset, isClickablePartialFilterPreset, isDisabledActionContextState, isIdleActionState, isLatestSuccessfulRoute, isSegueRef, isSegueRefActive, isSegueRefActiveFunction, isSegueRefActiveOnTransitionSuccess, isValidStorageKeyPrefix, isWorkingActionState, latestSuccessfulRoutes, loadingStateForActionContextState, loadingStateTypeForActionContextState, loadingStateTypeForActionState, loggedInObsFromIsLoggedIn, loggedOutObsFromIsLoggedIn, makeAuthTransitionHook, makeDbxActionContextSourceReference, mapRefStringObsToSegueRefObs, mergeDbxInjectionComponentConfigs, mergeStaticProviders, newWithInjector, index$1 as onDbxAppAuth, index$3 as onDbxAppContext, onRouterTransitionEventType, onRouterTransitionSuccessEvent, pipeActionStore, provideActionStoreSource, provideDbxActionButtonEchoConfig, provideDbxActionWorkable, provideDbxAnchor, provideDbxAppAuth, provideDbxAppAuthRouter, provideDbxAppAuthRouterState, provideDbxAppAuthState, provideDbxAppContextState, provideDbxAppEnvironment, provideDbxAssetLoader, provideDbxAuthImpersonation, provideDbxAuthImpersonationDelegate, provideDbxButton, provideDbxFilterStorage, provideDbxInjectionContext, provideDbxRouteModelIdDirectiveDelegate, provideDbxRouteModelKeyDirectiveDelegate, provideDbxStorage, provideDbxUIRouterService, provideFilterSource, provideFilterSourceConnector, provideFilterSourceDirective, provideSecondaryActionStoreSource, redirectBasedOnAuthUserState, redirectForIdentifierParamHook, redirectForUserIdentifierParamHook, refStringToSegueRef, successTransition, switchMapDbxInjectionComponentConfig, transformEmptyStringInputToUndefined, useActionStore };
|
|
9656
9870
|
//# sourceMappingURL=dereekb-dbx-core.mjs.map
|