@yomotech/view-toolkit 1.0.18 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yomotech/view-toolkit",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "peerDependencies": {
5
5
  "@angular/cdk": "^21.0.0",
6
6
  "@angular/common": "^21.0.0",
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ElementRef, ChangeDetectorRef, NgZone, SimpleChanges, OnInit, OnChanges, AfterViewInit, OnDestroy, Injector } from '@angular/core';
2
+ import { EventEmitter, ElementRef, ChangeDetectorRef, NgZone, SimpleChanges, OnInit, OnChanges, AfterViewInit, OnDestroy, Injector, PipeTransform } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import * as rxjs from 'rxjs';
5
5
  import { Platform } from '@angular/cdk/platform';
@@ -81,10 +81,12 @@ declare class UtilityService {
81
81
  authorizationBaseUrl: any;
82
82
  accessTokenEndpoint: any;
83
83
  redirectUrl: any;
84
- scope: any;
84
+ scope: string;
85
85
  responseType: any;
86
86
  pkceEnabled: any;
87
87
  };
88
+ /** OAuth scope as the space separated string the OAuth2 plugin expects. */
89
+ private oauthScope;
88
90
  setupStripePaymentForm(environment: any, form: any, onCardChange: (message: string) => void): Promise<void>;
89
91
  formData(form: any, environment: any, cartInfo: any): Promise<void>;
90
92
  normalizeDatesForStorage(obj: any): any;
@@ -195,8 +197,27 @@ interface CustomKeyboardSession {
195
197
  originalInputMode: string | null;
196
198
  originalInputType: string | null;
197
199
  }
200
+ /** Set on body while keyboard or calendar stand at the right edge instead of the bottom. */
201
+ declare const SIDE_DOCK_CLASS = "vl-side-dock";
202
+ /**
203
+ * Side or bottom, decided from the space at hand rather than a device or an orientation: docked at
204
+ * the bottom, a panel (keyboard or calendar, up to about half the height) must leave about two of
205
+ * the dialog's fields visible below its header. If it would not and the dialog still has room
206
+ * beside a panel, the panels dock at the right edge - and the dialog stands left of them for as
207
+ * long as it is open, so it never moves. Returns the width kept free at the right (panel plus its
208
+ * distance to the screen edge), or null for the bottom. Also used by the app to place the dialog.
209
+ */
210
+ declare function sideDockWidth(): number | null;
198
211
  declare class CustomKeyboardService {
199
212
  private openingSuspendedUntil;
213
+ private tapsTracked;
214
+ private lastPointerDownAt;
215
+ private lastClickAt;
216
+ /** Set by DateTimePickerService: closes the open picker when another field is tapped. */
217
+ private pickerCloser;
218
+ /** Watches the dialog a side-docked panel lines up with. */
219
+ private dialogObserver;
220
+ constructor();
200
221
  private lastKeyboardHeight;
201
222
  private pickerOverlayOpen;
202
223
  private pickerTriggerPressedUntil;
@@ -208,6 +229,31 @@ declare class CustomKeyboardService {
208
229
  private blockInitialInteraction;
209
230
  private scrollTargetIntoDialogView;
210
231
  private updateKeyboardHeight;
232
+ /**
233
+ * Runs once the tap that opened the keyboard is complete. The keyboard opens on touch-down; a
234
+ * scroll before the finger lifts makes the click land beside the field, which then loses its
235
+ * focus. Without a tap in progress it runs on the next frame.
236
+ */
237
+ private afterTap;
238
+ /**
239
+ * Height of the keyboard docked at the bottom: the last measured one, or the height its
240
+ * screen-relative key sizes give (see the stylesheet) before it was ever shown.
241
+ */
242
+ keyboardHeight(): number;
243
+ /** Hands the picker closer over; see pickerCloser. */
244
+ setPickerCloser(closer: () => void): void;
245
+ /**
246
+ * The keyboard opens on touch-down; under a field near the bottom it slides in under the
247
+ * finger and the click of the same tap lands on it, so the field never got its focus.
248
+ */
249
+ private refocusTarget;
250
+ private trackTaps;
251
+ /**
252
+ * Scrolls the dialog just far enough that the active field stands fully above the keyboard,
253
+ * or fully below the dialog header when it went up out of sight. A field already in view
254
+ * does not move.
255
+ */
256
+ private scrollTargetAboveKeyboard;
211
257
  private canProcessKeyboardAction;
212
258
  insert(character: string): void;
213
259
  backspace(): void;
@@ -224,6 +270,8 @@ declare class CustomKeyboardService {
224
270
  private readonly documentPointerDownHandler;
225
271
  private readonly activeTargetBlurHandler;
226
272
  private handleDocumentPointerDown;
273
+ /** Closes the keyboard when the outside press ends as a tap; a swipe (scrolling) keeps it. */
274
+ private closeOnTapNotSwipe;
227
275
  private handleActiveTargetBlur;
228
276
  private insertDateTimeDigit;
229
277
  private removeDateTimeDigit;
@@ -246,6 +294,25 @@ declare class CustomKeyboardService {
246
294
  */
247
295
  reserveBottomArea(panel: HTMLElement | null): void;
248
296
  releaseBottomArea(): void;
297
+ /** See sideDockWidth; keeps the width for the panels' styles. */
298
+ dockAtSide(): boolean;
299
+ /** A panel takes the side: the bottom area goes, the dialog stands beside it. */
300
+ useSideDock(): void;
301
+ /**
302
+ * The panel lines up with the dialog - the dialog keeps its own size and place. At the side the
303
+ * panel takes over its upper and lower edge, at the bottom its left and right edge, and follows
304
+ * when the dialog changes (an error message, a turn of the device).
305
+ */
306
+ private followDialog;
307
+ /**
308
+ * Keyboard and calendar look like the page behind them: its background colour - from the
309
+ * project's styles, the app or the theme - becomes --vl-page-background. Dialogs, masks and the
310
+ * panels themselves are looked through; transparent elements pass on their parent's colour.
311
+ */
312
+ applyPageBackground(): void;
313
+ /** Keyboard: side or bottom, the same decision as the calendar's. */
314
+ private applyDock;
315
+ private clearDock;
249
316
  getActiveValue(type: CustomKeyboardType, targetName?: string): string | null;
250
317
  static ɵfac: i0.ɵɵFactoryDeclaration<CustomKeyboardService, never>;
251
318
  static ɵprov: i0.ɵɵInjectableDeclaration<CustomKeyboardService>;
@@ -270,10 +337,21 @@ declare class DateTimePickerService {
270
337
  private activePicker;
271
338
  private activePickerRequest;
272
339
  private pickerOpening;
340
+ /** Whether the system keyboard is up; only then does an icon have to wait for it to hide. */
341
+ private systemKeyboardVisible;
273
342
  private lockedPickerInput;
274
343
  constructor(keyboard: CustomKeyboardService);
275
344
  /** (onShow) of a picker. */
276
345
  onShown(): void;
346
+ /**
347
+ * Side or bottom - the keyboard service decides from the space at hand, the same for the
348
+ * keyboard, so switching between calendar and keyboard never moves the dialog. At the side the
349
+ * calendar stands at the right edge over the full height with the dialog beside it; at the
350
+ * bottom it docks like a keyboard and the dialog ends above it. Decided again on every resize.
351
+ */
352
+ private placeDockedPanel;
353
+ /** Side dock: the field only has to be inside the dialog's visible part. */
354
+ private scrollFieldIntoDialog;
277
355
  /** (onClose) of a picker; pass the picker so a late close of a replaced one is ignored. */
278
356
  onClose(picker?: any): void;
279
357
  /** (pointerdown) of the calendar or clock icon inside a .picker-field. */
@@ -291,10 +369,18 @@ declare class DateTimePickerService {
291
369
  */
292
370
  closeIfWithin(container: HTMLElement): void;
293
371
  /**
294
- * A month has five or six week rows, so the docked calendar grew and shrank while paging
295
- * through the months and its upper edge went up and down. It keeps the height of six rows.
372
+ * The docked calendar is exactly as high as the keyboard, so switching between the two moves
373
+ * nothing; the day cells are sized to fit the header, the weekdays and always six week rows,
374
+ * so paging through months with five and six weeks does not change its height either.
296
375
  */
297
- private keepSixWeekHeight;
376
+ private fitToKeyboardHeight;
377
+ /** Day cells as large as the panel's height allows for its header, the weekdays and six weeks. */
378
+ private fitDays;
379
+ /**
380
+ * The time picker hangs below its field - upright there is room. Where there is not (a phone in
381
+ * landscape), the field scrolls up first; PrimeNG would put the picker above it otherwise.
382
+ */
383
+ private makeRoomBelow;
298
384
  /**
299
385
  * Scrolls the dialog so the field sits right above the docked picker: the eye and the thumb
300
386
  * move a short way from the value to the picker instead of across the whole screen.
@@ -326,6 +412,15 @@ declare class CardComponent {
326
412
  private notificationService;
327
413
  private oauthService;
328
414
  private requestService;
415
+ private readonly remoteLists;
416
+ /** Loaded lists by field reference. */
417
+ remoteData: Record<string, any[]>;
418
+ /** Current suggestions of an autocomplete by field reference. */
419
+ remoteSuggestions: Record<string, any[]>;
420
+ /** Loads every backend list the given layout nodes describe; dropdown/combobox get their items. */
421
+ loadRemoteLists(nodes: any[], propertySchema: any): Promise<void>;
422
+ /** (completeMethod) of an autocomplete with a backend list. */
423
+ completeRemote(event: any, node: any): void;
329
424
  /** Date and time picker behaviour shared by all containers. */
330
425
  readonly picker: DateTimePickerService;
331
426
  private readonly pickerHost;
@@ -417,11 +512,23 @@ declare class CardComponent {
417
512
  showButtonIcon(button: any): boolean;
418
513
  showButtonCaption(button: any): boolean;
419
514
  getScope(scope: any): string;
515
+ getMediaSource(layout: any, record: any): string;
516
+ getMediaLabel(layout: any): string;
517
+ getMediaKind(layout: any, record: any): 'image' | 'video' | 'audio' | 'pdf' | 'file';
420
518
  static ɵfac: i0.ɵɵFactoryDeclaration<CardComponent, never>;
421
519
  static ɵcmp: i0.ɵɵComponentDeclaration<CardComponent, "vl-card", never, { "itemInfo": { "alias": "itemInfo"; "required": false; }; "currentPage": { "alias": "currentPage"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "selectedLanguageInfo": { "alias": "selectedLanguageInfo"; "required": false; }; "mobileDisplay": { "alias": "mobileDisplay"; "required": false; }; "scrollPagination": { "alias": "scrollPagination"; "required": false; }; "pages": { "alias": "pages"; "required": false; }; "paginationMode": { "alias": "paginationMode"; "required": false; }; "paginationLoading": { "alias": "paginationLoading"; "required": false; }; }, { "cardButtonClick": "cardButtonClick"; "cardHeaderButtonClick": "cardHeaderButtonClick"; "linkDetails": "linkDetails"; "imageDetails": "imageDetails"; "onPageSizeChange": "onPageSizeChange"; "onPageChange": "onPageChange"; "cardDataChange": "cardDataChange"; }, never, never, true, never>;
422
520
  }
423
521
 
424
522
  declare class FormComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
523
+ private readonly remoteLists;
524
+ /** Loaded lists by field reference. */
525
+ remoteData: Record<string, any[]>;
526
+ /** Current suggestions of an autocomplete by field reference. */
527
+ remoteSuggestions: Record<string, any[]>;
528
+ /** Loads every backend list the given layout nodes describe; dropdown/combobox get their items. */
529
+ loadRemoteLists(nodes: any[], propertySchema: any): Promise<void>;
530
+ /** (completeMethod) of an autocomplete with a backend list. */
531
+ completeRemote(event: any, node: any): void;
425
532
  /** Date and time picker behaviour shared by all containers. */
426
533
  readonly picker: DateTimePickerService;
427
534
  private readonly host;
@@ -464,6 +571,10 @@ declare class FormComponent implements OnInit, OnChanges, AfterViewInit, OnDestr
464
571
  timeChangeEvent(formField: any, event: any): void;
465
572
  autocompChangeEvent(event: any, formfield: any): void;
466
573
  autocompFocusOutEvent(event: any, formfield: any): void;
574
+ private getMediaProperty;
575
+ getMediaSource(field: any): string;
576
+ getMediaLabel(field: any): string;
577
+ getMediaKind(field: any): 'image' | 'video' | 'audio' | 'pdf' | 'file';
467
578
  static ɵfac: i0.ɵɵFactoryDeclaration<FormComponent, never>;
468
579
  static ɵcmp: i0.ɵɵComponentDeclaration<FormComponent, "vl-form", never, { "errorMessages": { "alias": "errorMessages"; "required": false; }; "creditCardError": { "alias": "creditCardError"; "required": false; }; "form": { "alias": "form"; "required": false; }; "selectedLanguageInfo": { "alias": "selectedLanguageInfo"; "required": false; }; }, { "formButtonClick": "formButtonClick"; "checkBoxChangeEvent": "checkBoxChangeEvent"; }, never, never, true, never>;
469
580
  }
@@ -477,10 +588,25 @@ declare class GridComponent implements AfterViewInit, OnDestroy {
477
588
  private utilityService;
478
589
  private notificationService;
479
590
  private oktaAuthService;
591
+ private readonly remoteLists;
592
+ /** Loaded lists by field reference. */
593
+ remoteData: Record<string, any[]>;
594
+ /** Current suggestions of an autocomplete by field reference. */
595
+ remoteSuggestions: Record<string, any[]>;
596
+ /** Loads every backend list the given layout nodes describe; dropdown/combobox get their items. */
597
+ loadRemoteLists(nodes: any[], propertySchema: any): Promise<void>;
598
+ /** (completeMethod) of an autocomplete with a backend list. */
599
+ completeRemote(event: any, node: any): void;
480
600
  /** Date and time picker behaviour shared by all containers. */
481
601
  readonly picker: DateTimePickerService;
482
602
  private readonly host;
483
603
  ngOnDestroy(): void;
604
+ private sideHintObserver?;
605
+ /** Marks the table's scroll area while columns lie beyond its left or right edge. */
606
+ private updateSideHints;
607
+ private onSideScroll;
608
+ /** Watches size and content of the table, so the hints follow new data and a turn of the device. */
609
+ private startSideHints;
484
610
  /** New data objects use boolean; older projects may still use checkbox. */
485
611
  isLegacyCheckboxFieldType(type: string | undefined): boolean;
486
612
  isLogined: boolean;
@@ -554,6 +680,10 @@ declare class GridComponent implements AfterViewInit, OnDestroy {
554
680
  clearColumnFilter(column: any): void;
555
681
  private hasFilterValue;
556
682
  private matchesColumnFilter;
683
+ isMediaColumn(col: any): boolean;
684
+ getMediaSource(col: any, data: any): string;
685
+ getMediaLabel(col: any): string;
686
+ getMediaKind(col: any, data: any): 'image' | 'video' | 'audio' | 'pdf' | 'file';
557
687
  static ɵfac: i0.ɵɵFactoryDeclaration<GridComponent, never>;
558
688
  static ɵcmp: i0.ɵɵComponentDeclaration<GridComponent, "vl-grid", never, { "errorMessages": { "alias": "errorMessages"; "required": false; }; "environment": { "alias": "environment"; "required": false; }; "selectedLanguageInfo": { "alias": "selectedLanguageInfo"; "required": false; }; "tableitemInfo": { "alias": "tableitemInfo"; "required": false; }; "form": { "alias": "form"; "required": false; }; "isTableDataLoad": { "alias": "isTableDataLoad"; "required": false; }; "currenTableOptions": { "alias": "currenTableOptions"; "required": false; }; "projectSeleted": { "alias": "projectSeleted"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "currentPage": { "alias": "currentPage"; "required": false; }; "pages": { "alias": "pages"; "required": false; }; "userInfo": { "alias": "userInfo"; "required": false; }; }, { "onPageChange": "onPageChange"; "onPageSizeChange": "onPageSizeChange"; "onGridScroll": "onGridScroll"; "showGridLink": "showGridLink"; "gridButtonClick": "gridButtonClick"; "gridIncreamentClick": "gridIncreamentClick"; "gridDecreamentClick": "gridDecreamentClick"; "gridImgClick": "gridImgClick"; }, never, never, true, never>;
559
689
  }
@@ -615,6 +745,7 @@ declare class ModelComponent implements OnChanges, OnDestroy {
615
745
  private readonly dialogRef;
616
746
  private readonly dialogConfig;
617
747
  private utilityService;
748
+ private readonly remoteLists;
618
749
  /** Keep existing checkbox data objects usable; new objects use boolean. */
619
750
  renderFieldType(type: string | undefined): string | undefined;
620
751
  /** Date and time picker behaviour shared by all containers. */
@@ -643,22 +774,11 @@ declare class ModelComponent implements OnChanges, OnDestroy {
643
774
  getButtonCaption(formField: any): any;
644
775
  mapDataToPropertySchema(data: any, modalItemInfo: any): void;
645
776
  setAutoCompleteData(): Promise<void>;
646
- fetchAutocompleteData(formField: any): Promise<any>;
647
- resolveAutocompleteConfig(config: any, userInfo: any): {
648
- url: string;
649
- method: any;
650
- params: any;
651
- headers: {
652
- Authorization: string;
653
- Accept: string;
654
- } | {
655
- Authorization?: undefined;
656
- Accept?: undefined;
657
- };
658
- };
659
- private getAutocompleteRequestUrl;
660
- buildCompany(userInfo: any): string;
777
+ /** The field's backend list (RemoteListService - shared by every container). */
778
+ fetchAutocompleteData(formField: any): Promise<any[]>;
779
+ /** Resolves {{...}} against the user info (RemoteListService). */
661
780
  resolveToken(template: string, context: any): string;
781
+ buildCompany(userInfo: any): string;
662
782
  getScope(scope: any): string;
663
783
  autocompChangeEvent(event: any, formField: any): void;
664
784
  autocompFocusOutEvent(event: any, formField: any): void;
@@ -685,6 +805,10 @@ declare class ModelComponent implements OnChanges, OnDestroy {
685
805
  invokeFormBtnClick(option: any, propertySchema: any, form: NgForm): void;
686
806
  checkValidty(form: NgForm): boolean;
687
807
  onCancel(): void;
808
+ private getMediaProperty;
809
+ getMediaSource(field: any): string;
810
+ getMediaLabel(field: any): string;
811
+ getMediaKind(field: any): 'image' | 'video' | 'audio' | 'pdf' | 'file';
688
812
  static ɵfac: i0.ɵɵFactoryDeclaration<ModelComponent, never>;
689
813
  static ɵcmp: i0.ɵɵComponentDeclaration<ModelComponent, "vl-model", never, { "errorMessages": { "alias": "errorMessages"; "required": false; }; "modalItemInfo": { "alias": "modalItemInfo"; "required": false; }; "selectedLanguageInfo": { "alias": "selectedLanguageInfo"; "required": false; }; "userInfo": { "alias": "userInfo"; "required": false; }; "setFormDataHandler": { "alias": "setFormDataHandler"; "required": false; }; }, {}, never, never, true, never>;
690
814
  }
@@ -720,6 +844,61 @@ declare class PaginationComponent implements OnInit {
720
844
  static ɵcmp: i0.ɵɵComponentDeclaration<PaginationComponent, "vl-pagination", never, { "itemInfo": { "alias": "itemInfo"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "currentPage": { "alias": "currentPage"; "required": false; }; "selectedLanguageInfo": { "alias": "selectedLanguageInfo"; "required": false; }; "pages": { "alias": "pages"; "required": false; }; }, { "pageSizeChange": "pageSizeChange"; "onGoToPage": "onGoToPage"; }, never, never, true, never>;
721
845
  }
722
846
 
847
+ /** What a project's login configuration has to say about its identity provider. */
848
+ interface OidcProvider {
849
+ /** e.g. https://keycloak-poc.wilken.de/realms/p5, https://integrator-1772139.okta.com/oauth2/default */
850
+ issuer: string;
851
+ clientId: string;
852
+ redirectUri: string;
853
+ /** Space separated string or array; default "openid profile email". */
854
+ scope?: string | string[];
855
+ /** Ask for offline_access (refresh token that outlives the browser session). */
856
+ offlineAccess?: boolean;
857
+ }
858
+ interface OidcTokens {
859
+ access_token: string;
860
+ refresh_token?: string;
861
+ id_token?: string;
862
+ expires_in?: number;
863
+ token_type?: string;
864
+ issuer?: string;
865
+ }
866
+ /** Result of a refresh: new tokens, 'refused' (sign in again) or null (no answer - keep the sign-in). */
867
+ type OidcRefresh = OidcTokens | 'refused' | null;
868
+ declare class MobileOidcService {
869
+ private discoveries;
870
+ /** The issuer's discovery document, fetched once per issuer. */
871
+ discover(issuer: string): Promise<any>;
872
+ /**
873
+ * Signs in through the system browser (authorization code + PKCE). With offlineAccess the scope
874
+ * gets offline_access; if the provider refuses it the login is repeated without it. After a
875
+ * logout the provider is asked for the password again (prompt=login).
876
+ */
877
+ login(provider: OidcProvider): Promise<OidcTokens | null>;
878
+ /** New tokens from the refresh token (grant_type=refresh_token, public client - no secret). */
879
+ refresh(provider: OidcProvider, stored: OidcTokens | any): Promise<OidcRefresh>;
880
+ /** The user's claims from the provider's userinfo endpoint; null when the token is refused. */
881
+ userInfo(provider: OidcProvider, accessToken: string): Promise<any | null>;
882
+ /**
883
+ * The same logout for every provider, without a browser window: the provider session is ended
884
+ * where the provider allows it from the app (Keycloak: logout endpoint with the refresh token),
885
+ * refresh and access token are revoked, the saved sign-in is removed and the app restarts. The
886
+ * next login asks for the password. When the project requires a login, the restarted app shows
887
+ * its loader until the sign-in window opens.
888
+ */
889
+ signOut(provider: OidcProvider | null, stored: OidcTokens | any, storageKey: string, removeStored: (key: string) => Promise<void>, options: {
890
+ loginRequired: boolean;
891
+ }): Promise<void>;
892
+ /** Scope as the space separated string the OAuth2 plugin expects. */
893
+ scopeOf(scope: string | string[] | undefined): string;
894
+ private withOfflineAccess;
895
+ private post;
896
+ private flag;
897
+ private setFlag;
898
+ static ɵfac: i0.ɵɵFactoryDeclaration<MobileOidcService, never>;
899
+ static ɵprov: i0.ɵɵInjectableDeclaration<MobileOidcService>;
900
+ }
901
+
723
902
  interface MobileAuthTokens {
724
903
  access_token: string;
725
904
  refresh_token?: string;
@@ -732,19 +911,22 @@ declare class MobileKeycloakService {
732
911
  private http;
733
912
  private utilityService;
734
913
  private platform;
914
+ private oidc;
735
915
  private tokens;
736
- constructor(config: ConfigService, http: HttpClient, utilityService: UtilityService, platform: Platform);
916
+ constructor(config: ConfigService, http: HttpClient, utilityService: UtilityService, platform: Platform, oidc: MobileOidcService);
917
+ /** The Keycloak realm as an OIDC provider, from login.mobile of the project. */
918
+ private provider;
737
919
  login(): Promise<any>;
738
- /** The configured scope plus offline_access, without duplicating it. */
739
- private withOfflineAccess;
740
- /**
741
- * New tokens from the refresh token (grant_type=refresh_token). Returns them in the stored token
742
- * shape, or null when Keycloak refuses - then the caller falls back to the login.
743
- */
744
920
  refreshTokens(stored: MobileAuthTokens | any): Promise<any | null>;
745
921
  getUserInfo(accessToken: any, issuer: any): Promise<any>;
746
922
  getAccessToken(): string | null;
747
923
  getRefreshToken(): string | null;
924
+ /**
925
+ * Ends the Keycloak session without a browser window: the refresh token goes to the logout
926
+ * endpoint directly (allowed for public clients). The browser variant left an empty in-app window
927
+ * that did not close, and its close button cancelled the new sign-in started behind it. The local
928
+ * sign-in is removed in any case - without network the session simply runs out at Keycloak.
929
+ */
748
930
  logout(): Promise<void>;
749
931
  static ɵfac: i0.ɵɵFactoryDeclaration<MobileKeycloakService, never>;
750
932
  static ɵprov: i0.ɵɵInjectableDeclaration<MobileKeycloakService>;
@@ -793,6 +975,8 @@ declare class SideMenuComponent implements AfterViewInit, OnChanges, OnDestroy {
793
975
  errorMessage: EventEmitter<any>;
794
976
  deleteProject: EventEmitter<any>;
795
977
  paginationType: EventEmitter<any>;
978
+ /** The language file in use ("de.json"); its menu entry has a check mark. */
979
+ activeLanguage: string | null;
796
980
  sideMenu: ElementRef<HTMLElement>;
797
981
  readonly PRIME_DE: {
798
982
  firstDayOfWeek: number;
@@ -824,6 +1008,13 @@ declare class SideMenuComponent implements AfterViewInit, OnChanges, OnDestroy {
824
1008
  getPaginationType(): Promise<void>;
825
1009
  ngAfterViewInit(): Promise<void>;
826
1010
  ngOnDestroy(): void;
1011
+ /**
1012
+ * Mobile menu (overlay when open, no width when closed, styles under :host(.sidemenu-mobile)):
1013
+ * the app on iOS and Android - phones and tablets - and small browser windows.
1014
+ */
1015
+ mobileMode: boolean;
1016
+ onResizeMobileMode(): void;
1017
+ private computeMobileMode;
827
1018
  onDocumentClick(event: MouseEvent): void;
828
1019
  toggleCollapsed(): void;
829
1020
  private isNativeMobile;
@@ -836,6 +1027,8 @@ declare class SideMenuComponent implements AfterViewInit, OnChanges, OnDestroy {
836
1027
  private clearLoginUser;
837
1028
  getUserInfoFromToken(token: string): any | null;
838
1029
  setLoginedUser(user: any): void;
1030
+ /** The menu entry with action 'logout', at any depth of the menu. */
1031
+ private findLogoutMenu;
839
1032
  initializeProjects(): void;
840
1033
  setProjectSetting(): Promise<void>;
841
1034
  private setLanguageMenuImage;
@@ -935,7 +1128,7 @@ declare class Textbox {
935
1128
  };
936
1129
  /** The toolkit keyboard for this field, from option.keyboardType or the attribute type. */
937
1130
  keyboardTypeFor(formField: any): CustomKeyboardType | null;
938
- getPlaceholder(formField: any): any;
1131
+ getPlaceholder(formField: any): string;
939
1132
  static ɵfac: i0.ɵɵFactoryDeclaration<Textbox, never>;
940
1133
  static ɵcmp: i0.ɵɵComponentDeclaration<Textbox, "vl-textbox", never, { "formField": { "alias": "formField"; "required": false; }; "modalItemInfo": { "alias": "modalItemInfo"; "required": false; }; }, {}, never, never, true, never>;
941
1134
  }
@@ -961,8 +1154,40 @@ declare class AppVersionResetService {
961
1154
  static ɵprov: i0.ɵɵInjectableDeclaration<AppVersionResetService>;
962
1155
  }
963
1156
 
1157
+ type MobileOktaTokens = OidcTokens;
1158
+ type MobileOktaRefresh = OidcRefresh;
1159
+ declare class MobileOktaService {
1160
+ private utilityService;
1161
+ private oidc;
1162
+ constructor(utilityService: UtilityService, oidc: MobileOidcService);
1163
+ /**
1164
+ * The Okta authorization server as an OIDC provider, from login.mobile of the project. The issuer
1165
+ * is login.mobile.issuer, else login.web.issuer, else derived from the authorize URL
1166
+ * (https://…/oauth2/default/v1/authorize → https://…/oauth2/default).
1167
+ */
1168
+ provider(environment: any): OidcProvider;
1169
+ login(environment: any): Promise<MobileOktaTokens | null>;
1170
+ refreshTokens(environment: any, stored: MobileOktaTokens | any): Promise<MobileOktaRefresh>;
1171
+ /**
1172
+ * Logout with the shared flow. login.required decides where the restarted app goes: true → the
1173
+ * loader until the sign-in opens, otherwise (default for Okta) the start page, signed out.
1174
+ */
1175
+ signOut(environment: any, stored: MobileOktaTokens | any): Promise<void>;
1176
+ static ɵfac: i0.ɵɵFactoryDeclaration<MobileOktaService, never>;
1177
+ static ɵprov: i0.ɵɵInjectableDeclaration<MobileOktaService>;
1178
+ }
1179
+
1180
+ /** True in the native app on iOS (iPhone and iPad) and Android; false in a browser. */
1181
+ declare function isNativeMobile(): boolean;
1182
+ /**
1183
+ * True in the native app on a phone - upright and in landscape alike (its shorter screen side is
1184
+ * below 600pt). Tablets get the tablet and desktop styles by width.
1185
+ */
1186
+ declare function isNativePhone(): boolean;
1187
+
964
1188
  declare class CustomKeyboardComponent {
965
1189
  readonly keyboard: CustomKeyboardService;
1190
+ /** Capital letters: on for the first letter of an empty field, then off - as on iOS. */
966
1191
  readonly uppercase: i0.WritableSignal<boolean>;
967
1192
  /** true while the ?123 page is shown instead of the letters. */
968
1193
  readonly symbols: i0.WritableSignal<boolean>;
@@ -997,5 +1222,86 @@ declare class CustomKeyboardDirective implements OnDestroy {
997
1222
  static ɵdir: i0.ɵɵDirectiveDeclaration<CustomKeyboardDirective, "[vlCustomKeyboard]", never, { "keyboardType": { "alias": "vlCustomKeyboard"; "required": false; }; }, {}, never, never, true, never>;
998
1223
  }
999
1224
 
1000
- export { AppVersionResetService, CardComponent, ConfigService, Couchdb, CustomKeyboardComponent, CustomKeyboardDirective, CustomKeyboardService, FormComponent, GridComponent, HeaderMenuComponent, LogsComponent, MobileKeycloakService, ModelComponent, NetworkLogService, NotificationService, PaginationComponent, RequestService, SideMenuComponent, UtilityService, ViewToolkitModule, normalizeCustomKeyboardType, resolveCustomKeyboardType };
1001
- export type { CustomKeyboardTarget, CustomKeyboardType, MobileAuthTokens };
1225
+ /**
1226
+ * The placeholder of the field `reference` in `propertySchema`, translated when the selected
1227
+ * language has an entry for it; empty when the project defines none.
1228
+ */
1229
+ declare function resolvePlaceholder(propertySchema: any, reference: string | null | undefined, translations?: Record<string, string> | null): string;
1230
+ /** Template form of resolvePlaceholder: [placeholder]="propertySchema | vlPlaceholder: reference". */
1231
+ declare class PlaceholderPipe implements PipeTransform {
1232
+ transform(propertySchema: any, reference: string | null | undefined, translations?: Record<string, string> | null): string;
1233
+ static ɵfac: i0.ɵɵFactoryDeclaration<PlaceholderPipe, never>;
1234
+ static ɵpipe: i0.ɵɵPipeDeclaration<PlaceholderPipe, "vlPlaceholder", true>;
1235
+ }
1236
+
1237
+ interface RequestTimeoutMessages {
1238
+ requestSlow: string;
1239
+ requestStillSlow: string;
1240
+ requestTimeout: string;
1241
+ }
1242
+ /** Thrown when a request was given up after the last stage. */
1243
+ declare class RequestTimeoutError extends Error {
1244
+ constructor();
1245
+ }
1246
+ /** Stages in ms: first hint, second hint, give up. */
1247
+ declare const REQUEST_STAGES: {
1248
+ readonly slow: 10000;
1249
+ readonly stillSlow: 30000;
1250
+ readonly timeout: 60000;
1251
+ };
1252
+ declare class RequestTimeoutService {
1253
+ private readonly notification;
1254
+ /** For code outside Angular's injection (stagedRequest). */
1255
+ static instance: RequestTimeoutService | null;
1256
+ private messages;
1257
+ /** When each message was shown last; several requests waiting at once show it only once. */
1258
+ private lastShown;
1259
+ constructor(notification: NotificationService);
1260
+ /** The texts in the current language (from the app's framework translation). */
1261
+ setMessages(messages: Partial<RequestTimeoutMessages> | null | undefined): void;
1262
+ /** Shows a stage's message, at most once per stage interval. */
1263
+ notify(stage: keyof RequestTimeoutMessages): void;
1264
+ /**
1265
+ * Runs one request under the waiting rule. `work` gets an AbortSignal (fetch can use it);
1266
+ * after the last stage the signal aborts and the promise rejects with RequestTimeoutError.
1267
+ */
1268
+ run<T>(work: (signal: AbortSignal) => Promise<T>): Promise<T>;
1269
+ static ɵfac: i0.ɵɵFactoryDeclaration<RequestTimeoutService, never>;
1270
+ static ɵprov: i0.ɵɵInjectableDeclaration<RequestTimeoutService>;
1271
+ }
1272
+ /** A request under the waiting rule (RequestTimeoutService.run); runs plainly before Angular is up. */
1273
+ declare function stagedRequest<T>(work: (signal: AbortSignal) => Promise<T>): Promise<T>;
1274
+
1275
+ declare class RemoteListService {
1276
+ /** The signed-in user (claims + token), set by the app; used when a caller has none. */
1277
+ private currentUser;
1278
+ setUser(userInfo: any): void;
1279
+ /** Lists already loaded, by request (url + params), so a page does not ask twice. */
1280
+ private readonly cache;
1281
+ /** Like load(), with the current user and one request per source while the app runs. */
1282
+ loadShared(config: any): Promise<any[]>;
1283
+ /** Loads the list a field's source describes (option.autocomplete: url, method, params). */
1284
+ load(config: any, userInfo?: any): Promise<any[]>;
1285
+ resolveAutocompleteConfig(config: any, userInfo: any): {
1286
+ url: string;
1287
+ method: any;
1288
+ params: any;
1289
+ headers: {
1290
+ Authorization: string;
1291
+ Accept: string;
1292
+ } | {
1293
+ Authorization?: undefined;
1294
+ Accept?: undefined;
1295
+ };
1296
+ };
1297
+ private getAutocompleteRequestUrl;
1298
+ buildCompany(userInfo: any): string;
1299
+ resolveToken(template: string, context: any): string;
1300
+ /** Suggestions of `list` whose `field` starts with the typed `query` (case-insensitive). */
1301
+ filter(list: any[] | undefined, field: string | undefined, query: string | undefined): any[];
1302
+ static ɵfac: i0.ɵɵFactoryDeclaration<RemoteListService, never>;
1303
+ static ɵprov: i0.ɵɵInjectableDeclaration<RemoteListService>;
1304
+ }
1305
+
1306
+ export { AppVersionResetService, CardComponent, ConfigService, Couchdb, CustomKeyboardComponent, CustomKeyboardDirective, CustomKeyboardService, FormComponent, GridComponent, HeaderMenuComponent, LogsComponent, MobileKeycloakService, MobileOidcService, MobileOktaService, ModelComponent, NetworkLogService, NotificationService, PaginationComponent, PlaceholderPipe, REQUEST_STAGES, RemoteListService, RequestService, RequestTimeoutError, RequestTimeoutService, SIDE_DOCK_CLASS, SideMenuComponent, UtilityService, ViewToolkitModule, isNativeMobile, isNativePhone, normalizeCustomKeyboardType, resolveCustomKeyboardType, resolvePlaceholder, sideDockWidth, stagedRequest };
1307
+ export type { CustomKeyboardTarget, CustomKeyboardType, MobileAuthTokens, MobileOktaRefresh, MobileOktaTokens, OidcProvider, OidcRefresh, OidcTokens, RequestTimeoutMessages };