@quadrel-enterprise-ui/framework 20.14.0 → 20.15.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/quadrel-enterprise-ui-framework.mjs +631 -415
- package/fesm2022/quadrel-enterprise-ui-framework.mjs.map +1 -1
- package/index.d.ts +226 -191
- package/package.json +1 -1
- package/src/assets/i18n/de.json +4 -0
- package/src/assets/i18n/en.json +6 -0
- package/src/assets/i18n/fr.json +6 -0
- package/src/assets/i18n/it.json +6 -0
|
@@ -18,8 +18,8 @@ import { NG_VALUE_ACCESSOR, FormsModule, UntypedFormControl, UntypedFormArray, U
|
|
|
18
18
|
import { ComponentPortal } from '@angular/cdk/portal';
|
|
19
19
|
import { OverlayPositionBuilder, Overlay } from '@angular/cdk/overlay';
|
|
20
20
|
import isNumber from 'lodash/isNumber';
|
|
21
|
-
import { EventSourcePolyfill } from 'event-source-polyfill';
|
|
22
21
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
22
|
+
import { EventSourcePolyfill } from 'event-source-polyfill';
|
|
23
23
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
24
24
|
import * as i3$1 from 'ngx-editor';
|
|
25
25
|
import { Editor, NgxEditorModule } from 'ngx-editor';
|
|
@@ -1604,6 +1604,24 @@ const updateHtmlLang = (lang) => {
|
|
|
1604
1604
|
const htmlNode = document.documentElement;
|
|
1605
1605
|
htmlNode.setAttribute('lang', lang);
|
|
1606
1606
|
};
|
|
1607
|
+
const SERVICE_NAV_LOCALE_DEFAULTS = {
|
|
1608
|
+
DE: 'de-CH',
|
|
1609
|
+
IT: 'it-CH',
|
|
1610
|
+
FR: 'fr-CH',
|
|
1611
|
+
EN: 'en-GB'
|
|
1612
|
+
};
|
|
1613
|
+
const determineLocale = (serviceNavLanguage, browserLocales) => {
|
|
1614
|
+
const browserLocale = browserLocales?.[0] ?? navigator.language;
|
|
1615
|
+
if (!serviceNavLanguage) {
|
|
1616
|
+
const browserLocaleUpper = browserLocale.toUpperCase();
|
|
1617
|
+
return SERVICE_NAV_LOCALE_DEFAULTS[browserLocaleUpper] ?? browserLocale;
|
|
1618
|
+
}
|
|
1619
|
+
const serviceNavLangUpper = serviceNavLanguage.toUpperCase();
|
|
1620
|
+
const browserLanguage = browserLocale.split('-')[0].toUpperCase();
|
|
1621
|
+
if (browserLanguage === serviceNavLangUpper)
|
|
1622
|
+
return browserLocale;
|
|
1623
|
+
return SERVICE_NAV_LOCALE_DEFAULTS[serviceNavLangUpper] ?? browserLocale;
|
|
1624
|
+
};
|
|
1607
1625
|
|
|
1608
1626
|
const constantCase = (str) => upperCase(str).replace(/ /g, '_');
|
|
1609
1627
|
|
|
@@ -6636,6 +6654,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
6636
6654
|
}]
|
|
6637
6655
|
}] });
|
|
6638
6656
|
|
|
6657
|
+
const QD_SAFE_BOTTOM_OFFSET = new InjectionToken('QD_SAFE_BOTTOM_OFFSET');
|
|
6658
|
+
|
|
6639
6659
|
let QdFileSizePipe$1 = class QdFileSizePipe {
|
|
6640
6660
|
translate = inject(TranslateService, { optional: true });
|
|
6641
6661
|
transform(bytes) {
|
|
@@ -6687,6 +6707,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
6687
6707
|
}]
|
|
6688
6708
|
}] });
|
|
6689
6709
|
|
|
6710
|
+
const QD_POPOVER_TOP_FIRST = new InjectionToken('QD_POPOVER_TOP_FIRST');
|
|
6711
|
+
|
|
6690
6712
|
class QdProjectionGuardComponent {
|
|
6691
6713
|
elementRef = inject(ElementRef);
|
|
6692
6714
|
isDisabled = false;
|
|
@@ -6715,406 +6737,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
6715
6737
|
type: Input
|
|
6716
6738
|
}] } });
|
|
6717
6739
|
|
|
6718
|
-
class QdRwdDisabledDirective {
|
|
6719
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
6720
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdRwdDisabledDirective, isStandalone: false, selector: "[qdRwdDisabled]", host: { classAttribute: "qd-rwd-disabled" }, ngImport: i0 });
|
|
6721
|
-
}
|
|
6722
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, decorators: [{
|
|
6723
|
-
type: Directive,
|
|
6724
|
-
args: [{
|
|
6725
|
-
selector: '[qdRwdDisabled]',
|
|
6726
|
-
host: { class: 'qd-rwd-disabled' },
|
|
6727
|
-
standalone: false
|
|
6728
|
-
}]
|
|
6729
|
-
}] });
|
|
6730
|
-
|
|
6731
|
-
var breakpoints$1 = {
|
|
6732
|
-
xs: 320,
|
|
6733
|
-
sm: 600,
|
|
6734
|
-
md: 960,
|
|
6735
|
-
lg: 1280,
|
|
6736
|
-
xl: 1600,
|
|
6737
|
-
xxl: 1800
|
|
6738
|
-
};
|
|
6739
|
-
var panel = {
|
|
6740
|
-
sm: 432,
|
|
6741
|
-
md: 588,
|
|
6742
|
-
lg: 720
|
|
6743
|
-
};
|
|
6744
|
-
var base = {
|
|
6745
|
-
fontsize: 16
|
|
6746
|
-
};
|
|
6747
|
-
var globalVars = {
|
|
6748
|
-
breakpoints: breakpoints$1,
|
|
6749
|
-
panel: panel,
|
|
6750
|
-
base: base
|
|
6751
|
-
};
|
|
6752
|
-
|
|
6753
|
-
const convertPxToRem = (pixel) => `${parseFloat((pixel / globalVars.base.fontsize).toFixed(3))}rem`;
|
|
6754
|
-
|
|
6755
|
-
class QdTooltipComponent {
|
|
6756
|
-
content;
|
|
6757
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6758
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipComponent, isStandalone: false, selector: "qd-tooltip", inputs: { content: "content" }, ngImport: i0, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
6759
|
-
}
|
|
6760
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, decorators: [{
|
|
6761
|
-
type: Component,
|
|
6762
|
-
args: [{ selector: 'qd-tooltip', standalone: false, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"] }]
|
|
6763
|
-
}], propDecorators: { content: [{
|
|
6764
|
-
type: Input
|
|
6765
|
-
}] } });
|
|
6766
|
-
|
|
6767
|
-
const TARGET_SELECTOR = '.qd-intersection-target';
|
|
6768
|
-
const SHOW_EVENTS = ['mouseenter', 'mousemove'];
|
|
6769
|
-
const HIDE_EVENTS = ['mouseleave', 'click'];
|
|
6770
|
-
const HIDE_DELAY = 300;
|
|
6771
|
-
const OVERLAY_WIDTH = 280;
|
|
6772
|
-
const UNSUBSCRIBE_IMMEDIATELY = true;
|
|
6773
|
-
const THRESHOLD = 1;
|
|
6774
|
-
/**
|
|
6775
|
-
* QdTooltipAtIntersectionDirective provides a tooltip. This will be triggered if the content is intersected.
|
|
6776
|
-
*
|
|
6777
|
-
* * Selector: [qdTooltipAtIntersection]
|
|
6778
|
-
* * Target Selector: .qd-intersection-target
|
|
6779
|
-
*
|
|
6780
|
-
* The IntersectionObserver API is used for the implementation.
|
|
6781
|
-
* * @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
|
|
6782
|
-
*
|
|
6783
|
-
* * Note: The intersection of the target is calculated by the IntersectionObserver only once, initially (can be extended later if required). After that it will be unsubscribed immediately.
|
|
6784
|
-
* */
|
|
6785
|
-
class QdTooltipAtIntersectionDirective {
|
|
6786
|
-
_host = inject(ElementRef);
|
|
6787
|
-
_positionBuilder = inject(OverlayPositionBuilder);
|
|
6788
|
-
_overlay = inject(Overlay);
|
|
6789
|
-
_overlayRef;
|
|
6790
|
-
_target;
|
|
6791
|
-
_observer$;
|
|
6792
|
-
_isIntersected = false;
|
|
6793
|
-
_destroyed$ = new Subject();
|
|
6794
|
-
ngAfterViewInit() {
|
|
6795
|
-
this.setTarget();
|
|
6796
|
-
this.observeTarget();
|
|
6797
|
-
this.createOverlay();
|
|
6798
|
-
this.subscribeShow();
|
|
6799
|
-
this.subscribeHide();
|
|
6800
|
-
}
|
|
6801
|
-
ngOnDestroy() {
|
|
6802
|
-
this._observer$.unobserve(this._target);
|
|
6803
|
-
this._destroyed$.next();
|
|
6804
|
-
this._destroyed$.complete();
|
|
6805
|
-
}
|
|
6806
|
-
setTarget() {
|
|
6807
|
-
this._target = this._host.nativeElement.querySelector(TARGET_SELECTOR);
|
|
6808
|
-
}
|
|
6809
|
-
observeTarget() {
|
|
6810
|
-
const options = {
|
|
6811
|
-
root: this._host.nativeElement,
|
|
6812
|
-
threshold: THRESHOLD
|
|
6813
|
-
};
|
|
6814
|
-
this._observer$ = new IntersectionObserver(entries => {
|
|
6815
|
-
this._isIntersected = entries[0].intersectionRatio < 1;
|
|
6816
|
-
if (this._isIntersected) {
|
|
6817
|
-
this._setStyles();
|
|
6818
|
-
if (UNSUBSCRIBE_IMMEDIATELY)
|
|
6819
|
-
this._observer$.unobserve(this._target);
|
|
6820
|
-
}
|
|
6821
|
-
}, options);
|
|
6822
|
-
this._observer$.observe(this._target);
|
|
6823
|
-
}
|
|
6824
|
-
_setStyles() {
|
|
6825
|
-
this._target.style.overflow = 'hidden';
|
|
6826
|
-
this._target.style.textOverflow = 'ellipsis';
|
|
6827
|
-
this._target.style.cursor = 'help';
|
|
6828
|
-
}
|
|
6829
|
-
createOverlay() {
|
|
6830
|
-
this._overlayRef = this._overlay.create({
|
|
6831
|
-
positionStrategy: this._positionBuilder
|
|
6832
|
-
.flexibleConnectedTo(this._host)
|
|
6833
|
-
.withPositions([{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' }]),
|
|
6834
|
-
width: convertPxToRem(OVERLAY_WIDTH)
|
|
6835
|
-
});
|
|
6836
|
-
}
|
|
6837
|
-
subscribeShow() {
|
|
6838
|
-
merge(...SHOW_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
|
|
6839
|
-
.pipe(takeUntil(this._destroyed$), filter(() => !this._overlayRef.hasAttached() && this._isIntersected))
|
|
6840
|
-
.subscribe(() => {
|
|
6841
|
-
const content = this.getContent();
|
|
6842
|
-
const tooltipPortal = new ComponentPortal(QdTooltipComponent);
|
|
6843
|
-
const tooltipRef = this._overlayRef.attach(tooltipPortal);
|
|
6844
|
-
tooltipRef.instance.content = content;
|
|
6845
|
-
});
|
|
6846
|
-
}
|
|
6847
|
-
subscribeHide() {
|
|
6848
|
-
merge(...HIDE_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
|
|
6849
|
-
.pipe(takeUntil(this._destroyed$), filter(() => this._overlayRef.hasAttached()), debounceTime(HIDE_DELAY))
|
|
6850
|
-
.subscribe(() => this._overlayRef.detach());
|
|
6851
|
-
}
|
|
6852
|
-
getContent() {
|
|
6853
|
-
return {
|
|
6854
|
-
headline: this._target.getAttribute('data-tooltip-headline') || undefined,
|
|
6855
|
-
paragraphs: [this._target.textContent?.trim() || '']
|
|
6856
|
-
};
|
|
6857
|
-
}
|
|
6858
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
6859
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipAtIntersectionDirective, isStandalone: false, selector: "[qdTooltipAtIntersection]", ngImport: i0 });
|
|
6860
|
-
}
|
|
6861
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, decorators: [{
|
|
6862
|
-
type: Directive,
|
|
6863
|
-
args: [{
|
|
6864
|
-
selector: '[qdTooltipAtIntersection]',
|
|
6865
|
-
standalone: false
|
|
6866
|
-
}]
|
|
6867
|
-
}] });
|
|
6868
|
-
|
|
6869
|
-
class QdVisuallyHiddenDirective {
|
|
6870
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
6871
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdVisuallyHiddenDirective, isStandalone: false, selector: "[qdVisuallyHidden]", host: { classAttribute: "qd-visually-hidden" }, ngImport: i0 });
|
|
6872
|
-
}
|
|
6873
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, decorators: [{
|
|
6874
|
-
type: Directive,
|
|
6875
|
-
args: [{
|
|
6876
|
-
selector: '[qdVisuallyHidden]',
|
|
6877
|
-
host: { class: 'qd-visually-hidden' },
|
|
6878
|
-
standalone: false
|
|
6879
|
-
}]
|
|
6880
|
-
}] });
|
|
6881
|
-
|
|
6882
|
-
/**
|
|
6883
|
-
* Manages a server-sent event (SSE) connection with automatic reconnection and heartbeat monitoring.
|
|
6884
|
-
*
|
|
6885
|
-
* All service endpoints — including SSE — must be protected. The connection is therefore secured
|
|
6886
|
-
* via Quadrel Auth (Bearer token) by default. When the access token refreshes, the connection is
|
|
6887
|
-
* transparently rebuilt. Only disable authentication for endpoints that are explicitly public.
|
|
6888
|
-
*
|
|
6889
|
-
* ### Reconnection behavior
|
|
6890
|
-
*
|
|
6891
|
-
* - **Heartbeat timeout**: If no HEARTBEAT event arrives within the expected interval, the service reconnects.
|
|
6892
|
-
* - **401 Unauthorized**: Triggers exponential-backoff reconnection (max 5 attempts, capped at 30 s).
|
|
6893
|
-
* - **Other errors**: Reconnects immediately when the EventSource transitions to CLOSED.
|
|
6894
|
-
*
|
|
6895
|
-
* Existing `observe()` subscriptions are preserved across reconnections.
|
|
6896
|
-
*
|
|
6897
|
-
* ### Usage
|
|
6898
|
-
*
|
|
6899
|
-
* ```ts
|
|
6900
|
-
* pushEventsService.connect('https://api.example.com/events');
|
|
6901
|
-
*
|
|
6902
|
-
* const sub = pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleEvent(event));
|
|
6903
|
-
*
|
|
6904
|
-
* sub.unsubscribe();
|
|
6905
|
-
* pushEventsService.disconnect();
|
|
6906
|
-
* ```
|
|
6907
|
-
*/
|
|
6908
|
-
class QdPushEventsService {
|
|
6909
|
-
authenticationService = inject('QdAuthenticationService', { optional: true });
|
|
6910
|
-
_eventSource;
|
|
6911
|
-
_subjects = new Map();
|
|
6912
|
-
_listeners = [];
|
|
6913
|
-
_accessTokenSub;
|
|
6914
|
-
_options;
|
|
6915
|
-
_heartbeatTimeout;
|
|
6916
|
-
_heartbeatGracePeriod = 100;
|
|
6917
|
-
_initialHeartbeatTimeout = 10000;
|
|
6918
|
-
_isUnauthorized = false;
|
|
6919
|
-
_reconnectAttempts = 0;
|
|
6920
|
-
_maxReconnectAttempts = 5;
|
|
6921
|
-
_backoffTimer;
|
|
6922
|
-
/**
|
|
6923
|
-
* Opens an SSE connection to the given URL.
|
|
6924
|
-
*
|
|
6925
|
-
* With authentication enabled (default), the service subscribes to the `accessToken$` observable
|
|
6926
|
-
* provided by Quadrel Auth and rebuilds the connection whenever the token changes.
|
|
6927
|
-
* No-op if already connected.
|
|
6928
|
-
*
|
|
6929
|
-
* @param url The SSE endpoint URL.
|
|
6930
|
-
* @param options Set `{ disableAuthentication: true }` only for explicitly public endpoints.
|
|
6931
|
-
*
|
|
6932
|
-
* @example
|
|
6933
|
-
* ```ts
|
|
6934
|
-
* // Authenticated (default — requires Quadrel Auth)
|
|
6935
|
-
* pushEventsService.connect('https://api.example.com/events');
|
|
6936
|
-
*
|
|
6937
|
-
* // Without authentication (only for public endpoints)
|
|
6938
|
-
* pushEventsService.connect('https://api.example.com/public-events', { disableAuthentication: true });
|
|
6939
|
-
* ```
|
|
6940
|
-
*/
|
|
6941
|
-
connect(url, options) {
|
|
6942
|
-
if (this.isConnectedOrConnecting())
|
|
6943
|
-
return;
|
|
6944
|
-
this._options = { url, options };
|
|
6945
|
-
if (options?.disableAuthentication) {
|
|
6946
|
-
this.openEventSource(url);
|
|
6947
|
-
}
|
|
6948
|
-
else {
|
|
6949
|
-
this.connectWithAuth(url);
|
|
6950
|
-
}
|
|
6951
|
-
}
|
|
6952
|
-
/**
|
|
6953
|
-
* Closes the EventSource connection, clears all event listeners, and cancels pending backoff timers.
|
|
6954
|
-
* Subscription subjects are preserved so that a subsequent `connect()` re-attaches them.
|
|
6955
|
-
*
|
|
6956
|
-
* @example
|
|
6957
|
-
* ```ts
|
|
6958
|
-
* pushEventsService.disconnect();
|
|
6959
|
-
* // Subjects survive — a new connect() will re-attach existing observe() subscriptions.
|
|
6960
|
-
* ```
|
|
6961
|
-
*/
|
|
6962
|
-
disconnect() {
|
|
6963
|
-
if (!this._eventSource) {
|
|
6964
|
-
this.logWarn('No active connection to disconnect.');
|
|
6965
|
-
return;
|
|
6966
|
-
}
|
|
6967
|
-
if (this._accessTokenSub) {
|
|
6968
|
-
this._accessTokenSub.unsubscribe();
|
|
6969
|
-
this._accessTokenSub = undefined;
|
|
6970
|
-
}
|
|
6971
|
-
if (this._heartbeatTimeout)
|
|
6972
|
-
clearTimeout(this._heartbeatTimeout);
|
|
6973
|
-
if (this._backoffTimer) {
|
|
6974
|
-
clearTimeout(this._backoffTimer);
|
|
6975
|
-
this._backoffTimer = undefined;
|
|
6976
|
-
}
|
|
6977
|
-
this.removeAllListeners();
|
|
6978
|
-
this._eventSource.close();
|
|
6979
|
-
}
|
|
6980
|
-
/**
|
|
6981
|
-
* Returns an Observable that emits whenever the server sends an event of the given type.
|
|
6982
|
-
*
|
|
6983
|
-
* Lazily registers an EventSource listener on first call per event name.
|
|
6984
|
-
* Returns `NEVER` and logs an error if no connection exists.
|
|
6985
|
-
*
|
|
6986
|
-
* @param eventName The SSE event type to listen for.
|
|
6987
|
-
*
|
|
6988
|
-
* @example
|
|
6989
|
-
* ```ts
|
|
6990
|
-
* pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleUpdate(event));
|
|
6991
|
-
* ```
|
|
6992
|
-
*/
|
|
6993
|
-
observe(eventName) {
|
|
6994
|
-
if (!this._eventSource) {
|
|
6995
|
-
this.logWarn('Cannot observe events without a connection. Call connect() first.');
|
|
6996
|
-
return NEVER;
|
|
6997
|
-
}
|
|
6998
|
-
if (!this._subjects.has(eventName)) {
|
|
6999
|
-
this._subjects.set(eventName, new Subject());
|
|
7000
|
-
this.addListener(eventName, (event) => this._subjects.get(eventName).next(event));
|
|
7001
|
-
}
|
|
7002
|
-
return this._subjects.get(eventName).asObservable();
|
|
7003
|
-
}
|
|
7004
|
-
/**
|
|
7005
|
-
* Removes all event listeners and clears all subscription subjects. The connection stays open.
|
|
7006
|
-
* Use this to reset all subscriptions without disconnecting the SSE stream.
|
|
7007
|
-
*
|
|
7008
|
-
* @example
|
|
7009
|
-
* ```ts
|
|
7010
|
-
* pushEventsService.unobserveAll();
|
|
7011
|
-
* // Connection remains open, but no events are forwarded until observe() is called again.
|
|
7012
|
-
* ```
|
|
7013
|
-
*/
|
|
7014
|
-
unobserveAll() {
|
|
7015
|
-
this.removeAllListeners();
|
|
7016
|
-
this._subjects.clear();
|
|
7017
|
-
}
|
|
7018
|
-
/** Returns `true` when the EventSource is in state OPEN or CONNECTING. */
|
|
7019
|
-
isConnectedOrConnecting() {
|
|
7020
|
-
return (this._eventSource &&
|
|
7021
|
-
(this._eventSource.readyState === EventSource.OPEN || this._eventSource.readyState === EventSource.CONNECTING));
|
|
7022
|
-
}
|
|
7023
|
-
connectWithAuth(url) {
|
|
7024
|
-
if (!this.authenticationService) {
|
|
7025
|
-
this.logError("Can't connect to SSE without Quadrel Auth as the connection has to be secured. Please install Quadrel Auth or disable authentication when connecting.");
|
|
7026
|
-
return;
|
|
7027
|
-
}
|
|
7028
|
-
this._accessTokenSub = this.authenticationService.accessToken$.subscribe((token) => {
|
|
7029
|
-
this.openEventSource(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
7030
|
-
});
|
|
7031
|
-
}
|
|
7032
|
-
openEventSource(url, options = {}) {
|
|
7033
|
-
this._isUnauthorized = false;
|
|
7034
|
-
if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED)
|
|
7035
|
-
this._eventSource.close();
|
|
7036
|
-
this._eventSource = new EventSourcePolyfill(url, options);
|
|
7037
|
-
this._eventSource.onerror = (err) => this.handleError(err);
|
|
7038
|
-
this._eventSource.addEventListener('HEARTBEAT', (message) => this.handleHeartbeat(message));
|
|
7039
|
-
if (this._heartbeatTimeout)
|
|
7040
|
-
clearTimeout(this._heartbeatTimeout);
|
|
7041
|
-
this._heartbeatTimeout = setTimeout(() => this.reconnect(), this._initialHeartbeatTimeout);
|
|
7042
|
-
if (this._backoffTimer) {
|
|
7043
|
-
clearTimeout(this._backoffTimer);
|
|
7044
|
-
this._backoffTimer = undefined;
|
|
7045
|
-
}
|
|
7046
|
-
this._listeners = [];
|
|
7047
|
-
this.reattachListeners();
|
|
7048
|
-
}
|
|
7049
|
-
reconnect() {
|
|
7050
|
-
if (this.isConnectedOrConnecting() || this._isUnauthorized)
|
|
7051
|
-
return;
|
|
7052
|
-
this.disconnect();
|
|
7053
|
-
this.connect(this._options.url, this._options.options);
|
|
7054
|
-
}
|
|
7055
|
-
handleError(err) {
|
|
7056
|
-
const status = err?.status || err?.target?.status;
|
|
7057
|
-
if (status === 401) {
|
|
7058
|
-
this._isUnauthorized = true;
|
|
7059
|
-
this.logError('SSE connection unauthorized (401):', err);
|
|
7060
|
-
this._eventSource.close();
|
|
7061
|
-
this.scheduleRetry();
|
|
7062
|
-
return;
|
|
7063
|
-
}
|
|
7064
|
-
if (this._eventSource.readyState === EventSource.CLOSED)
|
|
7065
|
-
this.reconnect();
|
|
7066
|
-
this.logError('SSE connection error:', err);
|
|
7067
|
-
}
|
|
7068
|
-
scheduleRetry() {
|
|
7069
|
-
if (this._reconnectAttempts >= this._maxReconnectAttempts) {
|
|
7070
|
-
this.logError(`SSE reconnect aborted after ${this._maxReconnectAttempts} failed attempts.`);
|
|
7071
|
-
return;
|
|
7072
|
-
}
|
|
7073
|
-
const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), 30000);
|
|
7074
|
-
this._reconnectAttempts++;
|
|
7075
|
-
this._backoffTimer = setTimeout(() => {
|
|
7076
|
-
this._isUnauthorized = false;
|
|
7077
|
-
this.reconnect();
|
|
7078
|
-
}, delay);
|
|
7079
|
-
}
|
|
7080
|
-
handleHeartbeat(message) {
|
|
7081
|
-
if (this._isUnauthorized)
|
|
7082
|
-
return;
|
|
7083
|
-
if (this._heartbeatTimeout)
|
|
7084
|
-
clearTimeout(this._heartbeatTimeout);
|
|
7085
|
-
this._reconnectAttempts = 0;
|
|
7086
|
-
const interval = JSON.parse(message.data).interval;
|
|
7087
|
-
this._heartbeatTimeout = setTimeout(() => this.reconnect(), interval + this._heartbeatGracePeriod);
|
|
7088
|
-
}
|
|
7089
|
-
addListener(eventName, callback) {
|
|
7090
|
-
this._eventSource.addEventListener(eventName, callback);
|
|
7091
|
-
this._listeners.push([eventName, callback]);
|
|
7092
|
-
}
|
|
7093
|
-
reattachListeners() {
|
|
7094
|
-
this._subjects.forEach((subject, eventName) => this.addListener(eventName, (event) => subject.next(event)));
|
|
7095
|
-
}
|
|
7096
|
-
removeAllListeners() {
|
|
7097
|
-
if (!this._eventSource)
|
|
7098
|
-
return;
|
|
7099
|
-
this._listeners.forEach(([eventName, callback]) => this._eventSource.removeEventListener(eventName, callback));
|
|
7100
|
-
this._listeners = [];
|
|
7101
|
-
}
|
|
7102
|
-
logWarn(message) {
|
|
7103
|
-
console.warn(`Quadrel Framework | QdPushEvents - ${message}`);
|
|
7104
|
-
}
|
|
7105
|
-
logError(message, err) {
|
|
7106
|
-
console.error(`Quadrel Framework | QdPushEvents - ${message}`, err);
|
|
7107
|
-
}
|
|
7108
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
7109
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, providedIn: 'root' });
|
|
7110
|
-
}
|
|
7111
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, decorators: [{
|
|
7112
|
-
type: Injectable,
|
|
7113
|
-
args: [{
|
|
7114
|
-
providedIn: 'root'
|
|
7115
|
-
}]
|
|
7116
|
-
}] });
|
|
7117
|
-
|
|
7118
6740
|
/**
|
|
7119
6741
|
* Framework-wide funnel for syncing application state with the URL `?key=value` query string.
|
|
7120
6742
|
*
|
|
@@ -7404,6 +7026,511 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
7404
7026
|
args: [{ providedIn: 'root' }]
|
|
7405
7027
|
}], ctorParameters: () => [] });
|
|
7406
7028
|
|
|
7029
|
+
class QdRwdDisabledDirective {
|
|
7030
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7031
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdRwdDisabledDirective, isStandalone: false, selector: "[qdRwdDisabled]", host: { classAttribute: "qd-rwd-disabled" }, ngImport: i0 });
|
|
7032
|
+
}
|
|
7033
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdRwdDisabledDirective, decorators: [{
|
|
7034
|
+
type: Directive,
|
|
7035
|
+
args: [{
|
|
7036
|
+
selector: '[qdRwdDisabled]',
|
|
7037
|
+
host: { class: 'qd-rwd-disabled' },
|
|
7038
|
+
standalone: false
|
|
7039
|
+
}]
|
|
7040
|
+
}] });
|
|
7041
|
+
|
|
7042
|
+
class QdLocaleService {
|
|
7043
|
+
_serviceNavLanguage$ = new BehaviorSubject(null);
|
|
7044
|
+
locale$ = this._serviceNavLanguage$.pipe(map(serviceNavLanguage => determineLocale(serviceNavLanguage, navigator.languages)));
|
|
7045
|
+
setServiceNavigationLanguage(language) {
|
|
7046
|
+
this._serviceNavLanguage$.next(language);
|
|
7047
|
+
}
|
|
7048
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdLocaleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
7049
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdLocaleService, providedIn: 'root' });
|
|
7050
|
+
}
|
|
7051
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdLocaleService, decorators: [{
|
|
7052
|
+
type: Injectable,
|
|
7053
|
+
args: [{ providedIn: 'root' }]
|
|
7054
|
+
}] });
|
|
7055
|
+
|
|
7056
|
+
class QdNumberInputService {
|
|
7057
|
+
_locale;
|
|
7058
|
+
_decimalSeparator;
|
|
7059
|
+
_groupSeparator;
|
|
7060
|
+
localeService = inject(QdLocaleService, { optional: true });
|
|
7061
|
+
destroyRef = inject(DestroyRef);
|
|
7062
|
+
ambiguityHintKeyDot = 'i18n.qd.input.number.ambiguousHint.dot';
|
|
7063
|
+
ambiguityHintKeyComma = 'i18n.qd.input.number.ambiguousHint.comma';
|
|
7064
|
+
invalidCharactersErrorKeyComma = 'i18n.qd.input.number.invalidCharacters.comma';
|
|
7065
|
+
invalidCharactersErrorKeyDot = 'i18n.qd.input.number.invalidCharacters.dot';
|
|
7066
|
+
get invalidCharactersErrorKey() {
|
|
7067
|
+
return this._decimalSeparator === ',' ? this.invalidCharactersErrorKeyComma : this.invalidCharactersErrorKeyDot;
|
|
7068
|
+
}
|
|
7069
|
+
get decimalSeparator() {
|
|
7070
|
+
return this._decimalSeparator;
|
|
7071
|
+
}
|
|
7072
|
+
get groupSeparator() {
|
|
7073
|
+
return this._groupSeparator;
|
|
7074
|
+
}
|
|
7075
|
+
constructor() {
|
|
7076
|
+
if (this.localeService) {
|
|
7077
|
+
this.localeService.locale$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(locale => {
|
|
7078
|
+
this.detectSeparatorsForLocale(locale);
|
|
7079
|
+
});
|
|
7080
|
+
}
|
|
7081
|
+
else {
|
|
7082
|
+
this.detectSeparators();
|
|
7083
|
+
}
|
|
7084
|
+
}
|
|
7085
|
+
detectSeparators() {
|
|
7086
|
+
const locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language;
|
|
7087
|
+
this.detectSeparatorsForLocale(locale);
|
|
7088
|
+
}
|
|
7089
|
+
isValidNumber(value) {
|
|
7090
|
+
if (!value)
|
|
7091
|
+
return false;
|
|
7092
|
+
const escaped = this._decimalSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
7093
|
+
return new RegExp(`^-?\\d+(${escaped}\\d+)?$`).test(value);
|
|
7094
|
+
}
|
|
7095
|
+
detectSeparatorsForLocale(locale) {
|
|
7096
|
+
this._locale = locale;
|
|
7097
|
+
const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89);
|
|
7098
|
+
this._decimalSeparator = parts.find(p => p.type === 'decimal')?.value ?? '.';
|
|
7099
|
+
this._groupSeparator = parts.find(p => p.type === 'group')?.value ?? ',';
|
|
7100
|
+
}
|
|
7101
|
+
filterValue(value) {
|
|
7102
|
+
let result = '';
|
|
7103
|
+
let hasDecimal = false;
|
|
7104
|
+
for (let i = 0; i < value.length; i++) {
|
|
7105
|
+
const char = value[i];
|
|
7106
|
+
if (char >= '0' && char <= '9') {
|
|
7107
|
+
result += char;
|
|
7108
|
+
}
|
|
7109
|
+
else if (char === this._decimalSeparator && !hasDecimal) {
|
|
7110
|
+
result += char;
|
|
7111
|
+
hasDecimal = true;
|
|
7112
|
+
}
|
|
7113
|
+
else if (char === '-' && i === 0) {
|
|
7114
|
+
result += char;
|
|
7115
|
+
}
|
|
7116
|
+
}
|
|
7117
|
+
return result;
|
|
7118
|
+
}
|
|
7119
|
+
parseValue(value) {
|
|
7120
|
+
if (!value)
|
|
7121
|
+
return value;
|
|
7122
|
+
const normalized = value.split(this._groupSeparator).join('').replace(this._decimalSeparator, '.');
|
|
7123
|
+
const parsed = parseFloat(normalized);
|
|
7124
|
+
return isNaN(parsed) ? value : parsed;
|
|
7125
|
+
}
|
|
7126
|
+
isAmbiguous(value) {
|
|
7127
|
+
if (typeof value !== 'string' || !value)
|
|
7128
|
+
return false;
|
|
7129
|
+
return /^-?[1-9]\d*[.,]\d{3}$/.test(value);
|
|
7130
|
+
}
|
|
7131
|
+
getAmbiguityHintKey(value) {
|
|
7132
|
+
if (typeof value === 'string' && value.includes('.'))
|
|
7133
|
+
return this.ambiguityHintKeyDot;
|
|
7134
|
+
return this.ambiguityHintKeyComma;
|
|
7135
|
+
}
|
|
7136
|
+
formatNumberForViewonly(value) {
|
|
7137
|
+
if (value == null || value === '')
|
|
7138
|
+
return '';
|
|
7139
|
+
const str = String(value);
|
|
7140
|
+
const parsed = typeof value === 'number' ? value : this.parseValue(str);
|
|
7141
|
+
if (typeof parsed !== 'number')
|
|
7142
|
+
return str;
|
|
7143
|
+
return new Intl.NumberFormat(this._locale).format(parsed);
|
|
7144
|
+
}
|
|
7145
|
+
formatValueForDisplay(value) {
|
|
7146
|
+
if (value == null || value === '')
|
|
7147
|
+
return '';
|
|
7148
|
+
const str = String(value);
|
|
7149
|
+
if (this._decimalSeparator === '.')
|
|
7150
|
+
return str;
|
|
7151
|
+
return str.replace('.', this._decimalSeparator);
|
|
7152
|
+
}
|
|
7153
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdNumberInputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
7154
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdNumberInputService });
|
|
7155
|
+
}
|
|
7156
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdNumberInputService, decorators: [{
|
|
7157
|
+
type: Injectable
|
|
7158
|
+
}], ctorParameters: () => [] });
|
|
7159
|
+
|
|
7160
|
+
/**
|
|
7161
|
+
* Manages a server-sent event (SSE) connection with automatic reconnection and heartbeat monitoring.
|
|
7162
|
+
*
|
|
7163
|
+
* All service endpoints — including SSE — must be protected. The connection is therefore secured
|
|
7164
|
+
* via Quadrel Auth (Bearer token) by default. When the access token refreshes, the connection is
|
|
7165
|
+
* transparently rebuilt. Only disable authentication for endpoints that are explicitly public.
|
|
7166
|
+
*
|
|
7167
|
+
* ### Reconnection behavior
|
|
7168
|
+
*
|
|
7169
|
+
* - **Heartbeat timeout**: If no HEARTBEAT event arrives within the expected interval, the service reconnects.
|
|
7170
|
+
* - **401 Unauthorized**: Triggers exponential-backoff reconnection (max 5 attempts, capped at 30 s).
|
|
7171
|
+
* - **Other errors**: Reconnects immediately when the EventSource transitions to CLOSED.
|
|
7172
|
+
*
|
|
7173
|
+
* Existing `observe()` subscriptions are preserved across reconnections.
|
|
7174
|
+
*
|
|
7175
|
+
* ### Usage
|
|
7176
|
+
*
|
|
7177
|
+
* ```ts
|
|
7178
|
+
* pushEventsService.connect('https://api.example.com/events');
|
|
7179
|
+
*
|
|
7180
|
+
* const sub = pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleEvent(event));
|
|
7181
|
+
*
|
|
7182
|
+
* sub.unsubscribe();
|
|
7183
|
+
* pushEventsService.disconnect();
|
|
7184
|
+
* ```
|
|
7185
|
+
*/
|
|
7186
|
+
class QdPushEventsService {
|
|
7187
|
+
authenticationService = inject('QdAuthenticationService', { optional: true });
|
|
7188
|
+
_eventSource;
|
|
7189
|
+
_subjects = new Map();
|
|
7190
|
+
_listeners = [];
|
|
7191
|
+
_accessTokenSub;
|
|
7192
|
+
_options;
|
|
7193
|
+
_heartbeatTimeout;
|
|
7194
|
+
_heartbeatGracePeriod = 100;
|
|
7195
|
+
_initialHeartbeatTimeout = 10000;
|
|
7196
|
+
_isUnauthorized = false;
|
|
7197
|
+
_reconnectAttempts = 0;
|
|
7198
|
+
_maxReconnectAttempts = 5;
|
|
7199
|
+
_backoffTimer;
|
|
7200
|
+
/**
|
|
7201
|
+
* Opens an SSE connection to the given URL.
|
|
7202
|
+
*
|
|
7203
|
+
* With authentication enabled (default), the service subscribes to the `accessToken$` observable
|
|
7204
|
+
* provided by Quadrel Auth and rebuilds the connection whenever the token changes.
|
|
7205
|
+
* No-op if already connected.
|
|
7206
|
+
*
|
|
7207
|
+
* @param url The SSE endpoint URL.
|
|
7208
|
+
* @param options Set `{ disableAuthentication: true }` only for explicitly public endpoints.
|
|
7209
|
+
*
|
|
7210
|
+
* @example
|
|
7211
|
+
* ```ts
|
|
7212
|
+
* // Authenticated (default — requires Quadrel Auth)
|
|
7213
|
+
* pushEventsService.connect('https://api.example.com/events');
|
|
7214
|
+
*
|
|
7215
|
+
* // Without authentication (only for public endpoints)
|
|
7216
|
+
* pushEventsService.connect('https://api.example.com/public-events', { disableAuthentication: true });
|
|
7217
|
+
* ```
|
|
7218
|
+
*/
|
|
7219
|
+
connect(url, options) {
|
|
7220
|
+
if (this.isConnectedOrConnecting())
|
|
7221
|
+
return;
|
|
7222
|
+
this._options = { url, options };
|
|
7223
|
+
if (options?.disableAuthentication) {
|
|
7224
|
+
this.openEventSource(url);
|
|
7225
|
+
}
|
|
7226
|
+
else {
|
|
7227
|
+
this.connectWithAuth(url);
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7230
|
+
/**
|
|
7231
|
+
* Closes the EventSource connection, clears all event listeners, and cancels pending backoff timers.
|
|
7232
|
+
* Subscription subjects are preserved so that a subsequent `connect()` re-attaches them.
|
|
7233
|
+
*
|
|
7234
|
+
* @example
|
|
7235
|
+
* ```ts
|
|
7236
|
+
* pushEventsService.disconnect();
|
|
7237
|
+
* // Subjects survive — a new connect() will re-attach existing observe() subscriptions.
|
|
7238
|
+
* ```
|
|
7239
|
+
*/
|
|
7240
|
+
disconnect() {
|
|
7241
|
+
if (!this._eventSource) {
|
|
7242
|
+
this.logWarn('No active connection to disconnect.');
|
|
7243
|
+
return;
|
|
7244
|
+
}
|
|
7245
|
+
if (this._accessTokenSub) {
|
|
7246
|
+
this._accessTokenSub.unsubscribe();
|
|
7247
|
+
this._accessTokenSub = undefined;
|
|
7248
|
+
}
|
|
7249
|
+
if (this._heartbeatTimeout)
|
|
7250
|
+
clearTimeout(this._heartbeatTimeout);
|
|
7251
|
+
if (this._backoffTimer) {
|
|
7252
|
+
clearTimeout(this._backoffTimer);
|
|
7253
|
+
this._backoffTimer = undefined;
|
|
7254
|
+
}
|
|
7255
|
+
this.removeAllListeners();
|
|
7256
|
+
this._eventSource.close();
|
|
7257
|
+
}
|
|
7258
|
+
/**
|
|
7259
|
+
* Returns an Observable that emits whenever the server sends an event of the given type.
|
|
7260
|
+
*
|
|
7261
|
+
* Lazily registers an EventSource listener on first call per event name.
|
|
7262
|
+
* Returns `NEVER` and logs an error if no connection exists.
|
|
7263
|
+
*
|
|
7264
|
+
* @param eventName The SSE event type to listen for.
|
|
7265
|
+
*
|
|
7266
|
+
* @example
|
|
7267
|
+
* ```ts
|
|
7268
|
+
* pushEventsService.observe('RESOURCE_UPDATED').subscribe(event => handleUpdate(event));
|
|
7269
|
+
* ```
|
|
7270
|
+
*/
|
|
7271
|
+
observe(eventName) {
|
|
7272
|
+
if (!this._eventSource) {
|
|
7273
|
+
this.logWarn('Cannot observe events without a connection. Call connect() first.');
|
|
7274
|
+
return NEVER;
|
|
7275
|
+
}
|
|
7276
|
+
if (!this._subjects.has(eventName)) {
|
|
7277
|
+
this._subjects.set(eventName, new Subject());
|
|
7278
|
+
this.addListener(eventName, (event) => this._subjects.get(eventName).next(event));
|
|
7279
|
+
}
|
|
7280
|
+
return this._subjects.get(eventName).asObservable();
|
|
7281
|
+
}
|
|
7282
|
+
/**
|
|
7283
|
+
* Removes all event listeners and clears all subscription subjects. The connection stays open.
|
|
7284
|
+
* Use this to reset all subscriptions without disconnecting the SSE stream.
|
|
7285
|
+
*
|
|
7286
|
+
* @example
|
|
7287
|
+
* ```ts
|
|
7288
|
+
* pushEventsService.unobserveAll();
|
|
7289
|
+
* // Connection remains open, but no events are forwarded until observe() is called again.
|
|
7290
|
+
* ```
|
|
7291
|
+
*/
|
|
7292
|
+
unobserveAll() {
|
|
7293
|
+
this.removeAllListeners();
|
|
7294
|
+
this._subjects.clear();
|
|
7295
|
+
}
|
|
7296
|
+
/** Returns `true` when the EventSource is in state OPEN or CONNECTING. */
|
|
7297
|
+
isConnectedOrConnecting() {
|
|
7298
|
+
return (this._eventSource &&
|
|
7299
|
+
(this._eventSource.readyState === EventSource.OPEN || this._eventSource.readyState === EventSource.CONNECTING));
|
|
7300
|
+
}
|
|
7301
|
+
connectWithAuth(url) {
|
|
7302
|
+
if (!this.authenticationService) {
|
|
7303
|
+
this.logError("Can't connect to SSE without Quadrel Auth as the connection has to be secured. Please install Quadrel Auth or disable authentication when connecting.");
|
|
7304
|
+
return;
|
|
7305
|
+
}
|
|
7306
|
+
this._accessTokenSub = this.authenticationService.accessToken$.subscribe((token) => {
|
|
7307
|
+
this.openEventSource(url, { headers: { Authorization: `Bearer ${token}` } });
|
|
7308
|
+
});
|
|
7309
|
+
}
|
|
7310
|
+
openEventSource(url, options = {}) {
|
|
7311
|
+
this._isUnauthorized = false;
|
|
7312
|
+
if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED)
|
|
7313
|
+
this._eventSource.close();
|
|
7314
|
+
this._eventSource = new EventSourcePolyfill(url, options);
|
|
7315
|
+
this._eventSource.onerror = (err) => this.handleError(err);
|
|
7316
|
+
this._eventSource.addEventListener('HEARTBEAT', (message) => this.handleHeartbeat(message));
|
|
7317
|
+
if (this._heartbeatTimeout)
|
|
7318
|
+
clearTimeout(this._heartbeatTimeout);
|
|
7319
|
+
this._heartbeatTimeout = setTimeout(() => this.reconnect(), this._initialHeartbeatTimeout);
|
|
7320
|
+
if (this._backoffTimer) {
|
|
7321
|
+
clearTimeout(this._backoffTimer);
|
|
7322
|
+
this._backoffTimer = undefined;
|
|
7323
|
+
}
|
|
7324
|
+
this._listeners = [];
|
|
7325
|
+
this.reattachListeners();
|
|
7326
|
+
}
|
|
7327
|
+
reconnect() {
|
|
7328
|
+
if (this.isConnectedOrConnecting() || this._isUnauthorized)
|
|
7329
|
+
return;
|
|
7330
|
+
this.disconnect();
|
|
7331
|
+
this.connect(this._options.url, this._options.options);
|
|
7332
|
+
}
|
|
7333
|
+
handleError(err) {
|
|
7334
|
+
const status = err?.status || err?.target?.status;
|
|
7335
|
+
if (status === 401) {
|
|
7336
|
+
this._isUnauthorized = true;
|
|
7337
|
+
this.logError('SSE connection unauthorized (401):', err);
|
|
7338
|
+
this._eventSource.close();
|
|
7339
|
+
this.scheduleRetry();
|
|
7340
|
+
return;
|
|
7341
|
+
}
|
|
7342
|
+
if (this._eventSource.readyState === EventSource.CLOSED)
|
|
7343
|
+
this.reconnect();
|
|
7344
|
+
this.logError('SSE connection error:', err);
|
|
7345
|
+
}
|
|
7346
|
+
scheduleRetry() {
|
|
7347
|
+
if (this._reconnectAttempts >= this._maxReconnectAttempts) {
|
|
7348
|
+
this.logError(`SSE reconnect aborted after ${this._maxReconnectAttempts} failed attempts.`);
|
|
7349
|
+
return;
|
|
7350
|
+
}
|
|
7351
|
+
const delay = Math.min(1000 * Math.pow(2, this._reconnectAttempts), 30000);
|
|
7352
|
+
this._reconnectAttempts++;
|
|
7353
|
+
this._backoffTimer = setTimeout(() => {
|
|
7354
|
+
this._isUnauthorized = false;
|
|
7355
|
+
this.reconnect();
|
|
7356
|
+
}, delay);
|
|
7357
|
+
}
|
|
7358
|
+
handleHeartbeat(message) {
|
|
7359
|
+
if (this._isUnauthorized)
|
|
7360
|
+
return;
|
|
7361
|
+
if (this._heartbeatTimeout)
|
|
7362
|
+
clearTimeout(this._heartbeatTimeout);
|
|
7363
|
+
this._reconnectAttempts = 0;
|
|
7364
|
+
const interval = JSON.parse(message.data).interval;
|
|
7365
|
+
this._heartbeatTimeout = setTimeout(() => this.reconnect(), interval + this._heartbeatGracePeriod);
|
|
7366
|
+
}
|
|
7367
|
+
addListener(eventName, callback) {
|
|
7368
|
+
this._eventSource.addEventListener(eventName, callback);
|
|
7369
|
+
this._listeners.push([eventName, callback]);
|
|
7370
|
+
}
|
|
7371
|
+
reattachListeners() {
|
|
7372
|
+
this._subjects.forEach((subject, eventName) => this.addListener(eventName, (event) => subject.next(event)));
|
|
7373
|
+
}
|
|
7374
|
+
removeAllListeners() {
|
|
7375
|
+
if (!this._eventSource)
|
|
7376
|
+
return;
|
|
7377
|
+
this._listeners.forEach(([eventName, callback]) => this._eventSource.removeEventListener(eventName, callback));
|
|
7378
|
+
this._listeners = [];
|
|
7379
|
+
}
|
|
7380
|
+
logWarn(message) {
|
|
7381
|
+
console.warn(`Quadrel Framework | QdPushEvents - ${message}`);
|
|
7382
|
+
}
|
|
7383
|
+
logError(message, err) {
|
|
7384
|
+
console.error(`Quadrel Framework | QdPushEvents - ${message}`, err);
|
|
7385
|
+
}
|
|
7386
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
7387
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, providedIn: 'root' });
|
|
7388
|
+
}
|
|
7389
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdPushEventsService, decorators: [{
|
|
7390
|
+
type: Injectable,
|
|
7391
|
+
args: [{
|
|
7392
|
+
providedIn: 'root'
|
|
7393
|
+
}]
|
|
7394
|
+
}] });
|
|
7395
|
+
|
|
7396
|
+
var breakpoints$1 = {
|
|
7397
|
+
xs: 320,
|
|
7398
|
+
sm: 600,
|
|
7399
|
+
md: 960,
|
|
7400
|
+
lg: 1280,
|
|
7401
|
+
xl: 1600,
|
|
7402
|
+
xxl: 1800
|
|
7403
|
+
};
|
|
7404
|
+
var panel = {
|
|
7405
|
+
sm: 432,
|
|
7406
|
+
md: 588,
|
|
7407
|
+
lg: 720
|
|
7408
|
+
};
|
|
7409
|
+
var base = {
|
|
7410
|
+
fontsize: 16
|
|
7411
|
+
};
|
|
7412
|
+
var globalVars = {
|
|
7413
|
+
breakpoints: breakpoints$1,
|
|
7414
|
+
panel: panel,
|
|
7415
|
+
base: base
|
|
7416
|
+
};
|
|
7417
|
+
|
|
7418
|
+
const convertPxToRem = (pixel) => `${parseFloat((pixel / globalVars.base.fontsize).toFixed(3))}rem`;
|
|
7419
|
+
|
|
7420
|
+
class QdTooltipComponent {
|
|
7421
|
+
content;
|
|
7422
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7423
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipComponent, isStandalone: false, selector: "qd-tooltip", inputs: { content: "content" }, ngImport: i0, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
|
|
7424
|
+
}
|
|
7425
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipComponent, decorators: [{
|
|
7426
|
+
type: Component,
|
|
7427
|
+
args: [{ selector: 'qd-tooltip', standalone: false, template: "<ng-container *ngIf=\"content?.headline\">\n <strong>{{ content.headline }}</strong>\n</ng-container>\n\n<ng-container *ngFor=\"let paragraph of content.paragraphs\">\n <p>{{ paragraph }}</p>\n</ng-container>\n", styles: [":host{box-shadow:0 0 .625rem #979797;display:block;width:100%;max-width:16rem;padding:.5rem;border-radius:.5rem;background-color:#000;color:#fff;font-size:.75rem;line-height:1rem}:host strong,:host p{display:block}:host p{margin:0 0 .5rem}:host p:last-child{margin-bottom:0}\n"] }]
|
|
7428
|
+
}], propDecorators: { content: [{
|
|
7429
|
+
type: Input
|
|
7430
|
+
}] } });
|
|
7431
|
+
|
|
7432
|
+
const TARGET_SELECTOR = '.qd-intersection-target';
|
|
7433
|
+
const SHOW_EVENTS = ['mouseenter', 'mousemove'];
|
|
7434
|
+
const HIDE_EVENTS = ['mouseleave', 'click'];
|
|
7435
|
+
const HIDE_DELAY = 300;
|
|
7436
|
+
const OVERLAY_WIDTH = 280;
|
|
7437
|
+
const UNSUBSCRIBE_IMMEDIATELY = true;
|
|
7438
|
+
const THRESHOLD = 1;
|
|
7439
|
+
/**
|
|
7440
|
+
* QdTooltipAtIntersectionDirective provides a tooltip. This will be triggered if the content is intersected.
|
|
7441
|
+
*
|
|
7442
|
+
* * Selector: [qdTooltipAtIntersection]
|
|
7443
|
+
* * Target Selector: .qd-intersection-target
|
|
7444
|
+
*
|
|
7445
|
+
* The IntersectionObserver API is used for the implementation.
|
|
7446
|
+
* * @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
|
|
7447
|
+
*
|
|
7448
|
+
* * Note: The intersection of the target is calculated by the IntersectionObserver only once, initially (can be extended later if required). After that it will be unsubscribed immediately.
|
|
7449
|
+
* */
|
|
7450
|
+
class QdTooltipAtIntersectionDirective {
|
|
7451
|
+
_host = inject(ElementRef);
|
|
7452
|
+
_positionBuilder = inject(OverlayPositionBuilder);
|
|
7453
|
+
_overlay = inject(Overlay);
|
|
7454
|
+
_overlayRef;
|
|
7455
|
+
_target;
|
|
7456
|
+
_observer$;
|
|
7457
|
+
_isIntersected = false;
|
|
7458
|
+
_destroyed$ = new Subject();
|
|
7459
|
+
ngAfterViewInit() {
|
|
7460
|
+
this.setTarget();
|
|
7461
|
+
this.observeTarget();
|
|
7462
|
+
this.createOverlay();
|
|
7463
|
+
this.subscribeShow();
|
|
7464
|
+
this.subscribeHide();
|
|
7465
|
+
}
|
|
7466
|
+
ngOnDestroy() {
|
|
7467
|
+
this._observer$.unobserve(this._target);
|
|
7468
|
+
this._destroyed$.next();
|
|
7469
|
+
this._destroyed$.complete();
|
|
7470
|
+
}
|
|
7471
|
+
setTarget() {
|
|
7472
|
+
this._target = this._host.nativeElement.querySelector(TARGET_SELECTOR);
|
|
7473
|
+
}
|
|
7474
|
+
observeTarget() {
|
|
7475
|
+
const options = {
|
|
7476
|
+
root: this._host.nativeElement,
|
|
7477
|
+
threshold: THRESHOLD
|
|
7478
|
+
};
|
|
7479
|
+
this._observer$ = new IntersectionObserver(entries => {
|
|
7480
|
+
this._isIntersected = entries[0].intersectionRatio < 1;
|
|
7481
|
+
if (this._isIntersected) {
|
|
7482
|
+
this._setStyles();
|
|
7483
|
+
if (UNSUBSCRIBE_IMMEDIATELY)
|
|
7484
|
+
this._observer$.unobserve(this._target);
|
|
7485
|
+
}
|
|
7486
|
+
}, options);
|
|
7487
|
+
this._observer$.observe(this._target);
|
|
7488
|
+
}
|
|
7489
|
+
_setStyles() {
|
|
7490
|
+
this._target.style.overflow = 'hidden';
|
|
7491
|
+
this._target.style.textOverflow = 'ellipsis';
|
|
7492
|
+
this._target.style.cursor = 'help';
|
|
7493
|
+
}
|
|
7494
|
+
createOverlay() {
|
|
7495
|
+
this._overlayRef = this._overlay.create({
|
|
7496
|
+
positionStrategy: this._positionBuilder
|
|
7497
|
+
.flexibleConnectedTo(this._host)
|
|
7498
|
+
.withPositions([{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' }]),
|
|
7499
|
+
width: convertPxToRem(OVERLAY_WIDTH)
|
|
7500
|
+
});
|
|
7501
|
+
}
|
|
7502
|
+
subscribeShow() {
|
|
7503
|
+
merge(...SHOW_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
|
|
7504
|
+
.pipe(takeUntil(this._destroyed$), filter(() => !this._overlayRef.hasAttached() && this._isIntersected))
|
|
7505
|
+
.subscribe(() => {
|
|
7506
|
+
const content = this.getContent();
|
|
7507
|
+
const tooltipPortal = new ComponentPortal(QdTooltipComponent);
|
|
7508
|
+
const tooltipRef = this._overlayRef.attach(tooltipPortal);
|
|
7509
|
+
tooltipRef.instance.content = content;
|
|
7510
|
+
});
|
|
7511
|
+
}
|
|
7512
|
+
subscribeHide() {
|
|
7513
|
+
merge(...HIDE_EVENTS.map(event => fromEvent(this._host.nativeElement, event)))
|
|
7514
|
+
.pipe(takeUntil(this._destroyed$), filter(() => this._overlayRef.hasAttached()), debounceTime(HIDE_DELAY))
|
|
7515
|
+
.subscribe(() => this._overlayRef.detach());
|
|
7516
|
+
}
|
|
7517
|
+
getContent() {
|
|
7518
|
+
return {
|
|
7519
|
+
headline: this._target.getAttribute('data-tooltip-headline') || undefined,
|
|
7520
|
+
paragraphs: [this._target.textContent?.trim() || '']
|
|
7521
|
+
};
|
|
7522
|
+
}
|
|
7523
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7524
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdTooltipAtIntersectionDirective, isStandalone: false, selector: "[qdTooltipAtIntersection]", ngImport: i0 });
|
|
7525
|
+
}
|
|
7526
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdTooltipAtIntersectionDirective, decorators: [{
|
|
7527
|
+
type: Directive,
|
|
7528
|
+
args: [{
|
|
7529
|
+
selector: '[qdTooltipAtIntersection]',
|
|
7530
|
+
standalone: false
|
|
7531
|
+
}]
|
|
7532
|
+
}] });
|
|
7533
|
+
|
|
7407
7534
|
const MAX_TOOLTIP_CHARACTER = 512;
|
|
7408
7535
|
const TOOLTIP_POSITIONS = [
|
|
7409
7536
|
{ originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom' },
|
|
@@ -7509,9 +7636,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
7509
7636
|
type: Input
|
|
7510
7637
|
}] } });
|
|
7511
7638
|
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7639
|
+
class QdVisuallyHiddenDirective {
|
|
7640
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
7641
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: QdVisuallyHiddenDirective, isStandalone: false, selector: "[qdVisuallyHidden]", host: { classAttribute: "qd-visually-hidden" }, ngImport: i0 });
|
|
7642
|
+
}
|
|
7643
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdVisuallyHiddenDirective, decorators: [{
|
|
7644
|
+
type: Directive,
|
|
7645
|
+
args: [{
|
|
7646
|
+
selector: '[qdVisuallyHidden]',
|
|
7647
|
+
host: { class: 'qd-visually-hidden' },
|
|
7648
|
+
standalone: false
|
|
7649
|
+
}]
|
|
7650
|
+
}] });
|
|
7515
7651
|
|
|
7516
7652
|
class QdCoreModule {
|
|
7517
7653
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -8589,11 +8725,11 @@ class QdFormHintComponent {
|
|
|
8589
8725
|
this.actionEmitterService.hintEventEmitterSubject.next(null);
|
|
8590
8726
|
}
|
|
8591
8727
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdFormHintComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8592
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdFormHintComponent, isStandalone: false, selector: "qd-form-hint", inputs: { hint: "hint", control: "control", hasError: "hasError", hintAction: "hintAction", testId: ["data-test-id", "testId"] }, host: { classAttribute: "qd-form-hint" }, ngImport: i0, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: QdFormErrorComponent, selector: "qd-form-error", inputs: ["control"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
|
|
8728
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdFormHintComponent, isStandalone: false, selector: "qd-form-hint", inputs: { hint: "hint", control: "control", hasError: "hasError", hintAction: "hintAction", testId: ["data-test-id", "testId"] }, host: { classAttribute: "qd-form-hint" }, ngImport: i0, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}.qd-input-ambiguous :host{color:#069}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: QdFormErrorComponent, selector: "qd-form-error", inputs: ["control"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
|
|
8593
8729
|
}
|
|
8594
8730
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdFormHintComponent, decorators: [{
|
|
8595
8731
|
type: Component,
|
|
8596
|
-
args: [{ selector: 'qd-form-hint', host: { class: 'qd-form-hint' }, standalone: false, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"] }]
|
|
8732
|
+
args: [{ selector: 'qd-form-hint', host: { class: 'qd-form-hint' }, standalone: false, template: "<div class=\"qd-form-hint\" [attr.data-test-id]=\"testId + '-hint'\">\n <ng-container *ngIf=\"!hasError && !hintAction\">\n {{ hint | translate }}\n </ng-container>\n <ng-container *ngIf=\"!hasError && hintAction\">\n <div class=\"qd-form-hint--hint-action\" (click)=\"handleClick()\">\n {{ hint | translate }}\n </div>\n </ng-container>\n</div>\n\n<div class=\"qd-form-hint--error\" [attr.data-test-id]=\"testId + '-error'\">\n <ng-container *ngIf=\"hasError\">\n <qd-form-error [control]=\"control\"></qd-form-error>\n </ng-container>\n</div>\n", styles: [":host{display:block;min-height:.75rem;color:#757575;font-size:.75rem;font-weight:300;line-height:.75rem}:host .qd-form-hint--error{color:#c70023}.qd-form-disabled :host{color:#979797}.qd-input-ambiguous :host{color:#069}:host .qd-form-hint--hint-action{color:#069;cursor:pointer}:host .qd-form-hint--hint-action:hover,:host .qd-form-hint--hint-action:active,:host .qd-form-hint--hint-action:focus{text-decoration:underline}\n"] }]
|
|
8597
8733
|
}], propDecorators: { hint: [{
|
|
8598
8734
|
type: Input
|
|
8599
8735
|
}], control: [{
|
|
@@ -11218,6 +11354,7 @@ class QdInputComponent {
|
|
|
11218
11354
|
resolverRegistry = inject(QdFormOptionsResolverRegistry);
|
|
11219
11355
|
controlContainer = inject(ControlContainer, { optional: true, host: true, skipSelf: true });
|
|
11220
11356
|
eventBrokerService = inject(QdEventBrokerService, { optional: true });
|
|
11357
|
+
numberInputService = inject(QdNumberInputService);
|
|
11221
11358
|
/**
|
|
11222
11359
|
* The form control name can be assigned here if you want to use Reactive Forms.
|
|
11223
11360
|
*/
|
|
@@ -11292,9 +11429,13 @@ class QdInputComponent {
|
|
|
11292
11429
|
get isErrorFromOutside() {
|
|
11293
11430
|
return this.isError;
|
|
11294
11431
|
}
|
|
11432
|
+
get isAmbiguousState() {
|
|
11433
|
+
return this.isAmbiguousInput;
|
|
11434
|
+
}
|
|
11295
11435
|
inputElement;
|
|
11296
11436
|
inputType;
|
|
11297
11437
|
inputMode;
|
|
11438
|
+
htmlInputType;
|
|
11298
11439
|
placeholder;
|
|
11299
11440
|
label;
|
|
11300
11441
|
hint;
|
|
@@ -11306,6 +11447,7 @@ class QdInputComponent {
|
|
|
11306
11447
|
control;
|
|
11307
11448
|
_optionsResolver;
|
|
11308
11449
|
_subs = new Subscription();
|
|
11450
|
+
_isUserTyped = false;
|
|
11309
11451
|
_onChange = () => { };
|
|
11310
11452
|
_onTouch = () => { };
|
|
11311
11453
|
get hasOnlyUnitsError() {
|
|
@@ -11314,6 +11456,15 @@ class QdInputComponent {
|
|
|
11314
11456
|
get hasUnits() {
|
|
11315
11457
|
return this.config?.units?.length > 0;
|
|
11316
11458
|
}
|
|
11459
|
+
get ambiguityHintKey() {
|
|
11460
|
+
return this.numberInputService.getAmbiguityHintKey(this._value.value);
|
|
11461
|
+
}
|
|
11462
|
+
get isAmbiguousInput() {
|
|
11463
|
+
return (this.inputType === 'number' &&
|
|
11464
|
+
!this.hasError &&
|
|
11465
|
+
this._isUserTyped &&
|
|
11466
|
+
this.numberInputService.isAmbiguous(this._value.value));
|
|
11467
|
+
}
|
|
11317
11468
|
get numberOfCharacters() {
|
|
11318
11469
|
if (!this._value.value)
|
|
11319
11470
|
return 0;
|
|
@@ -11330,7 +11481,10 @@ class QdInputComponent {
|
|
|
11330
11481
|
return this.control.getMaxLengthOrUndefined();
|
|
11331
11482
|
}
|
|
11332
11483
|
get valueAsList() {
|
|
11333
|
-
|
|
11484
|
+
const displayValue = this.inputType === 'number'
|
|
11485
|
+
? this.numberInputService.formatNumberForViewonly(this._value.value)
|
|
11486
|
+
: this._value.value;
|
|
11487
|
+
return [`${displayValue}${this._value.unit ? ' ' + this._value.unit : ''}`];
|
|
11334
11488
|
}
|
|
11335
11489
|
ngOnInit() {
|
|
11336
11490
|
this.initializeOptionsResolver();
|
|
@@ -11343,6 +11497,11 @@ class QdInputComponent {
|
|
|
11343
11497
|
console.warn('Quadrel Framework | QdInput - Please use the QdFormControl instead of the Angular FormControl.');
|
|
11344
11498
|
}
|
|
11345
11499
|
}
|
|
11500
|
+
if (this.config.inputType === 'number' &&
|
|
11501
|
+
this.config.inputMode !== 'numeric' &&
|
|
11502
|
+
this.config.inputMode !== 'decimal' &&
|
|
11503
|
+
this.config.inputMode != null)
|
|
11504
|
+
console.error('QD-UI | QdInputComponent - Please use either decimal or numeric when using QdInputType number');
|
|
11346
11505
|
this.writeValue(this.value ?? getValue(this.config));
|
|
11347
11506
|
this.normalizeInitialControlValueIfNeeded();
|
|
11348
11507
|
this._subs.add(this.actionEmitterService.hintEventEmitter$.subscribe(() => this.clickHint.emit()));
|
|
@@ -11373,6 +11532,8 @@ class QdInputComponent {
|
|
|
11373
11532
|
writeValue(value) {
|
|
11374
11533
|
this._value = getValueWithUnit(value, this.config);
|
|
11375
11534
|
this._displayValue = String(this._value.value ?? '');
|
|
11535
|
+
this._isUserTyped = false;
|
|
11536
|
+
this.applyDisplayFormat();
|
|
11376
11537
|
}
|
|
11377
11538
|
setDisabledState(disabled) {
|
|
11378
11539
|
this.disabled = disabled;
|
|
@@ -11384,6 +11545,36 @@ class QdInputComponent {
|
|
|
11384
11545
|
if (input?.validity?.badInput)
|
|
11385
11546
|
return;
|
|
11386
11547
|
const value = event.target.value;
|
|
11548
|
+
if (this.inputType === 'number' && value && !this.numberInputService.isValidNumber(value)) {
|
|
11549
|
+
this.control?.setErrors({
|
|
11550
|
+
...this.control.errors,
|
|
11551
|
+
invalidCharacters: this.numberInputService.invalidCharactersErrorKey
|
|
11552
|
+
});
|
|
11553
|
+
return;
|
|
11554
|
+
}
|
|
11555
|
+
if (this.inputType === 'number' && value) {
|
|
11556
|
+
const valueWithoutGroups = value.split(this.numberInputService.groupSeparator).join('');
|
|
11557
|
+
const filtered = this.numberInputService.filterValue(valueWithoutGroups);
|
|
11558
|
+
const hasInvalidChars = filtered !== valueWithoutGroups;
|
|
11559
|
+
if (hasInvalidChars) {
|
|
11560
|
+
this._value = { ...this._value, value: filtered };
|
|
11561
|
+
if (this.control) {
|
|
11562
|
+
this.control.setErrors({
|
|
11563
|
+
...this.control.errors,
|
|
11564
|
+
invalidCharacters: this.numberInputService.invalidCharactersErrorKey
|
|
11565
|
+
});
|
|
11566
|
+
}
|
|
11567
|
+
this._isUserTyped = true;
|
|
11568
|
+
this._onTouch();
|
|
11569
|
+
this.emitValue();
|
|
11570
|
+
return;
|
|
11571
|
+
}
|
|
11572
|
+
if (this.control?.errors?.['invalidCharacters']) {
|
|
11573
|
+
const remainingErrors = Object.fromEntries(Object.entries(this.control.errors).filter(([key]) => key !== 'invalidCharacters'));
|
|
11574
|
+
this.control.setErrors(Object.keys(remainingErrors).length ? remainingErrors : null);
|
|
11575
|
+
}
|
|
11576
|
+
}
|
|
11577
|
+
this._isUserTyped = true;
|
|
11387
11578
|
this._value = { ...this._value, value };
|
|
11388
11579
|
this.emitValue();
|
|
11389
11580
|
this._onTouch();
|
|
@@ -11440,6 +11631,15 @@ class QdInputComponent {
|
|
|
11440
11631
|
updateConfig() {
|
|
11441
11632
|
this.inputType = getInputType(this.config);
|
|
11442
11633
|
this.inputMode = getInputMode(this.config);
|
|
11634
|
+
if (this.inputType === 'number') {
|
|
11635
|
+
this.htmlInputType = 'text';
|
|
11636
|
+
if (!this.inputMode) {
|
|
11637
|
+
this.inputMode = this.inputMode ?? 'decimal';
|
|
11638
|
+
}
|
|
11639
|
+
}
|
|
11640
|
+
else {
|
|
11641
|
+
this.htmlInputType = this.inputType;
|
|
11642
|
+
}
|
|
11443
11643
|
this.placeholder = getPlaceholder(this.config);
|
|
11444
11644
|
this.label = getLabel(this.config);
|
|
11445
11645
|
this.hint = getHint(this.config);
|
|
@@ -11458,13 +11658,15 @@ class QdInputComponent {
|
|
|
11458
11658
|
this._optionsResolver = this.resolverRegistry.findResolver();
|
|
11459
11659
|
}
|
|
11460
11660
|
emitValue() {
|
|
11661
|
+
const emittable = this.inputType === 'number' ? this.numberInputService.parseValue(this._value.value) : this._value.value;
|
|
11461
11662
|
if (this.hasUnits) {
|
|
11462
|
-
this.
|
|
11463
|
-
this.
|
|
11663
|
+
const emittableWithUnit = { ...this._value, value: emittable };
|
|
11664
|
+
this.valueChange.emit(emittableWithUnit);
|
|
11665
|
+
this._onChange(emittableWithUnit);
|
|
11464
11666
|
}
|
|
11465
11667
|
else {
|
|
11466
|
-
this.valueChange.emit(
|
|
11467
|
-
this._onChange(
|
|
11668
|
+
this.valueChange.emit(emittable);
|
|
11669
|
+
this._onChange(emittable);
|
|
11468
11670
|
}
|
|
11469
11671
|
}
|
|
11470
11672
|
initOpModeSubscription() {
|
|
@@ -11487,9 +11689,16 @@ class QdInputComponent {
|
|
|
11487
11689
|
if (!isEqual(modelValue, target))
|
|
11488
11690
|
this.control.setValue(target, { emitEvent: false });
|
|
11489
11691
|
this._value = normalized;
|
|
11692
|
+
this.applyDisplayFormat();
|
|
11693
|
+
}
|
|
11694
|
+
applyDisplayFormat() {
|
|
11695
|
+
if (this.inputType === 'number') {
|
|
11696
|
+
this._value = { ...this._value, value: this.numberInputService.formatValueForDisplay(this._value.value) };
|
|
11697
|
+
this._displayValue = String(this._value.value ?? '');
|
|
11698
|
+
}
|
|
11490
11699
|
}
|
|
11491
11700
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11492
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdInputComponent, isStandalone: false, selector: "qd-input", inputs: { formControlName: "formControlName", value: "value", config: "config", isError: "isError", testId: ["data-test-id", "testId"] }, outputs: { valueChange: "valueChange", enterClick: "enterClick", clickClear: "clickClear", clickHint: "clickHint", clickReadonly: "clickReadonly", clickViewonly: "clickViewonly" }, host: { properties: { "class.qd-input-readonly": "this.readonly", "class.qd-input--readonly-action": "this.readonlyAction", "class.qd-input-viewonly": "this.viewonly", "class.qd-input--viewonly-action": "this.viewonlyAction", "class.qd-form-hint-action": "this.hintAction", "class.qd-input-hint-action": "this.hintAction", "class.qd-form-disabled": "this.disabled", "class.qd-input-disabled": "this.disabled", "class.qd-input-focus": "this.isInputFocused", "class.qd-form-error": "this.hasError", "class.qd-input-error": "this.hasError", "class.qd-input-error-from-outside": "this.isErrorFromOutside" } }, providers: [
|
|
11701
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: QdInputComponent, isStandalone: false, selector: "qd-input", inputs: { formControlName: "formControlName", value: "value", config: "config", isError: "isError", testId: ["data-test-id", "testId"] }, outputs: { valueChange: "valueChange", enterClick: "enterClick", clickClear: "clickClear", clickHint: "clickHint", clickReadonly: "clickReadonly", clickViewonly: "clickViewonly" }, host: { properties: { "class.qd-input-readonly": "this.readonly", "class.qd-input--readonly-action": "this.readonlyAction", "class.qd-input-viewonly": "this.viewonly", "class.qd-input--viewonly-action": "this.viewonlyAction", "class.qd-form-hint-action": "this.hintAction", "class.qd-input-hint-action": "this.hintAction", "class.qd-form-disabled": "this.disabled", "class.qd-input-disabled": "this.disabled", "class.qd-input-focus": "this.isInputFocused", "class.qd-form-error": "this.hasError", "class.qd-input-error": "this.hasError", "class.qd-input-error-from-outside": "this.isErrorFromOutside", "class.qd-input-ambiguous": "this.isAmbiguousState" } }, providers: [
|
|
11493
11702
|
{
|
|
11494
11703
|
provide: NG_VALUE_ACCESSOR,
|
|
11495
11704
|
useExisting: QdInputComponent,
|
|
@@ -11497,13 +11706,14 @@ class QdInputComponent {
|
|
|
11497
11706
|
},
|
|
11498
11707
|
QdFormsActionEmitterService,
|
|
11499
11708
|
QdFormOptionsResolverRegistry,
|
|
11709
|
+
QdNumberInputService,
|
|
11500
11710
|
// TODO: Remove when removing derived directive
|
|
11501
11711
|
QdPopoverSizingService,
|
|
11502
11712
|
{
|
|
11503
11713
|
provide: QD_FOCUSABLE_TOKEN,
|
|
11504
11714
|
useExisting: QdInputComponent
|
|
11505
11715
|
}
|
|
11506
|
-
], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"
|
|
11716
|
+
], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["input"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"htmlInputType\"\n [attr.inputmode]=\"inputMode\"\n [qdAutofocus]=\"hasAutofocus\"\n [attr.data-test-id]=\"testId + '-input'\"\n [step]=\"config?.step\"\n required\n />\n <div class=\"qd-input-suffix\">\n <qd-icon *ngIf=\"hasError && !hasOnlyUnitsError\" class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n <qd-icon *ngIf=\"isAmbiguousInput\" class=\"qd-input-ambiguous-icon\" icon=\"circleInfoSolid\"></qd-icon>\n <qd-icon *ngIf=\"clearable\" class=\"qd-input-clearable-icon\" icon=\"timesLarge\" (click)=\"clearInput()\"></qd-icon>\n <ng-content select=\"[qdIconButton]\"></ng-content>\n </div>\n <qd-input-units\n *ngIf=\"hasUnits\"\n [unit]=\"_value.unit\"\n [config]=\"config\"\n (unitChange)=\"handleUnitChange($event)\"\n (opened)=\"handleUnitsOpened()\"\n (closed)=\"handleUnitsClosed()\"\n ></qd-input-units>\n <div class=\"qd-input-suffix\" *ngIf=\"hasError && hasOnlyUnitsError\">\n <qd-icon class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:block;width:100%;flex-direction:column;margin-bottom:.75rem}:host .qd-input-input{display:flex;overflow:hidden;height:2.25rem;align-items:center;padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(180,180,180);border-radius:0;margin-bottom:.375rem;background-color:#fff}:host .qd-input-input:hover,:host .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(23,23,23);border-radius:0}:host .qd-input-input input{overflow:hidden;width:100%;flex-grow:1;border:none;background-color:#fff;color:#171717;font-size:.875rem;line-height:1.875rem}:host .qd-input-input input:hover,:host .qd-input-input input:focus,:host .qd-input-input input:active{border:none;outline:none}:host .qd-input-input input::placeholder{color:#b4b4b4}:host .qd-input-input input:focus::placeholder{display:block;color:#b4b4b4}:host .qd-input-input .qd-input-suffix{display:flex;align-items:center;margin-left:.75rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon{padding-right:.5rem;color:#c70023}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon+.qd-input-clearable-icon{margin-left:-.25rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon{margin-right:.5625rem;color:#979797;cursor:pointer;font-size:1.25rem;line-height:2rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:hover,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:focus,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:active{color:#171717}:host .qd-input-input qd-input-units+.qd-input-suffix{margin:0 0 0 -.1875rem}:host .qd-input-character-counter{padding-left:.125rem;color:#757575;float:right;font-size:.75rem;font-weight:300;line-height:.75rem}:host:after{display:block;height:0;clear:both;content:\".\";visibility:hidden}:host.qd-input-focus .qd-input-input{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153);border-radius:0;outline:none}:host.qd-input-readonly .qd-input-readonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-viewonly .qd-input-viewonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-disabled .qd-input-input{border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled .qd-input-input input{background-color:#f5f5f5;color:#979797}:host.qd-input-disabled .qd-input-input input::placeholder{opacity:0}:host.qd-input-disabled .qd-input-input:hover,:host.qd-input-disabled .qd-input-input:active{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled.qd-input-focus{border-color:#ff9b00}:host.qd-input--readonly-action .qd-input-readonly{color:#069;cursor:pointer}:host.qd-input--readonly-action .qd-input-readonly:hover,:host.qd-input--readonly-action .qd-input-readonly:active,:host.qd-input--readonly-action .qd-input-readonly:focus{text-decoration:underline}:host.qd-input--viewonly-action .qd-input-viewonly{color:#069;cursor:pointer}:host.qd-input--viewonly-action .qd-input-viewonly:hover,:host.qd-input--viewonly-action .qd-input-viewonly:active,:host.qd-input--viewonly-action .qd-input-viewonly:focus{text-decoration:underline}:host.qd-input-ambiguous .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(0,102,153)}:host.qd-input-ambiguous .qd-input-input:hover,:host.qd-input-ambiguous .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153)}:host.qd-input-ambiguous.qd-input-focus .qd-input-input{border-color:#069}:host.qd-input-ambiguous .qd-input-suffix ::ng-deep .qd-input-ambiguous-icon{padding-right:.5rem;color:#069}:host.qd-input-error .qd-input-input,:host.qd-input-error-from-outside .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(199,0,35)}:host.qd-input-error .qd-input-input:hover,:host.qd-input-error .qd-input-input:active,:host.qd-input-error-from-outside .qd-input-input:hover,:host.qd-input-error-from-outside .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(199,0,35)}:host.qd-input-error.qd-input-focus,:host.qd-input-error-from-outside.qd-input-focus{border-color:#c70023}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: QdAutofocusDirective, selector: "[qdAutofocus]", inputs: ["qdAutofocus"] }, { kind: "component", type: QdIconComponent, selector: "qd-icon", inputs: ["icon"] }, { kind: "component", type: QdFormHintComponent, selector: "qd-form-hint", inputs: ["hint", "control", "hasError", "hintAction", "data-test-id"] }, { kind: "component", type: QdFormLabelComponent, selector: "qd-form-label", inputs: ["label", "isDisabled", "readonly", "viewonly", "control", "tooltip", "data-test-id"] }, { kind: "component", type: QdFormReadonlyComponent, selector: "qd-form-readonly", inputs: ["values", "readonlyAction", "data-test-id"] }, { kind: "component", type: QdFormViewonlyComponent, selector: "qd-form-viewonly", inputs: ["values", "viewonlyAction", "data-test-id"] }, { kind: "component", type: QdInputUnitsComponent, selector: "qd-input-units", inputs: ["config", "unit"], outputs: ["unitChange", "opened", "closed"] }, { kind: "directive", type: QdInputOptionsDirective, selector: "[qdInputOptions]", inputs: ["value", "config"], outputs: ["enterClick", "optionSelected"] }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }] });
|
|
11507
11717
|
}
|
|
11508
11718
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: QdInputComponent, decorators: [{
|
|
11509
11719
|
type: Component,
|
|
@@ -11515,13 +11725,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
11515
11725
|
},
|
|
11516
11726
|
QdFormsActionEmitterService,
|
|
11517
11727
|
QdFormOptionsResolverRegistry,
|
|
11728
|
+
QdNumberInputService,
|
|
11518
11729
|
// TODO: Remove when removing derived directive
|
|
11519
11730
|
QdPopoverSizingService,
|
|
11520
11731
|
{
|
|
11521
11732
|
provide: QD_FOCUSABLE_TOKEN,
|
|
11522
11733
|
useExisting: QdInputComponent
|
|
11523
11734
|
}
|
|
11524
|
-
], standalone: false, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"
|
|
11735
|
+
], standalone: false, template: "<qd-form-label\n [label]=\"label\"\n [readonly]=\"readonly\"\n [viewonly]=\"viewonly\"\n [control]=\"control\"\n [tooltip]=\"config?.tooltip\"\n [data-test-id]=\"testId\"\n></qd-form-label>\n\n<ng-container *ngIf=\"!readonly && !viewonly && !hasOptions\">\n <div class=\"qd-input-input\" (keydown.enter)=\"emitEnterClick()\">\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</ng-container>\n\n<div *ngIf=\"!readonly && !viewonly && hasOptions\">\n <div\n class=\"qd-input-input\"\n qdInputOptions\n [qdPopoverMinWidth]=\"200\"\n [config]=\"config\"\n [value]=\"_value.value\"\n (optionSelected)=\"handleOptionSelected($event)\"\n (enterClick)=\"emitEnterClick()\"\n >\n <!-- handle (enterClick) by options directive here because event has to be fired after selection -->\n <ng-container *ngTemplateOutlet=\"inputBox\"></ng-container>\n </div>\n\n <span class=\"qd-input-character-counter\" *ngIf=\"hasMaxLength\">{{ numberOfCharacters }} / {{ maxLength }}</span>\n\n <qd-form-hint\n *ngIf=\"hint || hasError\"\n [hint]=\"hint\"\n [control]=\"control\"\n [hasError]=\"hasError\"\n [hintAction]=\"hintAction\"\n [data-test-id]=\"testId\"\n ></qd-form-hint>\n <qd-form-hint *ngIf=\"isAmbiguousInput\" [hint]=\"ambiguityHintKey\" [data-test-id]=\"testId\"></qd-form-hint>\n</div>\n\n<qd-form-readonly\n *ngIf=\"readonly\"\n [values]=\"valueAsList\"\n [readonlyAction]=\"readonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-readonly>\n\n<qd-form-viewonly\n *ngIf=\"viewonly\"\n [values]=\"valueAsList\"\n [viewonlyAction]=\"viewonlyAction\"\n [data-test-id]=\"testId\"\n></qd-form-viewonly>\n\n<ng-template #inputBox>\n <input\n #input\n [placeholder]=\"placeholder | translate\"\n [value]=\"hasOptions ? (_value.value.toString() | translate) : _displayValue\"\n (input)=\"handleInput($event)\"\n (focus)=\"handleInputFocus()\"\n (blur)=\"handleInputBlur()\"\n [disabled]=\"disabled || readonly\"\n [type]=\"htmlInputType\"\n [attr.inputmode]=\"inputMode\"\n [qdAutofocus]=\"hasAutofocus\"\n [attr.data-test-id]=\"testId + '-input'\"\n [step]=\"config?.step\"\n required\n />\n <div class=\"qd-input-suffix\">\n <qd-icon *ngIf=\"hasError && !hasOnlyUnitsError\" class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n <qd-icon *ngIf=\"isAmbiguousInput\" class=\"qd-input-ambiguous-icon\" icon=\"circleInfoSolid\"></qd-icon>\n <qd-icon *ngIf=\"clearable\" class=\"qd-input-clearable-icon\" icon=\"timesLarge\" (click)=\"clearInput()\"></qd-icon>\n <ng-content select=\"[qdIconButton]\"></ng-content>\n </div>\n <qd-input-units\n *ngIf=\"hasUnits\"\n [unit]=\"_value.unit\"\n [config]=\"config\"\n (unitChange)=\"handleUnitChange($event)\"\n (opened)=\"handleUnitsOpened()\"\n (closed)=\"handleUnitsClosed()\"\n ></qd-input-units>\n <div class=\"qd-input-suffix\" *ngIf=\"hasError && hasOnlyUnitsError\">\n <qd-icon class=\"qd-input-error-icon\" icon=\"exclamationCircleSolid\"></qd-icon>\n </div>\n</ng-template>\n", styles: [":host{position:relative;display:block;width:100%;flex-direction:column;margin-bottom:.75rem}:host .qd-input-input{display:flex;overflow:hidden;height:2.25rem;align-items:center;padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(180,180,180);border-radius:0;margin-bottom:.375rem;background-color:#fff}:host .qd-input-input:hover,:host .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(23,23,23);border-radius:0}:host .qd-input-input input{overflow:hidden;width:100%;flex-grow:1;border:none;background-color:#fff;color:#171717;font-size:.875rem;line-height:1.875rem}:host .qd-input-input input:hover,:host .qd-input-input input:focus,:host .qd-input-input input:active{border:none;outline:none}:host .qd-input-input input::placeholder{color:#b4b4b4}:host .qd-input-input input:focus::placeholder{display:block;color:#b4b4b4}:host .qd-input-input .qd-input-suffix{display:flex;align-items:center;margin-left:.75rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon{padding-right:.5rem;color:#c70023}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-error-icon+.qd-input-clearable-icon{margin-left:-.25rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon{margin-right:.5625rem;color:#979797;cursor:pointer;font-size:1.25rem;line-height:2rem}:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:hover,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:focus,:host .qd-input-input .qd-input-suffix ::ng-deep .qd-input-clearable-icon:active{color:#171717}:host .qd-input-input qd-input-units+.qd-input-suffix{margin:0 0 0 -.1875rem}:host .qd-input-character-counter{padding-left:.125rem;color:#757575;float:right;font-size:.75rem;font-weight:300;line-height:.75rem}:host:after{display:block;height:0;clear:both;content:\".\";visibility:hidden}:host.qd-input-focus .qd-input-input{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153);border-radius:0;outline:none}:host.qd-input-readonly .qd-input-readonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-viewonly .qd-input-viewonly{color:#171717;font-size:.875rem;line-height:2.25rem}:host.qd-input-disabled .qd-input-input{border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled .qd-input-input input{background-color:#f5f5f5;color:#979797}:host.qd-input-disabled .qd-input-input input::placeholder{opacity:0}:host.qd-input-disabled .qd-input-input:hover,:host.qd-input-disabled .qd-input-input:active{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(151,151,151);background-color:#f5f5f5}:host.qd-input-disabled.qd-input-focus{border-color:#ff9b00}:host.qd-input--readonly-action .qd-input-readonly{color:#069;cursor:pointer}:host.qd-input--readonly-action .qd-input-readonly:hover,:host.qd-input--readonly-action .qd-input-readonly:active,:host.qd-input--readonly-action .qd-input-readonly:focus{text-decoration:underline}:host.qd-input--viewonly-action .qd-input-viewonly{color:#069;cursor:pointer}:host.qd-input--viewonly-action .qd-input-viewonly:hover,:host.qd-input--viewonly-action .qd-input-viewonly:active,:host.qd-input--viewonly-action .qd-input-viewonly:focus{text-decoration:underline}:host.qd-input-ambiguous .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(0,102,153)}:host.qd-input-ambiguous .qd-input-input:hover,:host.qd-input-ambiguous .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(0,102,153)}:host.qd-input-ambiguous.qd-input-focus .qd-input-input{border-color:#069}:host.qd-input-ambiguous .qd-input-suffix ::ng-deep .qd-input-ambiguous-icon{padding-right:.5rem;color:#069}:host.qd-input-error .qd-input-input,:host.qd-input-error-from-outside .qd-input-input{padding:0 .0625rem 0 .5rem;border:.0625rem solid rgb(199,0,35)}:host.qd-input-error .qd-input-input:hover,:host.qd-input-error .qd-input-input:active,:host.qd-input-error-from-outside .qd-input-input:hover,:host.qd-input-error-from-outside .qd-input-input:active{padding:.0625rem 0 .0625rem .4375rem;border:.125rem solid rgb(199,0,35)}:host.qd-input-error.qd-input-focus,:host.qd-input-error-from-outside.qd-input-focus{border-color:#c70023}\n"] }]
|
|
11525
11736
|
}], propDecorators: { formControlName: [{
|
|
11526
11737
|
type: Input
|
|
11527
11738
|
}], value: [{
|
|
@@ -11581,6 +11792,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
11581
11792
|
}], isErrorFromOutside: [{
|
|
11582
11793
|
type: HostBinding,
|
|
11583
11794
|
args: ['class.qd-input-error-from-outside']
|
|
11795
|
+
}], isAmbiguousState: [{
|
|
11796
|
+
type: HostBinding,
|
|
11797
|
+
args: ['class.qd-input-ambiguous']
|
|
11584
11798
|
}], inputElement: [{
|
|
11585
11799
|
type: ViewChild,
|
|
11586
11800
|
args: ['input']
|
|
@@ -31415,6 +31629,7 @@ class QdShellServiceNavigationComponent {
|
|
|
31415
31629
|
_config;
|
|
31416
31630
|
_destroyed$ = new Subject();
|
|
31417
31631
|
_attributesHaveBeenSet$ = new ReplaySubject(1);
|
|
31632
|
+
localeService = inject(QdLocaleService);
|
|
31418
31633
|
ngOnInit() {
|
|
31419
31634
|
loadJavascriptAsset(this.config?.javascriptAssetPath ?? DEFAULT_JAVASCRIPT_ASSET_PATH$1, {
|
|
31420
31635
|
defer: '',
|
|
@@ -31457,6 +31672,7 @@ class QdShellServiceNavigationComponent {
|
|
|
31457
31672
|
this._destroyed$.complete();
|
|
31458
31673
|
}
|
|
31459
31674
|
handleLanguageChange($event) {
|
|
31675
|
+
this.localeService.setServiceNavigationLanguage($event.detail);
|
|
31460
31676
|
this.useLanguage($event.detail);
|
|
31461
31677
|
}
|
|
31462
31678
|
handleLoginStatusChange($event) {
|
|
@@ -33993,5 +34209,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
33993
34209
|
* Generated bundle index. Do not edit.
|
|
33994
34210
|
*/
|
|
33995
34211
|
|
|
33996
|
-
export { APP_ENVIRONMENT, AVAILABLE_ICONS, BACKEND_ERROR_CODES, MockLocaleDatePipe, NavigationTileComponent, NavigationTilesComponent, QD_DIALOG_CONFIRMATION_RESOLVER_TOKEN, QD_FILE_MANAGER_TOKEN, QD_FILE_UPLOAD_MANAGER_TOKEN, QD_FORM_OPTIONS_RESOLVER, QD_PAGE_OBJECT_RESOLVER_TOKEN, QD_PAGE_STEP_RESOLVER_TOKEN, QD_POPOVER_TOP_FIRST, QD_SAFE_BOTTOM_OFFSET, QD_TABLE_DATA_RESOLVER_TOKEN, QD_UPLOAD_HTTP_OPTIONS, QdButtonComponent, QdButtonGhostDirective, QdButtonGridComponent, QdButtonLinkDirective, QdButtonModule, QdButtonStackButtonComponent, QdButtonStackComponent, QdCheckboxChipsComponent, QdCheckboxComponent, QdCheckboxesComponent, QdChipComponent, QdChipModule, QdColumnAutoFillDirective, QdColumnBreakBeforeDirective, QdColumnDirective, QdColumnDisableResponsiveColspansDirective, QdColumnFullGridWidthDirective, QdColumnNextInSameRowDirective, QdColumnsDirective, QdColumnsDisableAutoFillDirective, QdColumnsDisableResponsiveColspansDirective, QdColumnsMaxDirective, QdCommentsComponent, QdCommentsModule, QdConnectFormStateToPageDirective, QdConnectorTableContextDirective, QdConnectorTableFilterDirective, QdConnectorTableSearchDirective, QdContactCardComponent, QdContactCardModule, QdContainerPairsCaptionComponent, QdContainerPairsContainerComponent, QdContainerPairsHeaderComponent, QdContainerPairsItemComponent, QdContainerPairsValueComponent, QdContextService, QdCoreModule, QdDatepickerComponent, QdDialogActionComponent, QdDialogAuthSessionEndComponent, QdDialogAuthSessionEndService, QdDialogComponent, QdDialogConfirmationComponent, QdDialogConfirmationErrorDirective, QdDialogConfirmationInfoDirective, QdDialogConfirmationSuccessDirective, QdDialogModule, QdDialogRecordStepperComponent, QdDialogService, QdDialogSize, QdDisabledDirective, QdDropdownComponent, QdFileCollectorComponent, QdFileCollectorModule, QdFileSizePipe$1 as QdFileSizePipe, QdFileUploadComponent, QdFileUploadService, QdFilterComponent, QdFilterFormItemsComponent, QdFilterModule, QdFilterRestParamBuilder, QdFilterService, QdFormArray, QdFormBuilder, QdFormControl, QdFormGroup, QdFormModule, QdGridComponent, QdGridModule, QdHorizontalPairsCaptionComponent, QdHorizontalPairsComponent, QdHorizontalPairsItemComponent, QdHorizontalPairsValueComponent, QdIconButtonComponent, QdIconComponent, QdIconModule, QdImageComponent, QdImageModule, QdIndeterminateProgressBarComponent, QdInputComponent, QdListModule, QdMenuButtonComponent, QdMockBreakpointService, QdMockButtonComponent, QdMockButtonGhostDirective, QdMockButtonGridComponent, QdMockButtonLinkDirective, QdMockButtonModule, QdMockButtonStackButtonComponent, QdMockButtonStackComponent, QdMockCalendarComponent, QdMockCheckboxChipsComponent, QdMockCheckboxComponent, QdMockCheckboxesComponent, QdMockChipComponent, QdMockChipModule, QdMockColumnDirective, QdMockColumnsDirective, QdMockContactCardComponent, QdMockContactCardModule, QdMockContainerPairsCaptionComponent, QdMockContainerPairsContainerComponent, QdMockContainerPairsHeaderComponent, QdMockContainerPairsItemComponent, QdMockContainerPairsValueComponent, QdMockCoreModule, QdMockCounterBadgeComponent, QdMockDatepickerComponent, QdMockDisabledDirective, QdMockDropdownComponent, QdMockFileCollectorComponent, QdMockFileCollectorModule, QdMockFilterCategoryBooleanComponent, QdMockFilterCategoryComponent, QdMockFilterCategoryDateComponent, QdMockFilterCategoryDateRangeComponent, QdMockFilterCategoryFreeTextComponent, QdMockFilterCategorySelectComponent, QdMockFilterComponent, QdMockFilterFormItemsComponent, QdMockFilterItemBooleanComponent, QdMockFilterItemDateComponent, QdMockFilterItemDateRangeComponent, QdMockFilterItemFreeTextComponent, QdMockFilterItemMultiSelectComponent, QdMockFilterItemSingleSelectComponent, QdMockFilterModule, QdMockFilterService, QdMockFormErrorComponent, QdMockFormGroupErrorComponent, QdMockFormHintComponent, QdMockFormLabelComponent, QdMockFormReadonlyComponent, QdMockFormViewonlyComponent, QdMockFormsModule, QdMockGridModule, QdMockIconButtonComponent, QdMockIconComponent, QdMockIconModule, QdMockImageComponent, QdMockImageModule, QdMockIndeterminateProgressBarComponent, QdMockInputComponent, QdMockListModule, QdMockNavigationTileComponent, QdMockNavigationTilesComponent, QdMockNavigationTilesModule, QdMockNotificationComponent, QdMockNotificationContentComponent, QdMockNotificationsComponent, QdMockNotificationsModule, QdMockNotificationsService, QdMockPageComponent, QdMockPageModule, QdMockPercentageProgressBarComponent, QdMockPinCodeComponent, QdMockPlaceHolderModule, QdMockPopoverOnClickDirective, QdMockProgressBarModule, QdMockQdPlaceHolderComponent, QdMockRadioButtonsComponent, QdMockRwdDisabledDirective, QdMockSearchComponent, QdMockSearchModule, QdMockSectionComponent, QdMockSectionModule, QdMockShellComponent, QdMockShellFooterComponent, QdMockShellHeaderBannerComponent, QdMockShellHeaderComponent, QdMockShellHeaderSearchComponent, QdMockShellHeaderWidgetComponent, QdMockShellModule, QdMockShellToolbarComponent, QdMockShellToolbarItemComponent, QdMockStatusIndicatorCaptionComponent, QdMockStatusIndicatorComponent, QdMockStatusIndicatorItemComponent, QdMockStatusIndicatorModule, QdMockStatusPairsCaptionComponent, QdMockStatusPairsComponent, QdMockStatusPairsErrorComponent, QdMockStatusPairsItemComponent, QdMockStatusPairsValueComponent, QdMockSwitchComponent, QdMockSwitchesComponent, QdMockTableComponent, QdMockTableModule, QdMockTextSectionComponent, QdMockTextSectionHeadlineComponent, QdMockTextSectionModule, QdMockTextSectionParagraphComponent, QdMockTextareaComponent, QdMockTileButtonListComponent, QdMockTileComponent, QdMockTileTextListComponent, QdMockTileTextListItemComponent, QdMockTileTitleComponent, QdMockTilesContainerComponent, QdMockTilesContainerTitleComponent, QdMockTilesModule, QdMockTranslatePipe, QdMockVisuallyHiddenDirective, QdMultiInputComponent, QdNavigationTilesModule, QdNotificationComponent, QdNotificationContentComponent, QdNotificationsComponent, QdNotificationsHttpInterceptorService, QdNotificationsModule, QdNotificationsService, QdNotificationsSnackbarListenerDirective, QdPageComponent, QdPageControlPanelComponent, QdPageFooterComponent, QdPageFooterCustomContentDirective, QdPageInfoBannerComponent, QdPageModule, QdPageStepComponent, QdPageStepperAdapterDirective, QdPageStepperComponent, QdPageStepperModule, QdPageStoreService, QdPageTabComponent, QdPageTabsAdapterDirective, QdPageTabsComponent, QdPageTabsModule, QdPanelSectionActionsComponent, QdPanelSectionComponent, QdPanelSectionModule, QdPanelSectionStatusComponent, QdPanelSectionTextParagraphComponent, QdPendingChangesGuardDirective, QdPercentageProgressBarComponent, QdPinCodeComponent, QdPlaceHolderComponent, QdPlaceHolderModule, QdPlaceholderPipe, QdProgressBarModule, QdProjectionGuardComponent, QdPushEventsService, QdQuickEditComponent, QdQuickEditModule, QdRadioButtonsComponent, QdRichtextComponent, QdRouterQueryParamHubService, QdRwdDisabledDirective, QdSearchComponent, QdSearchModule, QdSectionAdapterDirective, QdSectionComponent, QdSectionModule, QdSectionToolbarComponent, QdShellComponent, QdShellModule, QdSortDirection, QdSpinnerComponent, QdSpinnerModule, QdStatusIndicatorComponent, QdStatusIndicatorModule, QdStatusPairsCaptionComponent, QdStatusPairsComponent, QdStatusPairsErrorComponent, QdStatusPairsItemComponent, QdStatusPairsValueComponent, QdSubgridComponent, QdSwitchComponent, QdSwitchesComponent, QdTableComponent, QdTableModule, QdTableSpringTools, QdTextSectionComponent, QdTextSectionHeadlineComponent, QdTextSectionModule, QdTextSectionParagraphComponent, QdTextareaComponent, QdTileButtonListComponent, QdTileComponent, QdTileTextListComponent, QdTileTextListItemComponent, QdTileTitleComponent, QdTilesComponent, QdTilesModule, QdTilesTitleComponent, QdTooltipAtIntersectionDirective, QdTooltipIconComponent, QdTreeComponent, QdTreeModule, QdTreeRowExpanderService, QdUiMockModule, QdUiModule, QdUploadErrorType, QdValidators, QdViewportAdaptiveDirective, QdVisuallyHiddenDirective, chipColorDefault, createMetadataStream, updateHtmlLang };
|
|
34212
|
+
export { APP_ENVIRONMENT, AVAILABLE_ICONS, BACKEND_ERROR_CODES, MockLocaleDatePipe, NavigationTileComponent, NavigationTilesComponent, QD_DIALOG_CONFIRMATION_RESOLVER_TOKEN, QD_FILE_MANAGER_TOKEN, QD_FILE_UPLOAD_MANAGER_TOKEN, QD_FORM_OPTIONS_RESOLVER, QD_PAGE_OBJECT_RESOLVER_TOKEN, QD_PAGE_STEP_RESOLVER_TOKEN, QD_POPOVER_TOP_FIRST, QD_SAFE_BOTTOM_OFFSET, QD_TABLE_DATA_RESOLVER_TOKEN, QD_UPLOAD_HTTP_OPTIONS, QdButtonComponent, QdButtonGhostDirective, QdButtonGridComponent, QdButtonLinkDirective, QdButtonModule, QdButtonStackButtonComponent, QdButtonStackComponent, QdCheckboxChipsComponent, QdCheckboxComponent, QdCheckboxesComponent, QdChipComponent, QdChipModule, QdColumnAutoFillDirective, QdColumnBreakBeforeDirective, QdColumnDirective, QdColumnDisableResponsiveColspansDirective, QdColumnFullGridWidthDirective, QdColumnNextInSameRowDirective, QdColumnsDirective, QdColumnsDisableAutoFillDirective, QdColumnsDisableResponsiveColspansDirective, QdColumnsMaxDirective, QdCommentsComponent, QdCommentsModule, QdConnectFormStateToPageDirective, QdConnectorTableContextDirective, QdConnectorTableFilterDirective, QdConnectorTableSearchDirective, QdContactCardComponent, QdContactCardModule, QdContainerPairsCaptionComponent, QdContainerPairsContainerComponent, QdContainerPairsHeaderComponent, QdContainerPairsItemComponent, QdContainerPairsValueComponent, QdContextService, QdCoreModule, QdDatepickerComponent, QdDialogActionComponent, QdDialogAuthSessionEndComponent, QdDialogAuthSessionEndService, QdDialogComponent, QdDialogConfirmationComponent, QdDialogConfirmationErrorDirective, QdDialogConfirmationInfoDirective, QdDialogConfirmationSuccessDirective, QdDialogModule, QdDialogRecordStepperComponent, QdDialogService, QdDialogSize, QdDisabledDirective, QdDropdownComponent, QdFileCollectorComponent, QdFileCollectorModule, QdFileSizePipe$1 as QdFileSizePipe, QdFileUploadComponent, QdFileUploadService, QdFilterComponent, QdFilterFormItemsComponent, QdFilterModule, QdFilterRestParamBuilder, QdFilterService, QdFormArray, QdFormBuilder, QdFormControl, QdFormGroup, QdFormModule, QdGridComponent, QdGridModule, QdHorizontalPairsCaptionComponent, QdHorizontalPairsComponent, QdHorizontalPairsItemComponent, QdHorizontalPairsValueComponent, QdIconButtonComponent, QdIconComponent, QdIconModule, QdImageComponent, QdImageModule, QdIndeterminateProgressBarComponent, QdInputComponent, QdListModule, QdMenuButtonComponent, QdMockBreakpointService, QdMockButtonComponent, QdMockButtonGhostDirective, QdMockButtonGridComponent, QdMockButtonLinkDirective, QdMockButtonModule, QdMockButtonStackButtonComponent, QdMockButtonStackComponent, QdMockCalendarComponent, QdMockCheckboxChipsComponent, QdMockCheckboxComponent, QdMockCheckboxesComponent, QdMockChipComponent, QdMockChipModule, QdMockColumnDirective, QdMockColumnsDirective, QdMockContactCardComponent, QdMockContactCardModule, QdMockContainerPairsCaptionComponent, QdMockContainerPairsContainerComponent, QdMockContainerPairsHeaderComponent, QdMockContainerPairsItemComponent, QdMockContainerPairsValueComponent, QdMockCoreModule, QdMockCounterBadgeComponent, QdMockDatepickerComponent, QdMockDisabledDirective, QdMockDropdownComponent, QdMockFileCollectorComponent, QdMockFileCollectorModule, QdMockFilterCategoryBooleanComponent, QdMockFilterCategoryComponent, QdMockFilterCategoryDateComponent, QdMockFilterCategoryDateRangeComponent, QdMockFilterCategoryFreeTextComponent, QdMockFilterCategorySelectComponent, QdMockFilterComponent, QdMockFilterFormItemsComponent, QdMockFilterItemBooleanComponent, QdMockFilterItemDateComponent, QdMockFilterItemDateRangeComponent, QdMockFilterItemFreeTextComponent, QdMockFilterItemMultiSelectComponent, QdMockFilterItemSingleSelectComponent, QdMockFilterModule, QdMockFilterService, QdMockFormErrorComponent, QdMockFormGroupErrorComponent, QdMockFormHintComponent, QdMockFormLabelComponent, QdMockFormReadonlyComponent, QdMockFormViewonlyComponent, QdMockFormsModule, QdMockGridModule, QdMockIconButtonComponent, QdMockIconComponent, QdMockIconModule, QdMockImageComponent, QdMockImageModule, QdMockIndeterminateProgressBarComponent, QdMockInputComponent, QdMockListModule, QdMockNavigationTileComponent, QdMockNavigationTilesComponent, QdMockNavigationTilesModule, QdMockNotificationComponent, QdMockNotificationContentComponent, QdMockNotificationsComponent, QdMockNotificationsModule, QdMockNotificationsService, QdMockPageComponent, QdMockPageModule, QdMockPercentageProgressBarComponent, QdMockPinCodeComponent, QdMockPlaceHolderModule, QdMockPopoverOnClickDirective, QdMockProgressBarModule, QdMockQdPlaceHolderComponent, QdMockRadioButtonsComponent, QdMockRwdDisabledDirective, QdMockSearchComponent, QdMockSearchModule, QdMockSectionComponent, QdMockSectionModule, QdMockShellComponent, QdMockShellFooterComponent, QdMockShellHeaderBannerComponent, QdMockShellHeaderComponent, QdMockShellHeaderSearchComponent, QdMockShellHeaderWidgetComponent, QdMockShellModule, QdMockShellToolbarComponent, QdMockShellToolbarItemComponent, QdMockStatusIndicatorCaptionComponent, QdMockStatusIndicatorComponent, QdMockStatusIndicatorItemComponent, QdMockStatusIndicatorModule, QdMockStatusPairsCaptionComponent, QdMockStatusPairsComponent, QdMockStatusPairsErrorComponent, QdMockStatusPairsItemComponent, QdMockStatusPairsValueComponent, QdMockSwitchComponent, QdMockSwitchesComponent, QdMockTableComponent, QdMockTableModule, QdMockTextSectionComponent, QdMockTextSectionHeadlineComponent, QdMockTextSectionModule, QdMockTextSectionParagraphComponent, QdMockTextareaComponent, QdMockTileButtonListComponent, QdMockTileComponent, QdMockTileTextListComponent, QdMockTileTextListItemComponent, QdMockTileTitleComponent, QdMockTilesContainerComponent, QdMockTilesContainerTitleComponent, QdMockTilesModule, QdMockTranslatePipe, QdMockVisuallyHiddenDirective, QdMultiInputComponent, QdNavigationTilesModule, QdNotificationComponent, QdNotificationContentComponent, QdNotificationsComponent, QdNotificationsHttpInterceptorService, QdNotificationsModule, QdNotificationsService, QdNotificationsSnackbarListenerDirective, QdNumberInputService, QdPageComponent, QdPageControlPanelComponent, QdPageFooterComponent, QdPageFooterCustomContentDirective, QdPageInfoBannerComponent, QdPageModule, QdPageStepComponent, QdPageStepperAdapterDirective, QdPageStepperComponent, QdPageStepperModule, QdPageStoreService, QdPageTabComponent, QdPageTabsAdapterDirective, QdPageTabsComponent, QdPageTabsModule, QdPanelSectionActionsComponent, QdPanelSectionComponent, QdPanelSectionModule, QdPanelSectionStatusComponent, QdPanelSectionTextParagraphComponent, QdPendingChangesGuardDirective, QdPercentageProgressBarComponent, QdPinCodeComponent, QdPlaceHolderComponent, QdPlaceHolderModule, QdPlaceholderPipe, QdProgressBarModule, QdProjectionGuardComponent, QdPushEventsService, QdQuickEditComponent, QdQuickEditModule, QdRadioButtonsComponent, QdRichtextComponent, QdRouterQueryParamHubService, QdRwdDisabledDirective, QdSearchComponent, QdSearchModule, QdSectionAdapterDirective, QdSectionComponent, QdSectionModule, QdSectionToolbarComponent, QdShellComponent, QdShellModule, QdSortDirection, QdSpinnerComponent, QdSpinnerModule, QdStatusIndicatorComponent, QdStatusIndicatorModule, QdStatusPairsCaptionComponent, QdStatusPairsComponent, QdStatusPairsErrorComponent, QdStatusPairsItemComponent, QdStatusPairsValueComponent, QdSubgridComponent, QdSwitchComponent, QdSwitchesComponent, QdTableComponent, QdTableModule, QdTableSpringTools, QdTextSectionComponent, QdTextSectionHeadlineComponent, QdTextSectionModule, QdTextSectionParagraphComponent, QdTextareaComponent, QdTileButtonListComponent, QdTileComponent, QdTileTextListComponent, QdTileTextListItemComponent, QdTileTitleComponent, QdTilesComponent, QdTilesModule, QdTilesTitleComponent, QdTooltipAtIntersectionDirective, QdTooltipIconComponent, QdTreeComponent, QdTreeModule, QdTreeRowExpanderService, QdUiMockModule, QdUiModule, QdUploadErrorType, QdValidators, QdViewportAdaptiveDirective, QdVisuallyHiddenDirective, chipColorDefault, createMetadataStream, updateHtmlLang };
|
|
33997
34213
|
//# sourceMappingURL=quadrel-enterprise-ui-framework.mjs.map
|